diff --git a/README.md b/README.md index 7c996db04..fe380e5ab 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,10 @@ cd stack_wallet git submodule update --init --recursive ``` -You will need to install all dependencies listed in each of the plugins in the crypto_plugins folder. (eg. [Monero](https://github.com/cypherstack/flutter_libmonero), [Epic Cash](https://github.com/cypherstack/flutter_libepiccash) ) as of Sep 8th 2022 that is: +Install all dependencies listed in each of the plugins in the crypto_plugins folder (eg. [flutter_libmonero](https://github.com/cypherstack/flutter_libmonero/blob/main/howto-build-android.md), [flutter_libepiccash](https://github.com/cypherstack/flutter_libepiccash) ) as of Oct 3rd 2022 that is: +``` +sudo apt-get install unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm sudo apt-get install debhelper libclang-dev cargo rustc opencl-headers libssl-dev ocl-icd-opencl-dev +``` Install [Rust](https://www.rust-lang.org/tools/install) ``` @@ -45,6 +48,26 @@ sudo apt install build-essential debhelper cmake libclang-dev libncurses5-dev cl sudo apt install unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless ``` +Run prebuild script + +``` +cd scripts +./prebuild.sh +// when finished go back to the root directory +cd .. +``` + + +Remove pre-installed system libraries for the following packages built by cryptography plugins in the crypto_plugins folder: `boost iconv libjson-dev libsecret openssl sodium unbound zmq`. You can use +``` +sudo apt list --installed | grep boost +``` +for example to find which pre-installed packages you may need to remove with `sudo apt remove`. Be careful, as some packages (especially boost) are linked to GNOME (GUI) packages: when in doubt, remove `-dev` packages first like with +``` +sudo apt-get remove '^libboost.*-dev.*' +``` + + Building plugins for Android ``` cd scripts/android/ diff --git a/assets/svg/Polygon.svg b/assets/svg/Polygon.svg new file mode 100644 index 000000000..b79ac9bc3 --- /dev/null +++ b/assets/svg/Polygon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/box-auto.svg b/assets/svg/box-auto.svg new file mode 100644 index 000000000..1dd771fb1 --- /dev/null +++ b/assets/svg/box-auto.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/crypto_plugins/flutter_libmonero b/crypto_plugins/flutter_libmonero index 8e3afd002..f74f31e2f 160000 --- a/crypto_plugins/flutter_libmonero +++ b/crypto_plugins/flutter_libmonero @@ -1 +1 @@ -Subproject commit 8e3afd002968d21a3de788569356587a70818022 +Subproject commit f74f31e2f3b4a7c11907ae5df6cd38505cd25897 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6756e40c4..1ffbb9415 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -42,6 +42,25 @@ PODS: - Flutter - cw_shared_external/Sodium (0.0.1): - Flutter + - cw_wownero (0.0.2): + - cw_shared_external + - cw_wownero/Boost (= 0.0.2) + - cw_wownero/OpenSSL (= 0.0.2) + - cw_wownero/Sodium (= 0.0.2) + - cw_wownero/Wownero (= 0.0.2) + - Flutter + - cw_wownero/Boost (0.0.2): + - cw_shared_external + - Flutter + - cw_wownero/OpenSSL (0.0.2): + - cw_shared_external + - Flutter + - cw_wownero/Sodium (0.0.2): + - cw_shared_external + - Flutter + - cw_wownero/Wownero (0.0.2): + - cw_shared_external + - Flutter - devicelocale (0.0.1): - Flutter - DKImagePickerController/Core (4.3.4): @@ -127,6 +146,7 @@ DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - cw_monero (from `.symlinks/plugins/cw_monero/ios`) - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`) + - cw_wownero (from `.symlinks/plugins/cw_wownero/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) @@ -169,6 +189,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/cw_monero/ios" cw_shared_external: :path: ".symlinks/plugins/cw_shared_external/ios" + cw_wownero: + :path: ".symlinks/plugins/cw_wownero/ios" devicelocale: :path: ".symlinks/plugins/devicelocale/ios" file_picker: @@ -216,6 +238,7 @@ SPEC CHECKSUMS: connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e cw_monero: 9816991daff0e3ad0a8be140e31933b5526babd4 cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 + cw_wownero: 08e5713fe311a3be95efd7f3c1bf9d47d9cfafde devicelocale: b22617f40038496deffba44747101255cee005b0 DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 1bfb53e8d..98c80851c 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -253,6 +253,7 @@ "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/cw_monero/cw_monero.framework", "${BUILT_PRODUCTS_DIR}/cw_shared_external/cw_shared_external.framework", + "${BUILT_PRODUCTS_DIR}/cw_wownero/cw_wownero.framework", "${BUILT_PRODUCTS_DIR}/devicelocale/devicelocale.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", "${BUILT_PRODUCTS_DIR}/flutter_libmonero/flutter_libmonero.framework", @@ -285,6 +286,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_monero.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_shared_external.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_wownero.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/devicelocale.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_libmonero.framework", diff --git a/lib/main.dart b/lib/main.dart index 0be26c39e..da08c6765 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -84,6 +84,10 @@ void main() async { if (Platform.isIOS) { appDirectory = (await getLibraryDirectory()); } + if (Platform.isLinux || Logging.isArmLinux) { + appDirectory = Directory("${appDirectory.path}/.stackwallet"); + await appDirectory.create(); + } // FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); if (!(Logging.isArmLinux || Logging.isTestEnv)) { final isar = await Isar.open( diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart index 0207a4c61..8a24e95bb 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart @@ -42,6 +42,11 @@ class _RestoreFromDatePickerState extends State { style: STextStyles.field(context), decoration: InputDecoration( hintText: "Restore from...", + hintStyle: STextStyles.fieldLabel(context).copyWith( + color: Theme.of(context) + .extension()! + .textFieldDefaultSearchIconLeft, + ), suffixIcon: UnconstrainedBox( child: Row( children: [ diff --git a/lib/pages/address_book_views/subviews/contact_details_view.dart b/lib/pages/address_book_views/subviews/contact_details_view.dart index 6538af0dc..c0c10b3b1 100644 --- a/lib/pages/address_book_views/subviews/contact_details_view.dart +++ b/lib/pages/address_book_views/subviews/contact_details_view.dart @@ -393,13 +393,15 @@ class _ContactDetailsViewState extends ConsumerState { color: Theme.of(context) .extension()! .textFieldDefaultBG, - padding: const EdgeInsets.all(4), - child: SvgPicture.asset(Assets.svg.pencil, - width: 12, - height: 12, - color: Theme.of(context) - .extension()! - .accentColorDark), + padding: const EdgeInsets.all(6), + child: SvgPicture.asset( + Assets.svg.pencil, + width: 14, + height: 14, + color: Theme.of(context) + .extension()! + .accentColorDark, + ), ), ), const SizedBox( @@ -421,13 +423,15 @@ class _ContactDetailsViewState extends ConsumerState { color: Theme.of(context) .extension()! .textFieldDefaultBG, - padding: const EdgeInsets.all(4), - child: SvgPicture.asset(Assets.svg.copy, - width: 12, - height: 12, - color: Theme.of(context) - .extension()! - .accentColorDark), + padding: const EdgeInsets.all(6), + child: SvgPicture.asset( + Assets.svg.copy, + width: 16, + height: 16, + color: Theme.of(context) + .extension()! + .accentColorDark, + ), ), ), ], diff --git a/lib/pages/address_book_views/subviews/contact_popup.dart b/lib/pages/address_book_views/subviews/contact_popup.dart index a14581c0a..67ab32cda 100644 --- a/lib/pages/address_book_views/subviews/contact_popup.dart +++ b/lib/pages/address_book_views/subviews/contact_popup.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart'; +import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/send_view/send_view.dart'; import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; @@ -19,6 +20,9 @@ import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; +final exchangeFromAddressBookAddressStateProvider = + StateProvider((ref) => ""); + class ContactPopUp extends ConsumerWidget { const ContactPopUp({ Key? key, @@ -268,11 +272,11 @@ class ContactPopUp extends ConsumerWidget { color: Theme.of(context) .extension()! .textFieldDefaultBG, - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.all(6), child: SvgPicture.asset( Assets.svg.copy, - width: 12, - height: 12, + width: 16, + height: 16, color: Theme.of(context) .extension()! .accentColorDark), @@ -280,6 +284,45 @@ class ContactPopUp extends ConsumerWidget { ), ], ), + if (isExchangeFlow) + const SizedBox( + width: 6, + ), + if (isExchangeFlow) + Column( + children: [ + const SizedBox( + height: 2, + ), + GestureDetector( + onTap: () { + ref + .read( + exchangeFromAddressBookAddressStateProvider + .state) + .state = e.address; + Navigator.of(context).popUntil( + ModalRoute.withName( + Step2View.routeName)); + }, + child: RoundedContainer( + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, + padding: + const EdgeInsets.all(6), + child: SvgPicture.asset( + Assets.svg.chevronRight, + width: 16, + height: 16, + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), + ), + ), + ], + ), if (contact.id != "default" && hasActiveWallet && !isExchangeFlow) diff --git a/lib/pages/exchange_view/choose_from_stack_view.dart b/lib/pages/exchange_view/choose_from_stack_view.dart new file mode 100644 index 000000000..f54a7552c --- /dev/null +++ b/lib/pages/exchange_view/choose_from_stack_view.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; + +class ChooseFromStackView extends ConsumerStatefulWidget { + const ChooseFromStackView({ + Key? key, + required this.coin, + }) : super(key: key); + + final Coin coin; + + static const String routeName = "/chooseFromStack"; + + @override + ConsumerState createState() => + _ChooseFromStackViewState(); +} + +class _ChooseFromStackViewState extends ConsumerState { + late final Coin coin; + + @override + void initState() { + coin = widget.coin; + super.initState(); + } + + @override + Widget build(BuildContext context) { + final walletIds = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getWalletIdsFor(coin: coin))); + + return Scaffold( + backgroundColor: Theme.of(context).extension()!.background, + appBar: AppBar( + leading: const AppBarBackButton(), + title: Text( + "Choose your ${coin.ticker.toUpperCase()} wallet", + style: STextStyles.navBarTitle(context), + ), + ), + body: Padding( + padding: const EdgeInsets.all(16), + child: walletIds.isEmpty + ? Column( + children: [ + RoundedWhiteContainer( + child: Center( + child: Text( + "No ${coin.ticker.toUpperCase()} wallets", + style: STextStyles.itemSubtitle(context), + ), + ), + ), + ], + ) + : ListView.builder( + itemCount: walletIds.length, + itemBuilder: (context, index) { + final manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(walletIds[index]))); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 5.0), + child: RawMaterialButton( + splashColor: + Theme.of(context).extension()!.highlight, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + padding: const EdgeInsets.all(0), + // color: Theme.of(context).extension()!.popupBG, + elevation: 0, + onPressed: () async { + if (mounted) { + Navigator.of(context).pop(manager.walletId); + } + }, + child: RoundedWhiteContainer( + // color: Colors.transparent, + child: Row( + children: [ + WalletInfoCoinIcon(coin: coin), + const SizedBox( + width: 12, + ), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + overflow: TextOverflow.ellipsis, + ), + const SizedBox( + height: 2, + ), + WalletInfoRowBalanceFuture( + walletId: walletIds[index], + ), + ], + ), + ) + ], + ), + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/exchange_view/confirm_change_now_send.dart b/lib/pages/exchange_view/confirm_change_now_send.dart index 6fd6c8a08..3ddf8932a 100644 --- a/lib/pages/exchange_view/confirm_change_now_send.dart +++ b/lib/pages/exchange_view/confirm_change_now_send.dart @@ -132,6 +132,7 @@ class _ConfirmChangeNowSendViewState final managerProvider = ref.watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvider(walletId))); return Scaffold( + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( @@ -327,7 +328,12 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Total amount", - style: STextStyles.titleBold12(context), + style: + STextStyles.titleBold12(context).copyWith( + color: Theme.of(context) + .extension()! + .textConfirmTotalAmount, + ), ), Text( "${Format.satoshiAmountToPrettyString( @@ -341,7 +347,12 @@ class _ConfirmChangeNowSendViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12(context), + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textConfirmTotalAmount, + ), textAlign: TextAlign.right, ), ], diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart index 3ac7fd8ec..5681018de 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart @@ -3,6 +3,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/pages/address_book_views/address_book_view.dart'; +import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart'; +import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart'; @@ -17,6 +19,7 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.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/icon_widgets/addressbook_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; @@ -54,6 +57,15 @@ class _Step2ViewState extends ConsumerState { late final FocusNode _toFocusNode; late final FocusNode _refundFocusNode; + bool isStackCoin(String ticker) { + try { + coinFromTickerCaseInsensitive(ticker); + return true; + } on ArgumentError catch (_) { + return false; + } + } + @override void initState() { model = widget.model; @@ -74,7 +86,22 @@ class _Step2ViewState extends ConsumerState { .read(walletsChangeNotifierProvider) .getManager(tuple.item1) .currentReceivingAddress - .then((value) => _toController.text = value); + .then((value) { + _toController.text = value; + model.recipientAddress = _toController.text; + }); + } else { + if (model.sendTicker.toUpperCase() == + tuple.item2.ticker.toUpperCase()) { + ref + .read(walletsChangeNotifierProvider) + .getManager(tuple.item1) + .currentReceivingAddress + .then((value) { + _refundController.text = value; + model.refundAddress = _refundController.text; + }); + } } } @@ -158,15 +185,36 @@ class _Step2ViewState extends ConsumerState { "Recipient Wallet", style: STextStyles.smallMed12(context), ), - // GestureDetector( - // onTap: () { - // // TODO: choose from stack? - // }, - // child: Text( - // "Choose from Stack", - // style: STextStyles.link2(context), - // ), - // ), + if (isStackCoin(model.receiveTicker)) + BlueTextButton( + text: "Choose from stack", + onTap: () { + try { + final coin = coinFromTickerCaseInsensitive( + model.receiveTicker, + ); + Navigator.of(context) + .pushNamed( + ChooseFromStackView.routeName, + arguments: coin, + ) + .then((value) async { + if (value is String) { + final manager = ref + .read(walletsChangeNotifierProvider) + .getManager(value); + + _toController.text = manager.walletName; + model.recipientAddress = await manager + .currentReceivingAddress; + } + }); + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Info); + } + }, + ), ], ), const SizedBox( @@ -195,6 +243,9 @@ class _Step2ViewState extends ConsumerState { ), focusNode: _toFocusNode, style: STextStyles.field(context), + onChanged: (value) { + setState(() {}); + }, decoration: standardInputDecoration( "Enter the ${model.receiveTicker.toUpperCase()} payout address", _toFocusNode, @@ -221,6 +272,8 @@ class _Step2ViewState extends ConsumerState { "sendViewClearAddressFieldButtonKey"), onTap: () { _toController.text = ""; + model.recipientAddress = + _toController.text; setState(() {}); }, @@ -239,6 +292,8 @@ class _Step2ViewState extends ConsumerState { data.text!.trim(); _toController.text = content; + model.recipientAddress = + _toController.text; setState(() {}); } @@ -259,13 +314,31 @@ class _Step2ViewState extends ConsumerState { .state = true; Navigator.of(context) .pushNamed( - AddressBookView.routeName, - ) - .then((_) => ref + AddressBookView.routeName, + ) + .then((_) { + ref + .read( + exchangeFlowIsActiveStateProvider + .state) + .state = false; + + final address = ref + .read( + exchangeFromAddressBookAddressStateProvider + .state) + .state; + if (address.isNotEmpty) { + _toController.text = address; + model.recipientAddress = + _toController.text; + ref .read( - exchangeFlowIsActiveStateProvider + exchangeFromAddressBookAddressStateProvider .state) - .state = false); + .state = ""; + } + }); }, child: const AddressBookIcon(), ), @@ -299,11 +372,15 @@ class _Step2ViewState extends ConsumerState { // auto fill address _toController.text = results["address"] ?? ""; + model.recipientAddress = + _toController.text; setState(() {}); } else { _toController.text = qrResult.rawContent; + model.recipientAddress = + _toController.text; setState(() {}); } @@ -348,15 +425,37 @@ class _Step2ViewState extends ConsumerState { "Refund Wallet (required)", style: STextStyles.smallMed12(context), ), - // GestureDetector( - // onTap: () { - // // TODO: choose from stack? - // }, - // child: Text( - // "Choose from Stack", - // style: STextStyles.link2(context), - // ), - // ), + if (isStackCoin(model.sendTicker)) + BlueTextButton( + text: "Choose from stack", + onTap: () { + try { + final coin = coinFromTickerCaseInsensitive( + model.sendTicker, + ); + Navigator.of(context) + .pushNamed( + ChooseFromStackView.routeName, + arguments: coin, + ) + .then((value) async { + if (value is String) { + final manager = ref + .read(walletsChangeNotifierProvider) + .getManager(value); + + _refundController.text = + manager.walletName; + model.refundAddress = await manager + .currentReceivingAddress; + } + }); + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Info); + } + }, + ), ], ), const SizedBox( @@ -384,6 +483,9 @@ class _Step2ViewState extends ConsumerState { ), focusNode: _refundFocusNode, style: STextStyles.field(context), + onChanged: (value) { + setState(() {}); + }, decoration: standardInputDecoration( "Enter ${model.sendTicker.toUpperCase()} refund address", _refundFocusNode, @@ -410,6 +512,8 @@ class _Step2ViewState extends ConsumerState { "sendViewClearAddressFieldButtonKey"), onTap: () { _refundController.text = ""; + model.refundAddress = + _refundController.text; setState(() {}); }, @@ -429,6 +533,8 @@ class _Step2ViewState extends ConsumerState { _refundController.text = content; + model.refundAddress = + _refundController.text; setState(() {}); } @@ -450,13 +556,26 @@ class _Step2ViewState extends ConsumerState { .state = true; Navigator.of(context) .pushNamed( - AddressBookView.routeName, - ) - .then((_) => ref - .read( - exchangeFlowIsActiveStateProvider - .state) - .state = false); + AddressBookView.routeName, + ) + .then((_) { + ref + .read( + exchangeFlowIsActiveStateProvider + .state) + .state = false; + final address = ref + .read( + exchangeFromAddressBookAddressStateProvider + .state) + .state; + if (address.isNotEmpty) { + _refundController.text = + address; + model.refundAddress = + _refundController.text; + } + }); }, child: const AddressBookIcon(), ), @@ -490,11 +609,15 @@ class _Step2ViewState extends ConsumerState { // auto fill address _refundController.text = results["address"] ?? ""; + model.refundAddress = + _refundController.text; setState(() {}); } else { _refundController.text = qrResult.rawContent; + model.refundAddress = + _refundController.text; setState(() {}); } @@ -556,9 +679,6 @@ class _Step2ViewState extends ConsumerState { Expanded( child: TextButton( onPressed: () { - model.recipientAddress = _toController.text; - model.refundAddress = _refundController.text; - Navigator.of(context).pushNamed( Step3View.routeName, arguments: model); diff --git a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart index 604e3707f..a7b34571b 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart @@ -16,6 +16,7 @@ import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -222,6 +223,26 @@ class _Step3ViewState extends ConsumerState { Expanded( child: TextButton( onPressed: () async { + unawaited( + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => WillPopScope( + onWillPop: () async => false, + child: Container( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.6), + child: const CustomLoadingOverlay( + message: "Creating a trade", + eventBus: null, + ), + ), + ), + ), + ); + ChangeNowResponse response; if (model.rateType == @@ -251,6 +272,10 @@ class _Step3ViewState extends ConsumerState { } if (response.value == null) { + if (mounted) { + Navigator.of(context).pop(); + } + unawaited(showDialog( context: context, barrierDismissible: true, @@ -273,8 +298,6 @@ class _Step3ViewState extends ConsumerState { .getTransactionStatus( id: response.value!.id); - debugPrint("WTF: $statusResponse"); - String status = "Waiting"; if (statusResponse.value != null) { status = statusResponse.value!.status.name; @@ -290,6 +313,10 @@ class _Step3ViewState extends ConsumerState { status += " for deposit"; } + if (mounted) { + Navigator.of(context).pop(); + } + unawaited(NotificationApi.showNotification( changeNowId: model.trade!.id, title: status, diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart index 1487f5f6a..ad618dd0c 100644 --- a/lib/pages/exchange_view/exchange_view.dart +++ b/lib/pages/exchange_view/exchange_view.dart @@ -232,7 +232,7 @@ class _ExchangeViewState extends ConsumerState { ? ref.read(estimatedRateExchangeFormProvider).fromAmountString : ref.read(fixedRateExchangeFormProvider).fromAmountString; _receiveController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).toAmountString + ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString : ref.read(fixedRateExchangeFormProvider).toAmountString; _sendFocusNode.addListener(() async { @@ -260,7 +260,11 @@ class _ExchangeViewState extends ConsumerState { .read(fixedRateExchangeFormProvider) .setFromAmountAndCalculateToAmount(Decimal.zero, true); } - _receiveController.text = ""; + _receiveController.text = + ref.read(prefsChangeNotifierProvider).exchangeRateType == + ExchangeRateType.estimated + ? "-" + : ""; } } }); @@ -325,7 +329,7 @@ class _ExchangeViewState extends ConsumerState { : fixedRateExchangeFormProvider.select( (value) => value.toAmountString), (previous, String next) { if (!_receiveFocusNode.hasFocus) { - _receiveController.text = next; + _receiveController.text = isEstimated && next.isEmpty ? "-" : next; debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _sendController.text = isEstimated @@ -345,7 +349,12 @@ class _ExchangeViewState extends ConsumerState { debugPrint("SEND AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _receiveController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).toAmountString + ? ref + .read(estimatedRateExchangeFormProvider) + .toAmountString + .isEmpty + ? "-" + : ref.read(estimatedRateExchangeFormProvider).toAmountString : ref.read(fixedRateExchangeFormProvider).toAmountString; } } @@ -424,7 +433,7 @@ class _ExchangeViewState extends ConsumerState { .setFromAmountAndCalculateToAmount( Decimal.zero, false); } - _receiveController.text = ""; + _receiveController.text = isEstimated ? "-" : ""; } }, keyboardType: const TextInputType.numberWithOptions( @@ -737,7 +746,7 @@ class _ExchangeViewState extends ConsumerState { .exchangeRateType == ExchangeRateType.estimated, onTap: () { - if (_receiveController.text == "-") { + if (!isEstimated && _receiveController.text == "-") { _receiveController.text = ""; } }, diff --git a/lib/pages/exchange_view/send_from_view.dart b/lib/pages/exchange_view/send_from_view.dart index 586ffc0da..74a1f62d4 100644 --- a/lib/pages/exchange_view/send_from_view.dart +++ b/lib/pages/exchange_view/send_from_view.dart @@ -48,6 +48,26 @@ class _SendFromViewState extends ConsumerState { late final String address; late final ExchangeTransaction trade; + String formatAmount(Decimal amount, Coin coin) { + switch (coin) { + case Coin.bitcoin: + case Coin.bitcoincash: + case Coin.dogecoin: + case Coin.epicCash: + case Coin.firo: + case Coin.namecoin: + case Coin.bitcoinTestNet: + case Coin.bitcoincashTestnet: + case Coin.dogecoinTestNet: + case Coin.firoTestNet: + return amount.toStringAsFixed(Constants.decimalPlaces); + case Coin.monero: + return amount.toStringAsFixed(Constants.decimalPlacesMonero); + case Coin.wownero: + return amount.toStringAsFixed(Constants.decimalPlacesWownero); + } + } + @override void initState() { coin = widget.coin; @@ -59,6 +79,11 @@ class _SendFromViewState extends ConsumerState { @override Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType"); + + final walletIds = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getWalletIdsFor(coin: coin))); + return Scaffold( backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( @@ -68,44 +93,41 @@ class _SendFromViewState extends ConsumerState { }, ), title: Text( - "Send ", + "Send from", style: STextStyles.navBarTitle(context), ), ), body: Padding( padding: const EdgeInsets.all(16), - child: Wrap( - // crossAxisAlignment: CrossAxisAlignment.stretch, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, children: [ - Text( - "Choose your ${coin.ticker} wallet", - style: STextStyles.pageTitleH1(context), - ), - const SizedBox( - height: 8, - ), - Text( - "You need to send ${amount.toStringAsFixed(coin == Coin.monero ? Constants.satsPerCoinMonero : coin == Coin.wownero ? Constants.satsPerCoinWownero : Constants.satsPerCoin)} ${coin.ticker}", - style: STextStyles.itemSubtitle(context), + Row( + children: [ + Text( + "You need to send ${formatAmount(amount, coin)} ${coin.ticker}", + style: STextStyles.itemSubtitle(context), + ), + ], ), const SizedBox( height: 16, ), - ListView( - shrinkWrap: true, - children: [ - ...ref - .watch(walletsChangeNotifierProvider - .select((value) => value.managers)) - .where((element) => element.coin == coin) - .map((e) => SendFromCard( - walletId: e.walletId, - amount: amount, - address: address, - trade: trade, - )) - .toList(growable: false) - ], + Expanded( + child: ListView.builder( + itemCount: walletIds.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: SendFromCard( + walletId: walletIds[index], + amount: amount, + address: address, + trade: trade, + ), + ); + }, + ), ), ], ), @@ -163,7 +185,7 @@ class _SendFromCardState extends ConsumerState { child: MaterialButton( splashColor: Theme.of(context).extension()!.highlight, key: Key("walletsSheetItemButtonKey_$walletId"), - padding: const EdgeInsets.all(5), + padding: const EdgeInsets.all(8), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -276,59 +298,61 @@ class _SendFromCardState extends ConsumerState { ), ), child: Padding( - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.all(6), child: SvgPicture.asset( Assets.svg.iconFor(coin: coin), - width: 20, - height: 20, + width: 24, + height: 24, ), ), ), const SizedBox( width: 12, ), - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - manager.walletName, - style: STextStyles.titleBold12(context), - ), - const SizedBox( - height: 2, - ), - FutureBuilder( - future: manager.totalBalance, - builder: (builderContext, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - return Text( - "${Format.localizedStringAsFixed( - value: snapshot.data!, - locale: locale, - decimalPlaces: coin == Coin.monero - ? Constants.satsPerCoinMonero - : coin == Coin.wownero - ? Constants.satsPerCoinWownero - : Constants.satsPerCoin, - )} ${coin.ticker}", - style: STextStyles.itemSubtitle(context), - ); - } else { - return AnimatedText( - stringsToLoopThrough: const [ - "Loading balance", - "Loading balance.", - "Loading balance..", - "Loading balance..." - ], - style: STextStyles.itemSubtitle(context), - ); - } - }, - ), - ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + ), + const SizedBox( + height: 2, + ), + FutureBuilder( + future: manager.totalBalance, + builder: (builderContext, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { + return Text( + "${Format.localizedStringAsFixed( + value: snapshot.data!, + locale: locale, + decimalPlaces: coin == Coin.monero + ? Constants.decimalPlacesMonero + : coin == Coin.wownero + ? Constants.decimalPlacesWownero + : Constants.decimalPlaces, + )} ${coin.ticker}", + style: STextStyles.itemSubtitle(context), + ); + } else { + return AnimatedText( + stringsToLoopThrough: const [ + "Loading balance", + "Loading balance.", + "Loading balance..", + "Loading balance..." + ], + style: STextStyles.itemSubtitle(context), + ); + } + }, + ), + ], + ), ), ], ), diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index 6c299ed24..ae44faeef 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -10,6 +10,7 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction_stat import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart'; +import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart'; import 'package:stackwallet/providers/exchange/change_now_provider.dart'; @@ -24,6 +25,7 @@ import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -60,6 +62,15 @@ class _TradeDetailsViewState extends ConsumerState { String _note = ""; + bool isStackCoin(String ticker) { + try { + coinFromTickerCaseInsensitive(ticker); + return true; + } on ArgumentError catch (_) { + return false; + } + } + @override initState() { tradeId = widget.tradeId; @@ -345,9 +356,48 @@ class _TradeDetailsViewState extends ConsumerState { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Send ${trade.fromCurrency.toUpperCase()} to this address", - style: STextStyles.itemSubtitle(context), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Send ${trade.fromCurrency.toUpperCase()} to this address", + style: STextStyles.itemSubtitle(context), + ), + GestureDetector( + onTap: () async { + final address = trade.payinAddress; + await Clipboard.setData( + ClipboardData( + text: address, + ), + ); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + context: context, + )); + }, + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.copy, + width: 12, + height: 12, + color: Theme.of(context) + .extension()! + .infoItemIcons, + ), + const SizedBox( + width: 4, + ), + Text( + "Copy", + style: STextStyles.link2(context), + ), + ], + ), + ), + ], ), const SizedBox( height: 4, @@ -717,6 +767,32 @@ class _TradeDetailsViewState extends ConsumerState { const SizedBox( height: 12, ), + if (isStackCoin(trade.fromCurrency) && + trade.statusObject != null && + (trade.statusObject!.status == + ChangeNowTransactionStatus.New || + trade.statusObject!.status == + ChangeNowTransactionStatus.Waiting)) + SecondaryButton( + label: "Send from Stack", + onPressed: () { + final amount = sendAmount; + final address = trade.payinAddress; + + final coin = + coinFromTickerCaseInsensitive(trade.fromCurrency); + + Navigator.of(context).pushNamed( + SendFromView.routeName, + arguments: Tuple4( + coin, + amount, + address, + trade, + ), + ); + }, + ), ], ), ), diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index 179555ba6..ea45c24d3 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -83,8 +83,8 @@ class _WalletInitiatedExchangeViewState child: Container( color: Theme.of(context) .extension()! - .accentColorDark - .withOpacity(0.8), + .overlay + .withOpacity(0.6), child: const CustomLoadingOverlay( message: "Updating exchange rate", eventBus: null, @@ -271,7 +271,11 @@ class _WalletInitiatedExchangeViewState .read(fixedRateExchangeFormProvider) .setFromAmountAndCalculateToAmount(Decimal.zero, true); } - _receiveController.text = ""; + _receiveController.text = + ref.read(prefsChangeNotifierProvider).exchangeRateType == + ExchangeRateType.estimated + ? "-" + : ""; } } }); @@ -329,7 +333,7 @@ class _WalletInitiatedExchangeViewState : fixedRateExchangeFormProvider.select( (value) => value.toAmountString), (previous, String next) { if (!_receiveFocusNode.hasFocus) { - _receiveController.text = next; + _receiveController.text = isEstimated && next.isEmpty ? "-" : next; debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _sendController.text = isEstimated @@ -349,7 +353,12 @@ class _WalletInitiatedExchangeViewState debugPrint("SEND AMOUNT LISTENER ACTIVATED"); if (_swapLock) { _receiveController.text = isEstimated - ? ref.read(estimatedRateExchangeFormProvider).toAmountString + ? ref + .read(estimatedRateExchangeFormProvider) + .toAmountString + .isEmpty + ? "-" + : ref.read(estimatedRateExchangeFormProvider).toAmountString : ref.read(fixedRateExchangeFormProvider).toAmountString; } } @@ -469,7 +478,7 @@ class _WalletInitiatedExchangeViewState .setFromAmountAndCalculateToAmount( Decimal.zero, false); } - _receiveController.text = ""; + _receiveController.text = isEstimated ? "-" : ""; } }, keyboardType: const TextInputType.numberWithOptions( @@ -808,7 +817,8 @@ class _WalletInitiatedExchangeViewState .exchangeRateType == ExchangeRateType.estimated, onTap: () { - if (_receiveController.text == "-") { + if (!isEstimated && + _receiveController.text == "-") { _receiveController.text = ""; } }, @@ -1280,23 +1290,23 @@ class _WalletInitiatedExchangeViewState .exchangeRateType == ExchangeRateType.estimated; - final ft = isEstimated - ? ref - .read( - estimatedRateExchangeFormProvider) - .from - ?.ticker ?? - "" - : ref - .read( - fixedRateExchangeFormProvider) - .market - ?.from ?? - ""; - - final manager = ref - .read(walletsChangeNotifierProvider) - .getManager(walletId); + // final ft = isEstimated + // ? ref + // .read( + // estimatedRateExchangeFormProvider) + // .from + // ?.ticker ?? + // "" + // : ref + // .read( + // fixedRateExchangeFormProvider) + // .market + // ?.from ?? + // ""; + // + // final manager = ref + // .read(walletsChangeNotifierProvider) + // .getManager(walletId); final sendAmount = Decimal.parse(ref .read(estimatedRateExchangeFormProvider) .fromAmountString); diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart index 6b073ea69..29baad1c6 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart @@ -303,13 +303,17 @@ class _DebugViewState extends ConsumerState { Logging.instance .log("$e\n$s", level: LogLevel.Error); } - - final String? path = - await FilePicker.platform.getDirectoryPath( - dialogTitle: "Choose Backup location", - initialDirectory: dir.path, - lockParentWindow: true, - ); + String? path; + if (Platform.isAndroid) { + path = dir.path; + } else { + path = await FilePicker.platform + .getDirectoryPath( + dialogTitle: "Choose Backup location", + initialDirectory: dir.path, + lockParentWindow: true, + ); + } if (path != null) { final eventBus = EventBus(); @@ -328,7 +332,7 @@ class _DebugViewState extends ConsumerState { ), )); - await ref + final filename = await ref .read(debugServiceProvider) .exportToFile(path, eventBus); @@ -336,10 +340,26 @@ class _DebugViewState extends ConsumerState { if (mounted) { Navigator.pop(context); - unawaited(showFloatingFlushBar( - type: FlushBarType.info, - context: context, - message: 'Logs file saved')); + + if (Platform.isAndroid) { + unawaited( + showDialog( + context: context, + builder: (context) => StackOkDialog( + title: "Logs saved to", + message: "${path!}/$filename", + ), + ), + ); + } else { + unawaited( + showFloatingFlushBar( + type: FlushBarType.info, + context: context, + message: 'Logs file saved', + ), + ); + } } } }, diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart index 22ace0a8e..b44a473b4 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart @@ -82,6 +82,17 @@ class _EnableAutoBackupViewState extends ConsumerState { passwordFocusNode = FocusNode(); passwordRepeatFocusNode = FocusNode(); + if (Platform.isAndroid) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final dir = await stackFileSystem.prepareStorage(); + if (mounted) { + setState(() { + fileLocationController.text = dir.path; + }); + } + }); + } + super.initState(); } @@ -133,64 +144,70 @@ class _EnableAutoBackupViewState extends ConsumerState { const SizedBox( height: 10, ), - TextField( - onTap: () async { - try { - await stackFileSystem.prepareStorage(); + if (!Platform.isAndroid) + TextField( + onTap: Platform.isAndroid + ? null + : () async { + try { + await stackFileSystem.prepareStorage(); - if (mounted) { - await stackFileSystem.pickDir(context); - } + if (mounted) { + await stackFileSystem.pickDir(context); + } - if (mounted) { - setState(() { - fileLocationController.text = - stackFileSystem.dirPath ?? ""; - }); - } - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Error); - } - }, - controller: fileLocationController, - style: STextStyles.field(context), - decoration: InputDecoration( - hintText: "Save to...", - suffixIcon: UnconstrainedBox( - child: Row( - children: [ - const SizedBox( - width: 16, - ), - SvgPicture.asset( - Assets.svg.folder, - color: Theme.of(context) - .extension()! - .textDark3, - width: 16, - height: 16, - ), - const SizedBox( - width: 12, - ), - ], + if (mounted) { + setState(() { + fileLocationController.text = + stackFileSystem.dirPath ?? ""; + }); + } + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Error); + } + }, + controller: fileLocationController, + style: STextStyles.field(context), + decoration: InputDecoration( + hintText: "Save to...", + hintStyle: STextStyles.fieldLabel(context), + suffixIcon: UnconstrainedBox( + child: Row( + children: [ + const SizedBox( + width: 16, + ), + SvgPicture.asset( + Assets.svg.folder, + color: Theme.of(context) + .extension()! + .textDark3, + width: 16, + height: 16, + ), + const SizedBox( + width: 12, + ), + ], + ), ), ), + key: const Key( + "createBackupSaveToFileLocationTextFieldKey"), + readOnly: true, + toolbarOptions: const ToolbarOptions( + copy: true, + cut: false, + paste: false, + selectAll: false, + ), + onChanged: (newValue) {}, ), - key: const Key( - "createBackupSaveToFileLocationTextFieldKey"), - readOnly: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: false, - paste: false, - selectAll: false, + if (!Platform.isAndroid) + const SizedBox( + height: 10, ), - onChanged: (newValue) {}, - ), - const SizedBox( - height: 10, - ), ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -593,8 +610,15 @@ class _EnableAutoBackupViewState extends ConsumerState { await showDialog( context: context, barrierDismissible: false, - builder: (_) => const StackOkDialog( - title: "Stack Auto Backup enabled!"), + builder: (_) => Platform.isAndroid + ? StackOkDialog( + title: + "Stack Auto Backup enabled and saved to:", + message: fileToSave, + ) + : const StackOkDialog( + title: + "Stack Auto Backup enabled!"), ); if (mounted) { passwordController.text = ""; diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart index 964111cd3..8dfc7588c 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart @@ -64,6 +64,17 @@ class _RestoreFromFileViewState extends State { passwordFocusNode = FocusNode(); passwordRepeatFocusNode = FocusNode(); + if (Platform.isAndroid) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final dir = await stackFileSystem.prepareStorage(); + if (mounted) { + setState(() { + fileLocationController.text = dir.path; + }); + } + }); + } + super.initState(); } @@ -113,88 +124,78 @@ class _RestoreFromFileViewState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Consumer(builder: (context, ref, __) { - return Container( - color: Colors.transparent, - child: TextField( - onTap: () async { - try { - await stackFileSystem.prepareStorage(); - // ref - // .read( - // shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = false; - if (mounted) { - await stackFileSystem.pickDir(context); - } + if (!Platform.isAndroid) + Consumer(builder: (context, ref, __) { + return Container( + color: Colors.transparent, + child: TextField( + onTap: Platform.isAndroid + ? null + : () async { + try { + await stackFileSystem.prepareStorage(); - // Future.delayed( - // const Duration(seconds: 2), - // () => ref - // .read( - // shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = true, - // ); - - setState(() { - fileLocationController.text = - stackFileSystem.dirPath ?? ""; - }); - } catch (e, s) { - // ref - // .read( - // shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = true; - Logging.instance - .log("$e\n$s", level: LogLevel.Error); - } - }, - controller: fileLocationController, - style: STextStyles.field(context), - decoration: InputDecoration( - hintText: "Save to...", - suffixIcon: UnconstrainedBox( - child: Row( - children: [ - const SizedBox( - width: 16, - ), - SvgPicture.asset( - Assets.svg.folder, - color: Theme.of(context) - .extension()! - .textDark3, - width: 16, - height: 16, - ), - const SizedBox( - width: 12, - ), - ], + if (mounted) { + await stackFileSystem + .pickDir(context); + } + + if (mounted) { + setState(() { + fileLocationController.text = + stackFileSystem.dirPath ?? ""; + }); + } + } catch (e, s) { + Logging.instance.log("$e\n$s", + level: LogLevel.Error); + } + }, + controller: fileLocationController, + style: STextStyles.field(context), + decoration: InputDecoration( + hintText: "Save to...", + hintStyle: STextStyles.fieldLabel(context), + suffixIcon: UnconstrainedBox( + child: Row( + children: [ + const SizedBox( + width: 16, + ), + SvgPicture.asset( + Assets.svg.folder, + color: Theme.of(context) + .extension()! + .textDark3, + width: 16, + height: 16, + ), + const SizedBox( + width: 12, + ), + ], + ), ), ), + key: const Key( + "createBackupSaveToFileLocationTextFieldKey"), + readOnly: true, + toolbarOptions: const ToolbarOptions( + copy: true, + cut: false, + paste: false, + selectAll: false, + ), + onChanged: (newValue) { + // ref.read(addressEntryDataProvider(widget.id)).address = newValue; + }, ), - key: const Key( - "createBackupSaveToFileLocationTextFieldKey"), - readOnly: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: false, - paste: false, - selectAll: false, - ), - onChanged: (newValue) { - // ref.read(addressEntryDataProvider(widget.id)).address = newValue; - }, - ), - ); - }), - const SizedBox( - height: 8, - ), + ); + }), + if (!Platform.isAndroid) + const SizedBox( + height: 8, + ), ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -315,8 +316,12 @@ class _RestoreFromFileViewState extends State { .extension()! .accentColorRed : passwordStrength < 1 - ? Theme.of(context).extension()!.accentColorYellow - : Theme.of(context).extension()!.accentColorGreen, + ? Theme.of(context) + .extension()! + .accentColorYellow + : Theme.of(context) + .extension()! + .accentColorGreen, backgroundColor: Theme.of(context) .extension()! .buttonBackSecondary, @@ -389,8 +394,12 @@ class _RestoreFromFileViewState extends State { const Spacer(), TextButton( style: shouldEnableCreate - ? Theme.of(context) .extension()!.getPrimaryEnabledButtonColor(context) - : Theme.of(context) .extension()!.getPrimaryDisabledButtonColor(context), + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: !shouldEnableCreate ? null : () async { @@ -468,8 +477,14 @@ class _RestoreFromFileViewState extends State { await showDialog( context: context, barrierDismissible: false, - builder: (_) => const StackOkDialog( - title: "Backup creation succeeded"), + builder: (_) => Platform.isAndroid + ? StackOkDialog( + title: "Backup saved to:", + message: fileToSave, + ) + : const StackOkDialog( + title: + "Backup creation succeeded"), ); passwordController.text = ""; passwordRepeatController.text = ""; diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart index fa14358ea..9368d3b77 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart @@ -84,6 +84,17 @@ class _EditAutoBackupViewState extends ConsumerState { passwordFocusNode = FocusNode(); passwordRepeatFocusNode = FocusNode(); + if (Platform.isAndroid) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final dir = await stackFileSystem.prepareStorage(); + if (mounted) { + setState(() { + fileLocationController.text = dir.path; + }); + } + }); + } + super.initState(); } @@ -135,64 +146,70 @@ class _EditAutoBackupViewState extends ConsumerState { const SizedBox( height: 10, ), - TextField( - onTap: () async { - try { - await stackFileSystem.prepareStorage(); + if (!Platform.isAndroid) + TextField( + onTap: Platform.isAndroid + ? null + : () async { + try { + await stackFileSystem.prepareStorage(); - if (mounted) { - await stackFileSystem.pickDir(context); - } + if (mounted) { + await stackFileSystem.pickDir(context); + } - if (mounted) { - setState(() { - fileLocationController.text = - stackFileSystem.dirPath ?? ""; - }); - } - } catch (e, s) { - Logging.instance.log("$e\n$s", level: LogLevel.Error); - } - }, - controller: fileLocationController, - style: STextStyles.field(context), - decoration: InputDecoration( - hintText: "Save to...", - suffixIcon: UnconstrainedBox( - child: Row( - children: [ - const SizedBox( - width: 16, - ), - SvgPicture.asset( - Assets.svg.folder, - color: Theme.of(context) - .extension()! - .textDark3, - width: 16, - height: 16, - ), - const SizedBox( - width: 12, - ), - ], + if (mounted) { + setState(() { + fileLocationController.text = + stackFileSystem.dirPath ?? ""; + }); + } + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Error); + } + }, + controller: fileLocationController, + style: STextStyles.field(context), + decoration: InputDecoration( + hintText: "Save to...", + hintStyle: STextStyles.fieldLabel(context), + suffixIcon: UnconstrainedBox( + child: Row( + children: [ + const SizedBox( + width: 16, + ), + SvgPicture.asset( + Assets.svg.folder, + color: Theme.of(context) + .extension()! + .textDark3, + width: 16, + height: 16, + ), + const SizedBox( + width: 12, + ), + ], + ), ), ), + key: const Key( + "createBackupSaveToFileLocationTextFieldKey"), + readOnly: true, + toolbarOptions: const ToolbarOptions( + copy: true, + cut: false, + paste: false, + selectAll: false, + ), + onChanged: (newValue) {}, ), - key: const Key( - "createBackupSaveToFileLocationTextFieldKey"), - readOnly: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: false, - paste: false, - selectAll: false, + if (!Platform.isAndroid) + const SizedBox( + height: 10, ), - onChanged: (newValue) {}, - ), - const SizedBox( - height: 10, - ), ClipRRect( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -594,8 +611,14 @@ class _EditAutoBackupViewState extends ConsumerState { await showDialog( context: context, barrierDismissible: false, - builder: (_) => const StackOkDialog( - title: "Stack Auto Backup saved"), + builder: (_) => Platform.isAndroid + ? StackOkDialog( + title: + "Stack Auto Backup saved to:", + message: fileToSave, + ) + : const StackOkDialog( + title: "Stack Auto Backup saved"), ); if (mounted) { passwordController.text = ""; 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 9665fdbaf..721141cb8 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 @@ -209,6 +209,10 @@ abstract class SWB { Logging.instance.log( "...createStackWalletJSON DB.instance.mutex acquired", level: LogLevel.Info); + Logging.instance.log( + "SWB backing up nodes", + level: LogLevel.Warning, + ); try { var primaryNodes = nodeService.primaryNodes.map((e) async { final map = e.toMap(); @@ -231,6 +235,11 @@ abstract class SWB { Logging.instance.log("$e $s", level: LogLevel.Error); } + Logging.instance.log( + "SWB backing up prefs", + level: LogLevel.Warning, + ); + Map prefs = {}; final _prefs = Prefs.instance; await _prefs.init(); @@ -251,11 +260,21 @@ abstract class SWB { backupJson['prefs'] = prefs; + Logging.instance.log( + "SWB backing up addressbook", + level: LogLevel.Warning, + ); + AddressBookService addressBookService = AddressBookService(); var addresses = await addressBookService.addressBookEntries; backupJson['addressBookEntries'] = addresses.map((e) => e.toMap()).toList(); + Logging.instance.log( + "SWB backing up wallets", + level: LogLevel.Warning, + ); + List backupWallets = []; for (var manager in _wallets.managers) { Map backupWallet = {}; @@ -283,6 +302,11 @@ abstract class SWB { } backupJson['wallets'] = backupWallets; + Logging.instance.log( + "SWB backing up trades", + level: LogLevel.Warning, + ); + // back up trade history final tradesService = TradesService(); final trades = @@ -295,6 +319,11 @@ abstract class SWB { tradeTxidLookupDataService.all.map((e) => e.toMap()).toList(); backupJson["tradeTxidLookupData"] = lookupData; + Logging.instance.log( + "SWB backing up trade notes", + level: LogLevel.Warning, + ); + // back up trade notes final tradeNotesService = TradeNotesService(); final tradeNotes = tradeNotesService.all; @@ -357,7 +386,7 @@ abstract class SWB { final notes = walletbackup["notes"] as Map?; if (notes != null) { for (final note in notes.entries) { - notesService.editOrAddNote( + await notesService.editOrAddNote( txid: note.key as String, note: note.value as String); } } @@ -432,11 +461,19 @@ abstract class SWB { uiState?.preferences = StackRestoringStatus.restoring; + Logging.instance.log( + "SWB restoring prefs", + level: LogLevel.Warning, + ); await _restorePrefs(prefs); uiState?.preferences = StackRestoringStatus.success; uiState?.addressBook = StackRestoringStatus.restoring; + Logging.instance.log( + "SWB restoring addressbook", + level: LogLevel.Warning, + ); if (addressBookEntries != null) { await _restoreAddressBook(addressBookEntries); } @@ -444,6 +481,10 @@ abstract class SWB { uiState?.addressBook = StackRestoringStatus.success; uiState?.nodes = StackRestoringStatus.restoring; + Logging.instance.log( + "SWB restoring nodes", + level: LogLevel.Warning, + ); await _restoreNodes(nodes, primaryNodes); uiState?.nodes = StackRestoringStatus.success; @@ -451,17 +492,29 @@ abstract class SWB { // restore trade history if (trades != null) { + Logging.instance.log( + "SWB restoring trades", + level: LogLevel.Warning, + ); await _restoreTrades(trades); } // restore trade history lookup data for trades send from stack wallet if (tradeTxidLookupData != null) { + Logging.instance.log( + "SWB restoring trade look up data", + level: LogLevel.Warning, + ); await _restoreTradesLookUpData(tradeTxidLookupData, oldToNewWalletIdMap); } // restore trade notes if (tradeNotes != null) { + Logging.instance.log( + "SWB restoring trade notes", + level: LogLevel.Warning, + ); await _restoreTradesNotes(tradeNotes); } @@ -490,9 +543,17 @@ abstract class SWB { String jsonBackup, StackRestoringUIState? uiState, ) async { - if (!Platform.isLinux) Wakelock.enable(); + if (!Platform.isLinux) await Wakelock.enable(); + Logging.instance.log( + "SWB creating temp backup", + level: LogLevel.Warning, + ); final preRestoreJSON = await createStackWalletJSON(); + Logging.instance.log( + "SWB temp backup created", + level: LogLevel.Warning, + ); List _currentWalletIds = Map.from(DB.instance .get( @@ -814,13 +875,13 @@ abstract class SWB { } await asyncRestore(epicCashWallets[i], uiState, walletsService); } - if (!Platform.isLinux) Wakelock.disable(); + if (!Platform.isLinux) await Wakelock.disable(); // check if cancel was requested and restore previous state if (_checkShouldCancel(preRestoreState)) { return false; } - Logging.instance.log("done with SWB restore", level: LogLevel.Info); + Logging.instance.log("done with SWB restore", level: LogLevel.Warning); return true; } @@ -849,7 +910,7 @@ abstract class SWB { // if no contacts were present before attempted restore then delete any that // could have been added before the restore was cancelled for (final String idToDelete in allContactIds) { - addressBookService.removeContact(idToDelete); + await addressBookService.removeContact(idToDelete); } } else { final Map preContactMap = {}; @@ -886,7 +947,7 @@ abstract class SWB { ); } else { // otherwise remove it as it was not there before attempting SWB restore - addressBookService.removeContact(id); + await addressBookService.removeContact(id); } } } @@ -898,7 +959,7 @@ abstract class SWB { // no pre nodes found so we delete all but defaults for (final node in currentNodes) { if (!node.isDefault) { - nodeService.delete(node.id, true); + await nodeService.delete(node.id, true); } } } else { @@ -912,7 +973,7 @@ abstract class SWB { if (nodeData != null) { // node existed before restore attempt // revert to pre restore node - nodeService.edit( + await nodeService.edit( node.copyWith( host: nodeData['host'] as String, port: nodeData['port'] as int, @@ -927,7 +988,7 @@ abstract class SWB { nodeData['password'] as String?, true); } else { - nodeService.delete(node.id, true); + await nodeService.delete(node.id, true); } } } @@ -951,7 +1012,7 @@ abstract class SWB { // no trade history found pre restore attempt so we delete anything that // was added during the restore attempt for (final tradeTx in currentTrades) { - tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); + await tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); } } else { final Map preTradeMap = {}; @@ -964,13 +1025,14 @@ abstract class SWB { if (tradeData != null) { // trade existed before attempted restore so we don't delete it, only // revert data to pre restore state - tradesService.edit( + await tradesService.edit( trade: ExchangeTransaction.fromJson( tradeData as Map), shouldNotifyListeners: true); } else { // trade did not exist before so we delete it - tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); + await tradesService.delete( + trade: tradeTx, shouldNotifyListeners: true); } } } @@ -982,7 +1044,7 @@ abstract class SWB { if (tradeNotes == null) { for (final noteEntry in currentNotes.entries) { - tradeNotesService.delete(tradeId: noteEntry.key); + await tradeNotesService.delete(tradeId: noteEntry.key); } } else { // grab all trade IDs of (reverted to pre state) trades @@ -991,7 +1053,7 @@ abstract class SWB { // delete all notes that don't correspond to an id that we have for (final noteEntry in currentNotes.entries) { if (!idsToKeep.contains(noteEntry.key)) { - tradeNotesService.delete(tradeId: noteEntry.key); + await tradeNotesService.delete(tradeId: noteEntry.key); } } } @@ -1009,7 +1071,7 @@ abstract class SWB { for (int i = 0; i < tradeTxidLookupData.length; i++) { final json = Map.from(tradeTxidLookupData[i] as Map); TradeWalletLookup lookup = TradeWalletLookup.fromJson(json); - tradeTxidLookupDataService.save(tradeWalletLookup: lookup); + await tradeTxidLookupDataService.save(tradeWalletLookup: lookup); } } @@ -1127,14 +1189,14 @@ abstract class SWB { ) async { final tradesService = TradesService(); for (int i = 0; i < trades.length - 1; i++) { - tradesService.add( + await tradesService.add( trade: ExchangeTransaction.fromJson(trades[i] as Map), shouldNotifyListeners: false, ); } // only call notifyListeners on last one added if (trades.isNotEmpty) { - tradesService.add( + await tradesService.add( trade: ExchangeTransaction.fromJson(trades.last as Map), shouldNotifyListeners: true, @@ -1177,7 +1239,7 @@ abstract class SWB { } } - tradeTxidLookupDataService.save(tradeWalletLookup: lookup); + await tradeTxidLookupDataService.save(tradeWalletLookup: lookup); } } @@ -1186,7 +1248,8 @@ abstract class SWB { ) async { final tradeNotesService = TradeNotesService(); for (final note in tradeNotes.entries) { - tradeNotesService.set(tradeId: note.key, note: note.value as String); + await tradeNotesService.set( + tradeId: note.key, note: note.value as String); } } } diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart index 75f2b272f..3196938da 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart @@ -13,7 +13,7 @@ class StackFileSystem { final bool isDesktop = !(Platform.isAndroid || Platform.isIOS); - Future prepareStorage() async { + Future prepareStorage() async { rootPath = (await getApplicationDocumentsDirectory()); debugPrint(rootPath!.absolute.toString()); if (Platform.isAndroid) { @@ -47,6 +47,7 @@ class StackFileSystem { debugPrint("$e $s"); } startPath = sampleFolder; + return sampleFolder; } Future pickDir(BuildContext context) async { diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart index feda62d0a..cec114023 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart @@ -99,29 +99,17 @@ class _RestoreFromFileViewState extends ConsumerState { onTap: () async { try { await stackFileSystem.prepareStorage(); - // ref - // .read(shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = false; - await stackFileSystem.openFile(context); + if (mounted) { + await stackFileSystem.openFile(context); + } - // Future.delayed( - // const Duration(seconds: 2), - // () => ref - // .read( - // shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = true, - // ); - - fileLocationController.text = - stackFileSystem.filePath ?? ""; - setState(() {}); + if (mounted) { + setState(() { + fileLocationController.text = + stackFileSystem.filePath ?? ""; + }); + } } catch (e, s) { - // ref - // .read(shouldShowLockscreenOnResumeStateProvider - // .state) - // .state = true; Logging.instance .log("$e\n$s", level: LogLevel.Error); } @@ -130,6 +118,7 @@ class _RestoreFromFileViewState extends ConsumerState { style: STextStyles.field(context), decoration: InputDecoration( hintText: "Choose file...", + hintStyle: STextStyles.fieldLabel(context), suffixIcon: UnconstrainedBox( child: Row( children: [ diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart index bda060071..f95e75997 100644 --- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart +++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart @@ -9,7 +9,12 @@ import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; +import 'package:stackwallet/widgets/trade_card.dart'; import 'package:stackwallet/widgets/transaction_card.dart'; +import 'package:tuple/tuple.dart'; + +import '../../../providers/global/trades_service_provider.dart'; +import '../../exchange_view/trade_details_view.dart'; class TransactionsList extends ConsumerStatefulWidget { const TransactionsList({ @@ -125,18 +130,67 @@ class _TransactionsListState extends ConsumerState { radius = _borderRadiusFirst; } final tx = list[index]; - return Container( - decoration: BoxDecoration( - color: Theme.of(context).extension()!.popupBG, - borderRadius: radius, - ), - child: TransactionCard( - // this may mess with combined firo transactions - key: Key(tx.toString()), // - transaction: tx, - walletId: widget.walletId, - ), - ); + + final matchingTrades = ref + .read(tradesServiceProvider) + .trades + .where((e) => + e.statusObject != null && + (e.statusObject!.payinHash == tx.txid || + e.statusObject!.payoutHash == tx.txid)); + if (tx.txType == "Sent" && matchingTrades.isNotEmpty) { + final trade = matchingTrades.first; + return Container( + decoration: BoxDecoration( + color: + Theme.of(context).extension()!.popupBG, + borderRadius: radius, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TransactionCard( + // this may mess with combined firo transactions + key: Key(tx.toString()), // + transaction: tx, + walletId: widget.walletId, + ), + TradeCard( + // this may mess with combined firo transactions + key: Key(tx.toString() + trade.uuid), // + trade: trade, + onTap: () { + unawaited( + Navigator.of(context).pushNamed( + TradeDetailsView.routeName, + arguments: Tuple4( + trade.id, + tx, + widget.walletId, + ref.read(managerProvider).walletName, + ), + ), + ); + }, + ) + ], + ), + ); + } else { + return Container( + decoration: BoxDecoration( + color: + Theme.of(context).extension()!.popupBG, + borderRadius: radius, + ), + child: TransactionCard( + // this may mess with combined firo transactions + key: Key(tx.toString()), // + transaction: tx, + walletId: widget.walletId, + ), + ); + } }, ), ); diff --git a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart index 4309186ac..8691b7d84 100644 --- a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart @@ -96,7 +96,14 @@ class AddWalletButton extends StatelessWidget { .extension()! .getPrimaryEnabledButtonColor(context), onPressed: () { - Navigator.of(context).pushNamed(AddWalletView.routeName); + if (isDesktop) { + Navigator.of( + context, + rootNavigator: true, + ).pushNamed(AddWalletView.routeName); + } else { + Navigator.of(context).pushNamed(AddWalletView.routeName); + } }, child: Center( child: Container( diff --git a/lib/pages_desktop_specific/home/settings_view/settings_view.dart b/lib/pages_desktop_specific/home/settings_view/settings_view.dart new file mode 100644 index 000000000..c308f2962 --- /dev/null +++ b/lib/pages_desktop_specific/home/settings_view/settings_view.dart @@ -0,0 +1,20 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class SettingsView extends ConsumerStatefulWidget { + const SettingsView({Key? key}) : super(key: key); + + static const String routeName = "/settingsView"; + + @override + ConsumerState createState() => _SettingsView(); +} + +class _SettingsView extends ConsumerState { + @override + Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType"); + // TODO: implement build + throw UnimplementedError(); + } +} diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 797b62969..368188171 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -1,7 +1,9 @@ +import 'package:decimal/decimal.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/contact_address_entry.dart'; +import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart'; @@ -20,12 +22,14 @@ import 'package:stackwallet/pages/address_book_views/subviews/address_book_filte import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart'; +import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart'; import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart'; +import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; import 'package:stackwallet/pages/exchange_view/trade_details_view.dart'; import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; @@ -879,6 +883,37 @@ class RouteGenerator { } return _routeError("${settings.name} invalid args: ${args.toString()}"); + case ChooseFromStackView.routeName: + if (args is Coin) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => ChooseFromStackView( + coin: args, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); + + case SendFromView.routeName: + if (args is Tuple4) { + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => SendFromView( + coin: args.item1, + amount: args.item2, + trade: args.item4, + address: args.item3, + ), + settings: RouteSettings( + name: settings.name, + ), + ); + } + return _routeError("${settings.name} invalid args: ${args.toString()}"); + // == Desktop specific routes ============================================ case CreatePasswordView.routeName: return getRoute( diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index e33428319..112e6c176 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -259,6 +259,9 @@ Future deleteEpicWallet({ if (Platform.isIOS) { appDir = (await getLibraryDirectory()); } + if (Platform.isLinux) { + appDir = Directory("${appDir.path}/.stackwallet"); + } final path = "${appDir.path}/epiccash"; final String name = walletId; @@ -1232,6 +1235,9 @@ class EpicCashWallet extends CoinServiceAPI { if (Platform.isIOS) { appDir = (await getLibraryDirectory()); } + if (Platform.isLinux) { + appDir = Directory("${appDir.path}/.stackwallet"); + } final path = "${appDir.path}/epiccash"; final String name = _walletId.trim(); return '$path/$name'; diff --git a/lib/services/coins/monero/monero_wallet.dart b/lib/services/coins/monero/monero_wallet.dart index b63e711a4..2488acc50 100644 --- a/lib/services/coins/monero/monero_wallet.dart +++ b/lib/services/coins/monero/monero_wallet.dart @@ -910,6 +910,10 @@ class MoneroWallet extends CoinServiceAPI { if (Platform.isIOS) { root = (await getLibraryDirectory()); } + // + if (Platform.isLinux) { + root = Directory("${root.path}/.stackwallet"); + } final prefix = walletTypeToString(type).toLowerCase(); final walletsDir = Directory('${root.path}/wallets'); final walletDire = Directory('${walletsDir.path}/$prefix/$name'); diff --git a/lib/services/coins/namecoin/namecoin_wallet.dart b/lib/services/coins/namecoin/namecoin_wallet.dart index bedd50327..af4217488 100644 --- a/lib/services/coins/namecoin/namecoin_wallet.dart +++ b/lib/services/coins/namecoin/namecoin_wallet.dart @@ -2501,7 +2501,8 @@ class NamecoinWallet extends CoinServiceAPI { int totalOutput = 0; for (final output in txObject["vout"] as List) { - final address = output["scriptPubKey"]["addresses"][0]; + Logging.instance.log(output, level: LogLevel.Info); + final address = output["scriptPubKey"]["address"]; final value = output["value"]; final _value = (Decimal.parse(value.toString()) * Decimal.fromInt(Constants.satsPerCoin)) diff --git a/lib/services/coins/wownero/wownero_wallet.dart b/lib/services/coins/wownero/wownero_wallet.dart index 7114269ec..b284c8733 100644 --- a/lib/services/coins/wownero/wownero_wallet.dart +++ b/lib/services/coins/wownero/wownero_wallet.dart @@ -913,6 +913,9 @@ class WowneroWallet extends CoinServiceAPI { if (Platform.isIOS) { root = (await getLibraryDirectory()); } + if (Platform.isLinux) { + root = Directory("${root.path}/.stackwallet"); + } final prefix = walletTypeToString(type).toLowerCase(); final walletsDir = Directory('${root.path}/wallets'); final walletDire = Directory('${walletsDir.path}/$prefix/$name'); diff --git a/lib/services/debug_service.dart b/lib/services/debug_service.dart index e7347c6a3..c63e22cb2 100644 --- a/lib/services/debug_service.dart +++ b/lib/services/debug_service.dart @@ -75,7 +75,8 @@ class DebugService extends ChangeNotifier { level: LogLevel.Info); } - Future exportToFile(String directory, EventBus eventBus) async { + /// returns the filename of the saved logs file + Future exportToFile(String directory, EventBus eventBus) async { final now = DateTime.now(); final filename = "Stack_Wallet_logs_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.txt"; @@ -99,5 +100,6 @@ class DebugService extends ChangeNotifier { await sink.close(); eventBus.fire(1.0); + return filename; } } diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart index 94558e623..1b38f42bc 100644 --- a/lib/utilities/assets.dart +++ b/lib/utilities/assets.dart @@ -51,7 +51,9 @@ class _SVG { String txExchangeFailed(BuildContext context) => "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-exchange-icon-failed.svg"; + String get polygon => "assets/svg/Polygon.svg"; String get drd => "assets/svg/drd-icon.svg"; + String get boxAuto => "assets/svg/box-auto.svg"; String get plus => "assets/svg/plus.svg"; String get gear => "assets/svg/gear.svg"; String get bell => "assets/svg/bell.svg"; diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index f5139477c..69c1444c3 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -21,6 +21,8 @@ abstract class Constants { static const int satsPerCoinWownero = 100000000000; static const int satsPerCoin = 100000000; static const int decimalPlaces = 8; + static const int decimalPlacesWownero = 11; + static const int decimalPlacesMonero = 12; static const int notificationsMax = 0xFFFFFFFF; static const Duration networkAliveTimerDuration = Duration(seconds: 10); diff --git a/lib/utilities/text_styles.dart b/lib/utilities/text_styles.dart index 7c6aa2aaf..21a1ee488 100644 --- a/lib/utilities/text_styles.dart +++ b/lib/utilities/text_styles.dart @@ -698,6 +698,25 @@ class STextStyles { } } + static TextStyle desktopTextExtraExtraSmall(BuildContext context) { + switch (_theme(context).themeType) { + case ThemeType.light: + return GoogleFonts.inter( + color: _theme(context).textSubtitle1, + fontWeight: FontWeight.w500, + fontSize: 14, + height: 21 / 14, + ); + case ThemeType.dark: + return GoogleFonts.inter( + color: _theme(context).textSubtitle1, + fontWeight: FontWeight.w500, + fontSize: 14, + height: 21 / 14, + ); + } + } + static TextStyle desktopButtonSmallSecondaryEnabled(BuildContext context) { switch (_theme(context).themeType) { case ThemeType.light: diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index 12d9f1f71..53391e7ad 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -137,6 +137,9 @@ install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/linux/build/libcw_monero.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/linux/build/libcw_wownero.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash/scripts/linux/build/rust/target/x86_64-unknown-linux-gnu/release/libepic_cash_wallet.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b60..4b81f9b2d 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index c2efd0b60..5caa9d157 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 000000000..dade8dfad --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,40 @@ +platform :osx, '10.11' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/pubspec.yaml b/pubspec.yaml index dbe44c852..60f65f3e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: Stack Wallet # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.4.52+68 +version: 1.5.0+70 environment: sdk: ">=2.17.0 <3.0.0" @@ -289,6 +289,7 @@ flutter: - assets/svg/tx-icon-anonymize.svg - assets/svg/tx-icon-anonymize-pending.svg - assets/svg/tx-icon-anonymize-failed.svg + - assets/svg/Polygon.svg # coin icons - assets/svg/coin_icons/Bitcoin.svg - assets/svg/coin_icons/Bitcoincash.svg @@ -312,6 +313,7 @@ flutter: - assets/svg/exchange-3.svg - assets/svg/message-question-1.svg - assets/svg/drd-icon.svg + - assets/svg/box-auto.svg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. diff --git a/scripts/prebuild.sh b/scripts/prebuild.sh new file mode 100644 index 000000000..31acfa82c --- /dev/null +++ b/scripts/prebuild.sh @@ -0,0 +1,6 @@ +# Create template lib/external_api_keys.dart file if it doesn't already exist +KEYS=../lib/external_api_keys.dart +if ! test -f "$KEYS"; then + echo 'prebuild.sh: creating template lib/external_api_keys.dart file' + echo 'const kChangeNowApiKey = "";' > $KEYS +fi diff --git a/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart b/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart index c373b739a..a9a7fdaf7 100644 --- a/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart +++ b/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart @@ -1,3092 +1,3090 @@ -// import 'dart:convert'; -// -// import 'package:bitcoindart/bitcoindart.dart'; -// import 'package:decimal/decimal.dart'; -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:hive/hive.dart'; -// import 'package:hive_test/hive_test.dart'; -// import 'package:mockito/annotations.dart'; -// import 'package:mockito/mockito.dart'; -// import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; -// import 'package:stackwallet/electrumx_rpc/electrumx.dart'; -// import 'package:stackwallet/hive/db.dart'; -// import 'package:stackwallet/models/paymint/fee_object_model.dart'; -// import 'package:stackwallet/models/paymint/transactions_model.dart'; -// import 'package:stackwallet/models/paymint/utxo_model.dart'; -// import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'; -// import 'package:stackwallet/services/price.dart'; -// import 'package:stackwallet/services/transaction_notification_tracker.dart'; -// import 'package:stackwallet/utilities/enums/coin_enum.dart'; -// import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; -// -// import 'bitcoincash_history_sample_data.dart'; -// import 'bitcoincash_wallet_test.mocks.dart'; -// import 'bitcoincash_wallet_test_parameters.dart'; -// -// @GenerateMocks( -// [ElectrumX, CachedElectrumX, PriceAPI, TransactionNotificationTracker]) -void main() {} -// group("bitcoincash constants", () { -// test("bitcoincash minimum confirmations", () async { -// expect(MINIMUM_CONFIRMATIONS, 3); -// }); -// test("bitcoincash dust limit", () async { -// expect(DUST_LIMIT, 546); -// }); -// test("bitcoincash mainnet genesis block hash", () async { -// expect(GENESIS_HASH_MAINNET, -// "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); -// }); -// -// test("bitcoincash testnet genesis block hash", () async { -// expect(GENESIS_HASH_TESTNET, -// "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); -// }); -// }); -// -// test("bitcoincash DerivePathType enum", () { -// expect(DerivePathType.values.length, 2); -// expect(DerivePathType.values.toString(), -// "[DerivePathType.bip44, DerivePathType.bip49]"); -// }); -// -// group("bip32 node/root", () { -// test("getBip32Root", () { -// final root = getBip32Root(TEST_MNEMONIC, bitcoincash); -// expect(root.toWIF(), ROOT_WIF); -// }); -// -// test("basic getBip32Node", () { -// final node = -// getBip32Node(0, 0, TEST_MNEMONIC, bitcoincash, DerivePathType.bip44); -// expect(node.toWIF(), NODE_WIF_44); -// }); -// }); -// -// group("validate mainnet bitcoincash addresses", () { -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// BitcoinCashWallet? mainnetWallet; -// -// setUp(() { -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// mainnetWallet = BitcoinCashWallet( -// walletId: "validateAddressMainNet", -// walletName: "validateAddressMainNet", -// coin: Coin.bitcoincash, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// test("valid mainnet legacy/p2pkh address type", () { -// expect( -// mainnetWallet?.addressType( -// address: "1DP3PUePwMa5CoZwzjznVKhzdLsZftjcAT"), -// DerivePathType.bip44); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("invalid base58 address type", () { -// expect( -// () => mainnetWallet?.addressType( -// address: "mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), -// throwsArgumentError); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("invalid bech32 address type", () { -// expect( -// () => mainnetWallet?.addressType( -// address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"), -// throwsArgumentError); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("address has no matching script", () { -// expect( -// () => mainnetWallet?.addressType( -// address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"), -// throwsArgumentError); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("invalid mainnet bitcoincash legacy/p2pkh address", () { -// expect( -// mainnetWallet?.validateAddress("mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), -// true); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// group("testNetworkConnection", () { -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// BitcoinCashWallet? bch; -// -// setUp(() { -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// bch = BitcoinCashWallet( -// walletId: "testNetworkConnection", -// walletName: "testNetworkConnection", -// coin: Coin.bitcoincash, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// test("attempted connection fails due to server error", () async { -// when(client?.ping()).thenAnswer((_) async => false); -// final bool? result = await bch?.testNetworkConnection(); -// expect(result, false); -// expect(secureStore?.interactions, 0); -// verify(client?.ping()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("attempted connection fails due to exception", () async { -// when(client?.ping()).thenThrow(Exception); -// final bool? result = await bch?.testNetworkConnection(); -// expect(result, false); -// expect(secureStore?.interactions, 0); -// verify(client?.ping()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("attempted connection test success", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// final bool? result = await bch?.testNetworkConnection(); -// expect(result, true); -// expect(secureStore?.interactions, 0); -// verify(client?.ping()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// group("basic getters, setters, and functions", () { -// final bchcoin = Coin.bitcoincash; -// final testWalletId = "BCHtestWalletID"; -// final testWalletName = "BCHWallet"; -// -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// BitcoinCashWallet? bch; -// -// setUp(() async { -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// test("get networkType main", () async { -// expect(bch?.coin, bchcoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get networkType test", () async { -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// expect(bch?.coin, bchcoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get cryptoCurrency", () async { -// expect(Coin.bitcoincash, Coin.bitcoincash); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get coinName", () async { -// expect(Coin.bitcoincash, Coin.bitcoincash); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get coinTicker", () async { -// expect(Coin.bitcoincash, Coin.bitcoincash); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get and set walletName", () async { -// expect(Coin.bitcoincash, Coin.bitcoincash); -// bch?.walletName = "new name"; -// expect(bch?.walletName, "new name"); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("estimateTxFee", () async { -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1), 356); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 900), 356); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 999), 356); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1000), 356); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1001), 712); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712); -// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get fees succeeds", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.estimateFee(blocks: 1)) -// .thenAnswer((realInvocation) async => Decimal.zero); -// when(client?.estimateFee(blocks: 5)) -// .thenAnswer((realInvocation) async => Decimal.one); -// when(client?.estimateFee(blocks: 20)) -// .thenAnswer((realInvocation) async => Decimal.ten); -// -// final fees = await bch?.fees; -// expect(fees, isA()); -// expect(fees?.slow, 1000000000); -// expect(fees?.medium, 100000000); -// expect(fees?.fast, 0); -// -// verify(client?.estimateFee(blocks: 1)).called(1); -// verify(client?.estimateFee(blocks: 5)).called(1); -// verify(client?.estimateFee(blocks: 20)).called(1); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get fees fails", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.estimateFee(blocks: 1)) -// .thenAnswer((realInvocation) async => Decimal.zero); -// when(client?.estimateFee(blocks: 5)) -// .thenAnswer((realInvocation) async => Decimal.one); -// when(client?.estimateFee(blocks: 20)) -// .thenThrow(Exception("some exception")); -// -// bool didThrow = false; -// try { -// await bch?.fees; -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.estimateFee(blocks: 1)).called(1); -// verify(client?.estimateFee(blocks: 5)).called(1); -// verify(client?.estimateFee(blocks: 20)).called(1); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get maxFee", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.estimateFee(blocks: 20)) -// .thenAnswer((realInvocation) async => Decimal.zero); -// when(client?.estimateFee(blocks: 5)) -// .thenAnswer((realInvocation) async => Decimal.one); -// when(client?.estimateFee(blocks: 1)) -// .thenAnswer((realInvocation) async => Decimal.ten); -// -// final maxFee = await bch?.maxFee; -// expect(maxFee, 1000000000); -// -// verify(client?.estimateFee(blocks: 1)).called(1); -// verify(client?.estimateFee(blocks: 5)).called(1); -// verify(client?.estimateFee(blocks: 20)).called(1); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// group("BCHWallet service class functions that depend on shared storage", () { -// final bchcoin = Coin.bitcoincash; -// final bchtestcoin = Coin.bitcoincashTestnet; -// final testWalletId = "BCHtestWalletID"; -// final testWalletName = "BCHWallet"; -// -// bool hiveAdaptersRegistered = false; -// -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// BitcoinCashWallet? bch; -// -// setUp(() async { -// await setUpTestHive(); -// if (!hiveAdaptersRegistered) { -// hiveAdaptersRegistered = true; -// -// // Registering Transaction Model Adapters -// Hive.registerAdapter(TransactionDataAdapter()); -// Hive.registerAdapter(TransactionChunkAdapter()); -// Hive.registerAdapter(TransactionAdapter()); -// Hive.registerAdapter(InputAdapter()); -// Hive.registerAdapter(OutputAdapter()); -// -// // Registering Utxo Model Adapters -// Hive.registerAdapter(UtxoDataAdapter()); -// Hive.registerAdapter(UtxoObjectAdapter()); -// Hive.registerAdapter(StatusAdapter()); -// -// final wallets = await Hive.openBox('wallets'); -// await wallets.put('currentWalletName', testWalletName); -// } -// -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// // test("initializeWallet no network", () async { -// // when(client?.ping()).thenAnswer((_) async => false); -// // await Hive.openBox(testWalletId); -// // await Hive.openBox(DB.boxNamePrefs); -// // expect(bch?.initializeNew(), false); -// // expect(secureStore?.interactions, 0); -// // verify(client?.ping()).called(0); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // test("initializeExisting no network exception", () async { -// // when(client?.ping()).thenThrow(Exception("Network connection failed")); -// // // bch?.initializeNew(); -// // expect(bch?.initializeExisting(), false); -// // expect(secureStore?.interactions, 0); -// // verify(client?.ping()).called(1); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// test("initializeNew mainnet throws bad network", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// expectLater(() => bch?.initializeNew(), throwsA(isA())) -// .then((_) { -// expect(secureStore?.interactions, 0); -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// test("initializeNew throws mnemonic overwrite exception", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// await secureStore?.write( -// key: "${testWalletId}_mnemonic", value: "some mnemonic"); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// expectLater(() => bch?.initializeNew(), throwsA(isA())) -// .then((_) { -// expect(secureStore?.interactions, 2); -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// test("initializeExisting testnet throws bad network", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// expectLater(() => bch?.initializeNew(), throwsA(isA())) -// .then((_) { -// expect(secureStore?.interactions, 0); -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// // test("getCurrentNode", () async { -// // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) -// // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); -// // when(client?.ping()).thenAnswer((_) async => true); -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_MAINNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // // await DebugService.instance.init(); -// // expect(bch?.initializeExisting(), true); -// // -// // bool didThrow = false; -// // try { -// // await bch?.getCurrentNode(); -// // } catch (_) { -// // didThrow = true; -// // } -// // // expect no nodes on a fresh wallet unless set in db externally -// // expect(didThrow, true); -// // -// // // set node -// // final wallet = await Hive.openBox(testWalletId); -// // await wallet.put("nodes", { -// // "default": { -// // "id": "some nodeID", -// // "ipAddress": "some address", -// // "port": "9000", -// // "useSSL": true, -// // } -// // }); -// // await wallet.put("activeNodeName", "default"); -// // -// // // try fetching again -// // final node = await bch?.getCurrentNode(); -// // expect(node.toString(), -// // "ElectrumXNode: {address: some address, port: 9000, name: default, useSSL: true}"); -// // -// // verify(client?.ping()).called(1); -// // verify(client?.getServerFeatures()).called(1); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // test("initializeWallet new main net wallet", () async { -// // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) -// // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); -// // when(client?.ping()).thenAnswer((_) async => true); -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_MAINNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // expect(await bch?.initializeWallet(), true); -// // -// // final wallet = await Hive.openBox(testWalletId); -// // -// // expect(await wallet.get("addressBookEntries"), {}); -// // expect(await wallet.get('notes'), null); -// // expect(await wallet.get("id"), testWalletId); -// // expect(await wallet.get("preferredFiatCurrency"), null); -// // expect(await wallet.get("blocked_tx_hashes"), ["0xdefault"]); -// // -// // final changeAddressesP2PKH = await wallet.get("changeAddressesP2PKH"); -// // expect(changeAddressesP2PKH, isA>()); -// // expect(changeAddressesP2PKH.length, 1); -// // expect(await wallet.get("changeIndexP2PKH"), 0); -// // -// // final receivingAddressesP2PKH = -// // await wallet.get("receivingAddressesP2PKH"); -// // expect(receivingAddressesP2PKH, isA>()); -// // expect(receivingAddressesP2PKH.length, 1); -// // expect(await wallet.get("receivingIndexP2PKH"), 0); -// // -// // final p2pkhReceiveDerivations = jsonDecode(await secureStore?.read( -// // key: "${testWalletId}_receiveDerivationsP2PKH")); -// // expect(p2pkhReceiveDerivations.length, 1); -// // -// // final p2pkhChangeDerivations = jsonDecode(await secureStore.read( -// // key: "${testWalletId}_changeDerivationsP2PKH")); -// // expect(p2pkhChangeDerivations.length, 1); -// // -// // expect(secureStore?.interactions, 10); -// // expect(secureStore?.reads, 7); -// // expect(secureStore?.writes, 3); -// // expect(secureStore?.deletes, 0); -// // verify(client?.ping()).called(1); -// // verify(client?.getServerFeatures()).called(1); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // // test("initializeWallet existing main net wallet", () async { -// // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) -// // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); -// // // when(client?.ping()).thenAnswer((_) async => true); -// // // when(client?.getBatchHistory(args: anyNamed("args"))) -// // // .thenAnswer((_) async => {}); -// // // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // // "hosts": {}, -// // // "pruning": null, -// // // "server_version": "Unit tests", -// // // "protocol_min": "1.4", -// // // "protocol_max": "1.4.2", -// // // "genesis_hash": GENESIS_HASH_MAINNET, -// // // "hash_function": "sha256", -// // // "services": [] -// // // }); -// // // // init new wallet -// // // expect(bch?.initializeNew(), true); -// // // -// // // // fetch data to compare later -// // // final newWallet = await Hive.openBox(testWalletId); -// // // -// // // final addressBookEntries = await newWallet.get("addressBookEntries"); -// // // final notes = await newWallet.get('notes'); -// // // final wID = await newWallet.get("id"); -// // // final currency = await newWallet.get("preferredFiatCurrency"); -// // // final blockedHashes = await newWallet.get("blocked_tx_hashes"); -// // // -// // // final changeAddressesP2PKH = await newWallet.get("changeAddressesP2PKH"); -// // // final changeIndexP2PKH = await newWallet.get("changeIndexP2PKH"); -// // // -// // // final receivingAddressesP2PKH = -// // // await newWallet.get("receivingAddressesP2PKH"); -// // // final receivingIndexP2PKH = await newWallet.get("receivingIndexP2PKH"); -// // // -// // // final p2pkhReceiveDerivations = jsonDecode(await secureStore?.read( -// // // key: "${testWalletId}_receiveDerivationsP2PKH")); -// // // -// // // final p2pkhChangeDerivations = jsonDecode(await secureStore?.read( -// // // key: "${testWalletId}_changeDerivationsP2PKH")); -// // // -// // // // exit new wallet -// // // await bch?.exit(); -// // // -// // // // open existing/created wallet -// // // bch = BitcoinCashWallet( -// // // walletId: testWalletId, -// // // walletName: testWalletName, -// // // coin: dtestcoin, -// // // client: client!, -// // // cachedClient: cachedClient!, -// // // priceAPI: priceAPI, -// // // secureStore: secureStore, -// // // ); -// // // -// // // // init existing -// // // expect(bch?.initializeExisting(), true); -// // // -// // // // compare data to ensure state matches state of previously closed wallet -// // // final wallet = await Hive.openBox(testWalletId); -// // // -// // // expect(await wallet.get("addressBookEntries"), addressBookEntries); -// // // expect(await wallet.get('notes'), notes); -// // // expect(await wallet.get("id"), wID); -// // // expect(await wallet.get("preferredFiatCurrency"), currency); -// // // expect(await wallet.get("blocked_tx_hashes"), blockedHashes); -// // // -// // // expect(await wallet.get("changeAddressesP2PKH"), changeAddressesP2PKH); -// // // expect(await wallet.get("changeIndexP2PKH"), changeIndexP2PKH); -// // // -// // // expect( -// // // await wallet.get("receivingAddressesP2PKH"), receivingAddressesP2PKH); -// // // expect(await wallet.get("receivingIndexP2PKH"), receivingIndexP2PKH); -// // // -// // // expect( -// // // jsonDecode(await secureStore?.read( -// // // key: "${testWalletId}_receiveDerivationsP2PKH")), -// // // p2pkhReceiveDerivations); -// // // -// // // expect( -// // // jsonDecode(await secureStore?.read( -// // // key: "${testWalletId}_changeDerivationsP2PKH")), -// // // p2pkhChangeDerivations); -// // // -// // // expect(secureStore?.interactions, 12); -// // // expect(secureStore?.reads, 9); -// // // expect(secureStore?.writes, 3); -// // // expect(secureStore?.deletes, 0); -// // // verify(client?.ping()).called(2); -// // // verify(client?.getServerFeatures()).called(1); -// // // verifyNoMoreInteractions(client); -// // // verifyNoMoreInteractions(cachedClient); -// // // verifyNoMoreInteractions(priceAPI); -// // // }); -// -// test("get current receiving addresses", () async { -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchtestcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// expect( -// Address.validateAddress( -// await bch!.currentReceivingAddress, bitcoincashtestnet), -// true); -// expect( -// Address.validateAddress( -// await bch!.currentReceivingAddress, bitcoincashtestnet), -// true); -// expect( -// Address.validateAddress( -// await bch!.currentReceivingAddress, bitcoincashtestnet), -// true); -// -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get allOwnAddresses", () async { -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchtestcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// final addresses = await bch?.allOwnAddresses; -// expect(addresses, isA>()); -// expect(addresses?.length, 2); -// -// for (int i = 0; i < 2; i++) { -// expect( -// Address.validateAddress(addresses![i], bitcoincashtestnet), true); -// } -// -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// // test("get utxos and balances", () async { -// // bch = BitcoinCashWallet( -// // walletId: testWalletId, -// // walletName: testWalletName, -// // coin: dtestcoin, -// // client: client!, -// // cachedClient: cachedClient!, -// // tracker: tracker!, -// // priceAPI: priceAPI, -// // secureStore: secureStore, -// // ); -// // when(client?.ping()).thenAnswer((_) async => true); -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_TESTNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // -// // await Hive.openBox(testWalletId); -// // await Hive.openBox(DB.boxNamePrefs); -// // -// // when(client?.getBatchUTXOs(args: anyNamed("args"))) -// // .thenAnswer((_) async => batchGetUTXOResponse0); -// // -// // when(client?.estimateFee(blocks: 20)) -// // .thenAnswer((realInvocation) async => Decimal.zero); -// // when(client?.estimateFee(blocks: 5)) -// // .thenAnswer((realInvocation) async => Decimal.one); -// // when(client?.estimateFee(blocks: 1)) -// // .thenAnswer((realInvocation) async => Decimal.ten); -// // -// // when(cachedClient?.getTransaction( -// // txHash: tx1.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).thenAnswer((_) async => tx1Raw); -// // when(cachedClient?.getTransaction( -// // txHash: tx2.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).thenAnswer((_) async => tx2Raw); -// // when(cachedClient?.getTransaction( -// // txHash: tx3.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).thenAnswer((_) async => tx3Raw); -// // when(cachedClient?.getTransaction( -// // txHash: tx4.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).thenAnswer((_) async => tx4Raw); -// // -// // await bch?.initializeNew(); -// // await bch?.initializeExisting(); -// // -// // final utxoData = await bch?.utxoData; -// // expect(utxoData, isA()); -// // expect(utxoData.toString(), -// // r"{totalUserCurrency: $103.2173, satoshiBalance: 1032173000, bitcoinBalance: null, unspentOutputArray: [{txid: 86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a, vout: 0, value: 800000000, fiat: $80, blocked: false, status: {confirmed: true, blockHash: e52cabb4445eb9ceb3f4f8d68cc64b1ede8884ce560296c27826a48ecc477370, blockHeight: 4274457, blockTime: 1655755742, confirmations: 100}}, {txid: a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469, vout: 0, value: 72173000, fiat: $7.2173, blocked: false, status: {confirmed: false, blockHash: bd239f922b3ecec299a90e4d1ce389334e8df4b95470fb5919966b0b650bb95b, blockHeight: 4270459, blockTime: 1655500912, confirmations: 0}}, {txid: 68c159dcc2f962cbc61f7dd3c8d0dcc14da8adb443811107115531c853fc0c60, vout: 1, value: 100000000, fiat: $10, blocked: false, status: {confirmed: false, blockHash: 9fee9b9446cfe81abb1a17bec56e6c160d9a6527e5b68b1141a827573bc2649f, blockHeight: 4255659, blockTime: 1654553247, confirmations: 0}}, {txid: 628a78606058ce4036aee3907e042742156c1894d34419578de5671b53ea5800, vout: 0, value: 60000000, fiat: $6, blocked: false, status: {confirmed: true, blockHash: bc461ab43e3a80d9a4d856ee9ff70f41d86b239d5f0581ffd6a5c572889a6b86, blockHeight: 4270352, blockTime: 1652888705, confirmations: 100}}]}"); -// // -// // final outputs = await bch?.unspentOutputs; -// // expect(outputs, isA>()); -// // expect(outputs?.length, 4); -// // -// // final availableBalance = await bch?.availableBalance; -// // expect(availableBalance, Decimal.parse("8.6")); -// // -// // final totalBalance = await bch?.totalBalance; -// // expect(totalBalance, Decimal.parse("10.32173")); -// // -// // final pendingBalance = await bch?.pendingBalance; -// // expect(pendingBalance, Decimal.parse("1.72173")); -// // -// // final balanceMinusMaxFee = await bch?.balanceMinusMaxFee; -// // expect(balanceMinusMaxFee, Decimal.parse("7.6")); -// // -// // verify(client?.ping()).called(1); -// // verify(client?.getServerFeatures()).called(1); -// // verify(client?.estimateFee(blocks: 1)).called(1); -// // verify(client?.estimateFee(blocks: 5)).called(1); -// // verify(client?.estimateFee(blocks: 20)).called(1); -// // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: tx1.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: tx2.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: tx3.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: tx4.txid, -// // coin: Coin.bitcoincashTestNet, -// // )).called(1); -// // -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// // -// // // test("get utxos - multiple batches", () async { -// // // bch = BitcoinCashWallet( -// // // walletId: testWalletId, -// // // walletName: testWalletName, -// // // coin: dtestcoin, -// // // client: client!, -// // // cachedClient: cachedClient!, -// // // priceAPI: priceAPI, -// // // secureStore: secureStore, -// // // ); -// // // when(client?.ping()).thenAnswer((_) async => true); -// // // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // // "hosts": {}, -// // // "pruning": null, -// // // "server_version": "Unit tests", -// // // "protocol_min": "1.4", -// // // "protocol_max": "1.4.2", -// // // "genesis_hash": GENESIS_HASH_TESTNET, -// // // "hash_function": "sha256", -// // // "services": [] -// // // }); -// // // -// // // when(client?.getBatchUTXOs(args: anyNamed("args"))) -// // // .thenAnswer((_) async => {}); -// // // -// // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) -// // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); -// // // -// // // await bch?.initializeWallet(); -// // // -// // // // add some extra addresses to make sure we have more than the single batch size of 10 -// // // final wallet = await Hive.openBox(testWalletId); -// // // final addresses = await wallet.get("receivingAddressesP2PKH"); -// // // addresses.add("DQaAi9R58GXMpDyhePys6hHCuif4fhc1sN"); -// // // addresses.add("DBVhuF8QgeuxU2pssxzMgJqPhGCx5qyVkD"); -// // // addresses.add("DCAokB2CXXPWC2JPj6jrK6hxANwTF2m21x"); -// // // addresses.add("D6Y9brE3jUGPrqLmSEWh6yQdgY5b7ZkTib"); -// // // addresses.add("DKdtobt3M5b3kQWZf1zRUZn3Ys6JTQwbPL"); -// // // addresses.add("DBYiFr1BRc2zB19p8jxdSu6DvFGTdWvkVF"); -// // // addresses.add("DE5ffowvbHPzzY6aRVGpzxR2QqikXxUKPG"); -// // // addresses.add("DA97TLg1741J2aLK6z9bVZoWysgQbMR45K"); -// // // addresses.add("DGGmf9q4PKcJXauPRstsFetu9DjW1VSBYk"); -// // // addresses.add("D9bXqnTtufcb6oJyuZniCXbst8MMLzHxUd"); -// // // addresses.add("DA6nv8M4kYL4RxxKrcsPaPUA1KrFA7CTfN"); -// // // await wallet.put("receivingAddressesP2PKH", addresses); -// // // -// // // final utxoData = await bch?.utxoData; -// // // expect(utxoData, isA()); -// // // -// // // final outputs = await bch?.unspentOutputs; -// // // expect(outputs, isA>()); -// // // expect(outputs?.length, 0); -// // // -// // // verify(client?.ping()).called(1); -// // // verify(client?.getServerFeatures()).called(1); -// // // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(2); -// // // verify(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")).called(1); -// // // -// // // verifyNoMoreInteractions(client); -// // // verifyNoMoreInteractions(cachedClient); -// // // verifyNoMoreInteractions(priceAPI); -// // // }); -// // -// test("get utxos fails", () async { -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchtestcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// when(client?.getBatchUTXOs(args: anyNamed("args"))) -// .thenThrow(Exception("some exception")); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// -// final utxoData = await bch?.utxoData; -// expect(utxoData, isA()); -// expect(utxoData.toString(), -// r"{totalUserCurrency: 0.00, satoshiBalance: 0, bitcoinBalance: 0, unspentOutputArray: []}"); -// -// final outputs = await bch?.unspentOutputs; -// expect(outputs, isA>()); -// expect(outputs?.length, 0); -// -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("chain height fetch, update, and get", () async { -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: bchtestcoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// -// // get stored -// expect(await bch?.storedChainHeight, 0); -// -// // fetch fails -// when(client?.getBlockHeadTip()).thenThrow(Exception("Some exception")); -// expect(await bch?.chainHeight, -1); -// -// // fetch succeeds -// when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => { -// "height": 100, -// "hex": "some block hex", -// }); -// expect(await bch?.chainHeight, 100); -// -// // update -// await bch?.updateStoredChainHeight(newHeight: 1000); -// -// // fetch updated -// expect(await bch?.storedChainHeight, 1000); -// -// verifyNever(client?.ping()).called(0); -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBlockHeadTip()).called(2); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("getTxCount succeeds", () async { -// when(client?.getHistory( -// scripthash: -// "1df1cab6d109d506aa424b00b6a013c5e1947dc13b78d62b4d0e9f518b3035d1")) -// .thenAnswer((realInvocation) async => [ -// { -// "height": 757727, -// "tx_hash": -// "aaac451c49c2e3bcbccb8a9fded22257eeb94c1702b456171aa79250bc1b20e0" -// }, -// { -// "height": 0, -// "tx_hash": -// "9ac29f35b72ca596bc45362d1f9556b0555e1fb633ca5ac9147a7fd467700afe" -// } -// ]); -// -// final count = -// await bch?.getTxCount(address: "1MMi672ueYFXLLdtZqPe4FsrS46gNDyRq1"); -// -// expect(count, 2); -// -// verify(client?.getHistory( -// scripthash: -// "1df1cab6d109d506aa424b00b6a013c5e1947dc13b78d62b4d0e9f518b3035d1")) -// .called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// //TODO - Needs refactoring -// test("getTxCount fails", () async { -// when(client?.getHistory( -// scripthash: -// "64953f7db441a21172de206bf70b920c8c718ed4f03df9a85073c0400be0053c")) -// .thenThrow(Exception("some exception")); -// -// bool didThrow = false; -// try { -// await bch?.getTxCount(address: "D6biRASajCy7GcJ8R6ZP4RE94fNRerJLCC"); -// } catch (_) { -// didThrow = true; -// } -// expect(didThrow, true); -// -// verifyNever(client?.getHistory( -// scripthash: -// "64953f7db441a21172de206bf70b920c8c718ed4f03df9a85073c0400be0053c")) -// .called(0); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("_checkCurrentReceivingAddressesForTransactions succeeds", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// .thenAnswer((realInvocation) async => [ -// { -// "height": 4270385, -// "tx_hash": -// "c07f740ad72c0dd759741f4c9ab4b1586a22bc16545584364ac9b3d845766271" -// }, -// { -// "height": 4270459, -// "tx_hash": -// "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a" -// } -// ]); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// -// bool didThrow = false; -// try { -// await bch?.checkCurrentReceivingAddressesForTransactions(); -// } catch (_) { -// didThrow = true; -// } -// expect(didThrow, false); -// -// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); -// verify(client?.getServerFeatures()).called(1); -// verifyNever(client?.ping()).called(0); -// -// expect(secureStore?.interactions, 20); -// expect(secureStore?.reads, 13); -// expect(secureStore?.writes, 7); -// expect(secureStore?.deletes, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("_checkCurrentReceivingAddressesForTransactions fails", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// .thenThrow(Exception("some exception")); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// -// bool didThrow = false; -// try { -// await bch?.checkCurrentReceivingAddressesForTransactions(); -// } catch (_) { -// didThrow = true; -// } -// expect(didThrow, true); -// -// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); -// verify(client?.getServerFeatures()).called(1); -// verifyNever(client?.ping()).called(0); -// -// expect(secureStore?.interactions, 14); -// expect(secureStore?.reads, 9); -// expect(secureStore?.writes, 5); -// expect(secureStore?.deletes, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("_checkCurrentChangeAddressesForTransactions succeeds", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// .thenAnswer((realInvocation) async => [ -// { -// "height": 4286283, -// "tx_hash": -// "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b" -// }, -// { -// "height": 4286295, -// "tx_hash": -// "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a" -// } -// ]); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// -// bool didThrow = false; -// try { -// await bch?.checkCurrentChangeAddressesForTransactions(); -// } catch (_) { -// didThrow = true; -// } -// expect(didThrow, false); -// -// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); -// verify(client?.getServerFeatures()).called(1); -// verifyNever(client?.ping()).called(0); -// -// expect(secureStore?.interactions, 20); -// expect(secureStore?.reads, 13); -// expect(secureStore?.writes, 7); -// expect(secureStore?.deletes, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("_checkCurrentChangeAddressesForTransactions fails", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// .thenThrow(Exception("some exception")); -// -// await Hive.openBox(testWalletId); -// await Hive.openBox(DB.boxNamePrefs); -// -// await bch?.initializeNew(); -// await bch?.initializeExisting(); -// -// bool didThrow = false; -// try { -// await bch?.checkCurrentChangeAddressesForTransactions(); -// } catch (_) { -// didThrow = true; -// } -// expect(didThrow, true); -// -// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); -// verify(client?.getServerFeatures()).called(1); -// verifyNever(client?.ping()).called(0); -// -// expect(secureStore?.interactions, 14); -// expect(secureStore?.reads, 9); -// expect(secureStore?.writes, 5); -// expect(secureStore?.deletes, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// // test("getAllTxsToWatch", () async { -// // TestWidgetsFlutterBinding.ensureInitialized(); -// // var notifications = {"show": 0}; -// // const MethodChannel('dexterous.com/flutter/local_notifications') -// // .setMockMethodCallHandler((call) async { -// // notifications[call.method]++; -// // }); -// // -// // bch?.pastUnconfirmedTxs = { -// // "88b7b5077d940dde1bc63eba37a09dec8e7b9dad14c183a2e879a21b6ec0ac1c", -// // "b39bac02b65af46a49e2985278fe24ca00dd5d627395d88f53e35568a04e10fa", -// // }; -// // -// // await bch?.getAllTxsToWatch(transactionData); -// // expect(notifications.length, 1); -// // expect(notifications["show"], 3); -// // -// // expect(bch?.unconfirmedTxs, { -// // "b2f75a017a7435f1b8c2e080a865275d8f80699bba68d8dce99a94606e7b3528", -// // 'dcca229760b44834478f0b266c9b3f5801e0139fdecacdc0820e447289a006d3', -// // }); -// // -// // expect(secureStore?.interactions, 0); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// // -// // test("refreshIfThereIsNewData true A", () async { -// // when(client?.getTransaction( -// // txHash: -// // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", -// // )).thenAnswer((_) async => tx2Raw); -// // when(client?.getTransaction( -// // txHash: -// // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a", -// // )).thenAnswer((_) async => tx1Raw); -// // -// // bch = BitcoinCashWallet( -// // walletId: testWalletId, -// // walletName: testWalletName, -// // coin: dtestcoin, -// // client: client!, -// // cachedClient: cachedClient!, -// // priceAPI: priceAPI, -// // secureStore: secureStore, -// // ); -// // final wallet = await Hive.openBox(testWalletId); -// // await wallet.put('receivingAddressesP2PKH', []); -// // -// // await wallet.put('changeAddressesP2PKH', []); -// // -// // bch?.unconfirmedTxs = { -// // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", -// // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a" -// // }; -// // -// // final result = await bch?.refreshIfThereIsNewData(); -// // -// // expect(result, true); -// // -// // verify(client?.getTransaction( -// // txHash: -// // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", -// // )).called(1); -// // verify(client?.getTransaction( -// // txHash: -// // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a", -// // )).called(1); -// // -// // expect(secureStore?.interactions, 0); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// // -// // test("refreshIfThereIsNewData true B", () async { -// // // when(priceAPI.getbitcoincashPrice(baseCurrency: "USD")) -// // // .thenAnswer((_) async => Decimal.fromInt(10)); -// // -// // when(client?.getBatchHistory(args: anyNamed("args"))) -// // .thenAnswer((realInvocation) async { -// // final uuids = Map>.from(realInvocation -// // .namedArguments.values.first as Map) -// // .keys -// // .toList(growable: false); -// // return { -// // uuids[0]: [ -// // { -// // "tx_hash": -// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", -// // "height": 4286305 -// // }, -// // { -// // "tx_hash": -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // "height": 4286295 -// // } -// // ], -// // uuids[1]: [ -// // { -// // "tx_hash": -// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", -// // "height": 4286283 -// // } -// // ], -// // }; -// // }); -// // -// // when(client?.getTransaction( -// // txHash: -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // )).thenAnswer((_) async => tx2Raw); -// // when(client?.getTransaction( -// // txHash: -// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", -// // )).thenAnswer((_) async => tx1Raw); -// // -// // when(cachedClient?.getTransaction( -// // txHash: -// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx3Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx3Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx1Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "4493caff0e1b4f248e3c6219e7f288cfdb46c32b72a77aec469098c5f7f5154e", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx5Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "e095cbe5531d174c3fc5c9c39a0e6ba2769489cdabdc17b35b2e3a33a3c2fc61", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx6Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx7Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "7b34e60cc37306f866667deb67b14096f4ea2add941fd6e2238a639000642b82", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx4Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "a70c6f0690fa84712dc6b3d20ee13862fe015a08cf2dc8949c4300d49c3bdeb5", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx8Raw); -// // -// // bch = BitcoinCashWallet( -// // walletId: testWalletId, -// // walletName: testWalletName, -// // coin: dtestcoin, -// // client: client!, -// // cachedClient: cachedClient!, -// // priceAPI: priceAPI, -// // secureStore: secureStore, -// // ); -// // final wallet = await Hive.openBox(testWalletId); -// // await wallet.put('receivingAddressesP2PKH', []); -// // -// // await wallet.put('changeAddressesP2PKH', []); -// // -// // bch?.unconfirmedTxs = { -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // }; -// // -// // final result = await bch?.refreshIfThereIsNewData(); -// // -// // expect(result, true); -// // -// // verify(client?.getBatchHistory(args: anyNamed("args"))).called(2); -// // verify(client?.getTransaction( -// // txHash: -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // )).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: anyNamed("tx_hash"), -// // verbose: true, -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .called(9); -// // // verify(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")).called(1); -// // -// // expect(secureStore?.interactions, 0); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // test("refreshIfThereIsNewData false A", () async { -// // // when(priceAPI.getbitcoincashPrice(baseCurrency: "USD")) -// // // .thenAnswer((_) async => Decimal.fromInt(10)); -// // -// // when(client?.getBatchHistory(args: anyNamed("args"))) -// // .thenAnswer((realInvocation) async { -// // final uuids = Map>.from(realInvocation -// // .namedArguments.values.first as Map) -// // .keys -// // .toList(growable: false); -// // return { -// // uuids[0]: [ -// // { -// // "tx_hash": -// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", -// // "height": 4286305 -// // }, -// // { -// // "tx_hash": -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // "height": 4286295 -// // } -// // ], -// // uuids[1]: [ -// // { -// // "tx_hash": -// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", -// // "height": 4286283 -// // } -// // ], -// // }; -// // }); -// // -// // when(client?.getTransaction( -// // txHash: -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // )).thenAnswer((_) async => tx2Raw); -// // when(client?.getTransaction( -// // txHash: -// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", -// // )).thenAnswer((_) async => tx1Raw); -// // -// // when(cachedClient?.getTransaction( -// // txHash: -// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx1Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx2Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx3Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "4493caff0e1b4f248e3c6219e7f288cfdb46c32b72a77aec469098c5f7f5154e", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx5Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "7b34e60cc37306f866667deb67b14096f4ea2add941fd6e2238a639000642b82", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx4Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "e095cbe5531d174c3fc5c9c39a0e6ba2769489cdabdc17b35b2e3a33a3c2fc61", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx6Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx7Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "a70c6f0690fa84712dc6b3d20ee13862fe015a08cf2dc8949c4300d49c3bdeb5", -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx8Raw); -// // -// // bch = BitcoinCashWallet( -// // walletId: testWalletId, -// // walletName: testWalletName, -// // coin: dtestcoin, -// // client: client!, -// // cachedClient: cachedClient!, -// // tracker: tracker!, -// // priceAPI: priceAPI, -// // secureStore: secureStore, -// // ); -// // final wallet = await Hive.openBox(testWalletId); -// // await wallet.put('receivingAddressesP2PKH', []); -// // -// // await wallet.put('changeAddressesP2PKH', []); -// // -// // bch?.unconfirmedTxs = { -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9" -// // }; -// // -// // final result = await bch?.refreshIfThereIsNewData(); -// // -// // expect(result, false); -// // -// // verify(client?.getBatchHistory(args: anyNamed("args"))).called(2); -// // verify(client?.getTransaction( -// // txHash: -// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // )).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: anyNamed("tx_hash"), -// // verbose: true, -// // coin: Coin.bitcoincashTestNet, -// // callOutSideMainIsolate: false)) -// // .called(15); -// // // verify(priceAPI.getbitcoincashPrice(baseCurrency: "USD")).called(1); -// // -// // expect(secureStore?.interactions, 0); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // // test("refreshIfThereIsNewData false B", () async { -// // // when(client?.getBatchHistory(args: anyNamed("args"))) -// // // .thenThrow(Exception("some exception")); -// // // -// // // when(client?.getTransaction( -// // // txHash: -// // // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // // )).thenAnswer((_) async => tx2Raw); -// // // -// // // bch = BitcoinCashWallet( -// // // walletId: testWalletId, -// // // walletName: testWalletName, -// // // coin: dtestcoin, -// // // client: client!, -// // // cachedClient: cachedClient!, -// // // tracker: tracker!, -// // // priceAPI: priceAPI, -// // // secureStore: secureStore, -// // // ); -// // // final wallet = await Hive.openBox(testWalletId); -// // // await wallet.put('receivingAddressesP2PKH', []); -// // // -// // // await wallet.put('changeAddressesP2PKH', []); -// // // -// // // bch?.unconfirmedTxs = { -// // // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", -// // // }; -// // // -// // // final result = await bch?.refreshIfThereIsNewData(); -// // // -// // // expect(result, false); -// // // -// // // verify(client?.getBatchHistory(args: anyNamed("args"))).called(1); -// // // verify(client?.getTransaction( -// // // txHash: -// // // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", -// // // )).called(1); -// // // -// // // expect(secureStore?.interactions, 0); -// // // verifyNoMoreInteractions(client); -// // // verifyNoMoreInteractions(cachedClient); -// // // verifyNoMoreInteractions(priceAPI); -// // // }); -// -// test("get mnemonic list", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// // when(client?.getBatchHistory(args: anyNamed("args"))) -// // .thenAnswer((thing) async { -// // print(jsonEncode(thing.namedArguments.entries.first.value)); -// // return {}; -// // }); -// -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// -// final wallet = await Hive.openBox(testWalletId); -// -// // add maxNumberOfIndexesToCheck and height -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// expect(await bch?.mnemonic, TEST_MNEMONIC.split(" ")); -// // -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test( -// "recoverFromMnemonic using empty seed on mainnet fails due to bad genesis hash match", -// () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// bool hasThrown = false; -// try { -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// verify(client?.getServerFeatures()).called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test( -// "recoverFromMnemonic using empty seed on testnet fails due to bad genesis hash match", -// () async { -// bch = BitcoinCashWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: Coin.bitcoincashTestnet, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// bool hasThrown = false; -// try { -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// verify(client?.getServerFeatures()).called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test( -// "recoverFromMnemonic using empty seed on mainnet fails due to attempted overwrite of mnemonic", -// () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await secureStore?.write( -// key: "${testWalletId}_mnemonic", value: "some mnemonic words"); -// -// bool hasThrown = false; -// try { -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// verify(client?.getServerFeatures()).called(1); -// -// expect(secureStore?.interactions, 2); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("recoverFromMnemonic using non empty seed on mainnet succeeds", -// () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// -// List dynamicArgValues = []; -// -// when(client?.getBatchHistory(args: anyNamed("args"))) -// .thenAnswer((realInvocation) async { -// if (realInvocation.namedArguments.values.first.length == 1) { -// dynamicArgValues.add(realInvocation.namedArguments.values.first); -// } -// -// return historyBatchResponse; -// }); -// -// // final wallet = await Hive.openBox(testWalletId); -// await Hive.openBox(testWalletId); -// -// bool hasThrown = false; -// try { -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, false); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// -// for (final arg in dynamicArgValues) { -// final map = Map>.from(arg as Map); -// -// verify(client?.getBatchHistory(args: map)).called(1); -// expect(activeScriptHashes.contains(map.values.first.first as String), -// true); -// } -// -// expect(secureStore?.interactions, 10); -// expect(secureStore?.writes, 5); -// expect(secureStore?.reads, 5); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("fullRescan succeeds", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) -// .thenAnswer((realInvocation) async {}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).thenAnswer((_) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).thenAnswer((_) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).thenAnswer((_) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).thenAnswer((_) async => {"0": []}); -// -// final wallet = await Hive.openBox(testWalletId); -// -// // restore so we have something to rescan -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// // fetch valid wallet data -// final preReceivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// -// final preReceivingAddressesP2SH = -// await wallet.get('receivingAddressesP2SH'); -// final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); -// final preReceivingIndexP2SH = await wallet.get('receivingIndexP2PKH'); -// final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); -// -// final preUtxoData = await wallet.get('latest_utxo_model'); -// final preReceiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final preChangeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// -// final preReceiveDerivationsStringP2SH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2SH"); -// final preChangeDerivationsStringP2SH = -// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); -// -// // destroy the data that the rescan will fix -// await wallet.put( -// 'receivingAddressesP2PKH', ["some address", "some other address"]); -// await wallet -// .put('changeAddressesP2PKH', ["some address", "some other address"]); -// -// await wallet.put( -// 'receivingAddressesP2SH', ["some address", "some other address"]); -// await wallet -// .put('changeAddressesP2SH', ["some address", "some other address"]); -// -// await wallet.put('receivingIndexP2PKH', 123); -// await wallet.put('changeIndexP2PKH', 123); -// -// await wallet.put('receivingIndexP2SH', 123); -// await wallet.put('changeIndexP2SH', 123); -// -// await secureStore?.write( -// key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_changeDerivationsP2PKH", value: "{}"); -// -// await secureStore?.write( -// key: "${testWalletId}_receiveDerivationsP2SH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_changeDerivationsP2SH", value: "{}"); -// -// bool hasThrown = false; -// try { -// await bch?.fullRescan(2, 1000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, false); -// -// // fetch wallet data again -// final receivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// -// final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); -// final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); -// final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); -// final changeIndexP2SH = await wallet.get('changeIndexP2SH'); -// -// final utxoData = await wallet.get('latest_utxo_model'); -// final receiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final changeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// -// final receiveDerivationsStringP2SH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2SH"); -// final changeDerivationsStringP2SH = -// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); -// -// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); -// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); -// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); -// expect(preChangeIndexP2PKH, changeIndexP2PKH); -// -// expect(preReceivingAddressesP2SH, receivingAddressesP2SH); -// expect(preChangeAddressesP2SH, changeAddressesP2SH); -// expect(preReceivingIndexP2SH, receivingIndexP2SH); -// expect(preChangeIndexP2SH, changeIndexP2SH); -// -// expect(preUtxoData, utxoData); -// -// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); -// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); -// -// expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); -// expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); -// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) -// .called(1); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).called(2); -// -// expect(secureStore?.writes, 17); -// expect(secureStore?.reads, 22); -// expect(secureStore?.deletes, 4); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("fullRescan fails", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) -// .thenAnswer((realInvocation) async {}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).thenAnswer((_) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).thenAnswer((_) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).thenAnswer((_) async => {"0": []}); -// -// final wallet = await Hive.openBox(testWalletId); -// -// // restore so we have something to rescan -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// // fetch wallet data -// final preReceivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// -// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// final preUtxoData = await wallet.get('latest_utxo_model'); -// final preReceiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final preChangeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenThrow(Exception("fake exception")); -// -// bool hasThrown = false; -// try { -// await bch?.fullRescan(2, 1000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// // fetch wallet data again -// final receivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// -// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// final utxoData = await wallet.get('latest_utxo_model'); -// final receiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final changeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// -// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); -// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); -// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); -// expect(preChangeIndexP2PKH, changeIndexP2PKH); -// expect(preUtxoData, utxoData); -// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); -// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); -// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) -// .called(1); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).called(2); -// -// expect(secureStore?.writes, 13); -// expect(secureStore?.reads, 18); -// expect(secureStore?.deletes, 8); -// }); -// -// // // test("fetchBuildTxData succeeds", () async { -// // // when(client.getServerFeatures()).thenAnswer((_) async => { -// // // "hosts": {}, -// // // "pruning": null, -// // // "server_version": "Unit tests", -// // // "protocol_min": "1.4", -// // // "protocol_max": "1.4.2", -// // // "genesis_hash": GENESIS_HASH_MAINNET, -// // // "hash_function": "sha256", -// // // "services": [] -// // // }); -// // // when(client.getBatchHistory(args: historyBatchArgs0)) -// // // .thenAnswer((_) async => historyBatchResponse); -// // // when(client.getBatchHistory(args: historyBatchArgs1)) -// // // .thenAnswer((_) async => historyBatchResponse); -// // // when(cachedClient.getTransaction( -// // // tx_hash: -// // // "339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9", -// // // coinName: "bitcoincash", -// // // callOutSideMainIsolate: false)) -// // // .thenAnswer((_) async => tx9Raw); -// // // when(cachedClient.getTransaction( -// // // tx_hash: -// // // "c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e", -// // // coinName: "bitcoincash", -// // // callOutSideMainIsolate: false)) -// // // .thenAnswer((_) async => tx10Raw); -// // // when(cachedClient.getTransaction( -// // // tx_hash: -// // // "d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c", -// // // coinName: "bitcoincash", -// // // callOutSideMainIsolate: false)) -// // // .thenAnswer((_) async => tx11Raw); -// // // -// // // // recover to fill data -// // // await bch.recoverFromMnemonic( -// // // mnemonic: TEST_MNEMONIC, -// // // maxUnusedAddressGap: 2, -// // // maxNumberOfIndexesToCheck: 1000, -// // // height: 4000); -// // // -// // // // modify addresses to trigger all change code branches -// // // final chg44 = -// // // await secureStore.read(key: testWalletId + "_changeDerivationsP2PKH"); -// // // await secureStore.write( -// // // key: testWalletId + "_changeDerivationsP2PKH", -// // // value: chg44.replaceFirst("1vFHF5q21GccoBwrB4zEUAs9i3Bfx797U", -// // // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); -// // // -// // // final data = await bch.fetchBuildTxData(utxoList); -// // // -// // // expect(data.length, 3); -// // // expect( -// // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] -// // // .length, -// // // 2); -// // // expect( -// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // .length, -// // // 3); -// // // expect( -// // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] -// // // .length, -// // // 2); -// // // expect( -// // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] -// // // ["output"], -// // // isA()); -// // // expect( -// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // ["output"], -// // // isA()); -// // // expect( -// // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] -// // // ["output"], -// // // isA()); -// // // expect( -// // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] -// // // ["keyPair"], -// // // isA()); -// // // expect( -// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // ["keyPair"], -// // // isA()); -// // // expect( -// // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] -// // // ["keyPair"], -// // // isA()); -// // // expect( -// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // ["redeemScript"], -// // // isA()); -// // // -// // // // modify addresses to trigger all receiving code branches -// // // final rcv44 = await secureStore.read( -// // // key: testWalletId + "_receiveDerivationsP2PKH"); -// // // await secureStore.write( -// // // key: testWalletId + "_receiveDerivationsP2PKH", -// // // value: rcv44.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", -// // // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); -// // // -// // // final data2 = await bch.fetchBuildTxData(utxoList); -// // // -// // // expect(data2.length, 3); -// // // expect( -// // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] -// // // .length, -// // // 2); -// // // expect( -// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // .length, -// // // 3); -// // // expect( -// // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] -// // // .length, -// // // 2); -// // // expect( -// // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] -// // // ["output"], -// // // isA()); -// // // expect( -// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // ["output"], -// // // isA()); -// // // expect( -// // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] -// // // ["output"], -// // // isA()); -// // // expect( -// // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] -// // // ["keyPair"], -// // // isA()); -// // // expect( -// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // ["keyPair"], -// // // isA()); -// // // expect( -// // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] -// // // ["keyPair"], -// // // isA()); -// // // expect( -// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] -// // // ["redeemScript"], -// // // isA()); -// // // -// // // verify(client.getServerFeatures()).called(1); -// // // verify(cachedClient.getTransaction( -// // // tx_hash: -// // // "339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9", -// // // coinName: "bitcoincash", -// // // callOutSideMainIsolate: false)) -// // // .called(2); -// // // verify(cachedClient.getTransaction( -// // // tx_hash: -// // // "c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e", -// // // coinName: "bitcoincash", -// // // callOutSideMainIsolate: false)) -// // // .called(2); -// // // verify(cachedClient.getTransaction( -// // // tx_hash: -// // // "d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c", -// // // coinName: "bitcoincash", -// // // callOutSideMainIsolate: false)) -// // // .called(2); -// // // verify(client.getBatchHistory(args: historyBatchArgs0)).called(1); -// // // verify(client.getBatchHistory(args: historyBatchArgs1)).called(1); -// // // -// // // expect(secureStore.interactions, 38); -// // // expect(secureStore.writes, 13); -// // // expect(secureStore.reads, 25); -// // // expect(secureStore.deletes, 0); -// // // -// // // verifyNoMoreInteractions(client); -// // // verifyNoMoreInteractions(cachedClient); -// // // verifyNoMoreInteractions(priceAPI); -// // // }); -// -// // test("fetchBuildTxData throws", () async { -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_MAINNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // when(client?.getBatchHistory(args: historyBatchArgs0)) -// // .thenAnswer((_) async => historyBatchResponse); -// // when(client?.getBatchHistory(args: historyBatchArgs1)) -// // .thenAnswer((_) async => historyBatchResponse); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx9Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx10Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .thenThrow(Exception("some exception")); -// // -// // // recover to fill data -// // await bch?.recoverFromMnemonic( -// // mnemonic: TEST_MNEMONIC, -// // maxUnusedAddressGap: 2, -// // maxNumberOfIndexesToCheck: 1000, -// // height: 4000); -// // -// // bool didThrow = false; -// // try { -// // await bch?.fetchBuildTxData(utxoList); -// // } catch (_) { -// // didThrow = true; -// // } -// // expect(didThrow, true); -// // -// // verify(client?.getServerFeatures()).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// // -// // expect(secureStore?.interactions, 14); -// // expect(secureStore?.writes, 7); -// // expect(secureStore?.reads, 7); -// // expect(secureStore?.deletes, 0); -// // -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // test("build transaction succeeds", () async { -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_MAINNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // when(client?.getBatchHistory(args: historyBatchArgs0)) -// // .thenAnswer((_) async => historyBatchResponse); -// // when(client?.getBatchHistory(args: historyBatchArgs1)) -// // .thenAnswer((_) async => historyBatchResponse); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "e9673acb3bfa928f92a7d5a545151a672e9613fdf972f3849e16094c1ed28268", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx9Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "fa5bfa4eb581bedb28ca96a65ee77d8e81159914b70d5b7e215994221cc02a63", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx10Raw); -// // when(cachedClient?.getTransaction( -// // txHash: -// // "694617f0000499be2f6af5f8d1ddbcf1a70ad4710c0cee6f33a13a64bba454ed", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .thenAnswer((_) async => tx11Raw); -// // -// // // recover to fill data -// // await bch?.recoverFromMnemonic( -// // mnemonic: TEST_MNEMONIC, -// // maxUnusedAddressGap: 2, -// // maxNumberOfIndexesToCheck: 1000, -// // height: 4000); -// // -// // // modify addresses to properly mock data to build a tx -// // final rcv44 = await secureStore?.read( -// // key: testWalletId + "_receiveDerivationsP2PKH"); -// // await secureStore?.write( -// // key: testWalletId + "_receiveDerivationsP2PKH", -// // value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", -// // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); -// // -// // final data = await bch?.fetchBuildTxData(utxoList); -// // -// // final txData = await bch?.buildTransaction( -// // utxosToUse: utxoList, -// // utxoSigningData: data!, -// // recipients: ["DS7cKFKdfbarMrYjFBQqEcHR5km6D51c74"], -// // satoshiAmounts: [13000]); -// // -// // expect(txData?.length, 2); -// // expect(txData?["hex"], isA()); -// // expect(txData?["vSize"], isA()); -// // -// // verify(client?.getServerFeatures()).called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "fa5bfa4eb581bedb28ca96a65ee77d8e81159914b70d5b7e215994221cc02a63", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "694617f0000499be2f6af5f8d1ddbcf1a70ad4710c0cee6f33a13a64bba454ed", -// // coin: Coin.bitcoincash, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// // -// // expect(secureStore?.interactions, 26); -// // expect(secureStore?.writes, 10); -// // expect(secureStore?.reads, 16); -// // expect(secureStore?.deletes, 0); -// // -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// test("confirmSend error 1", () async { -// bool didThrow = false; -// try { -// await bch?.confirmSend(txData: 1); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend error 2", () async { -// bool didThrow = false; -// try { -// await bch?.confirmSend(txData: 2); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend some other error code", () async { -// bool didThrow = false; -// try { -// await bch?.confirmSend(txData: 42); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend no hex", () async { -// bool didThrow = false; -// try { -// await bch?.confirmSend(txData: {"some": "strange map"}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend fails due to vSize being greater than fee", () async { -// bool didThrow = false; -// try { -// await bch -// ?.confirmSend(txData: {"hex": "a string", "fee": 1, "vSize": 10}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend fails when broadcast transactions throws", () async { -// when(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .thenThrow(Exception("some exception")); -// -// bool didThrow = false; -// try { -// await bch -// ?.confirmSend(txData: {"hex": "a string", "fee": 10, "vSize": 10}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("refresh wallet mutex locked", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// final wallet = await Hive.openBox(testWalletId); -// // recover to fill data -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// bch?.refreshMutex = true; -// -// await bch?.refresh(); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).called(1); -// -// expect(secureStore?.interactions, 10); -// expect(secureStore?.writes, 5); -// expect(secureStore?.reads, 5); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("refresh wallet throws", () async { -// when(client?.getBlockHeadTip()).thenThrow(Exception("some exception")); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// .thenThrow(Exception("some exception")); -// -// final wallet = await Hive.openBox(testWalletId); -// -// // recover to fill data -// await bch?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// await bch?.refresh(); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" -// ] -// })).called(1); -// -// verify(client?.getBlockHeadTip()).called(1); -// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); -// -// expect(secureStore?.interactions, 10); -// expect(secureStore?.writes, 5); -// expect(secureStore?.reads, 5); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// // test("refresh wallet normally", () async { -// // when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => -// // {"height": 520481, "hex": "some block hex"}); -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_MAINNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // when(client?.getBatchHistory(args: historyBatchArgs0)) -// // .thenAnswer((_) async => historyBatchResponse); -// // when(client?.getBatchHistory(args: historyBatchArgs1)) -// // .thenAnswer((_) async => historyBatchResponse); -// // when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// // .thenAnswer((_) async => []); -// // when(client?.estimateFee(blocks: anyNamed("blocks"))) -// // .thenAnswer((_) async => Decimal.one); -// // // when(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")) -// // // .thenAnswer((_) async => Decimal.one); -// // -// // await Hive.openBox(testWalletId); -// // await Hive.openBox(DB.boxNamePrefs); -// // -// // // recover to fill data -// // await bch?.recoverFromMnemonic( -// // mnemonic: TEST_MNEMONIC, -// // maxUnusedAddressGap: 2, -// // maxNumberOfIndexesToCheck: 1000, -// // height: 4000); -// // -// // when(client?.getBatchHistory(args: anyNamed("args"))) -// // .thenAnswer((_) async => {}); -// // when(client?.getBatchUTXOs(args: anyNamed("args"))) -// // .thenAnswer((_) async => emptyHistoryBatchResponse); -// // -// // await bch?.refresh(); -// // -// // verify(client?.getServerFeatures()).called(1); -// // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// // verify(client?.getBatchHistory(args: anyNamed("args"))).called(1); -// // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); -// // verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); -// // verify(client?.estimateFee(blocks: anyNamed("blocks"))).called(3); -// // verify(client?.getBlockHeadTip()).called(1); -// // // verify(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")).called(2); -// // -// // expect(secureStore?.interactions, 6); -// // expect(secureStore?.writes, 2); -// // expect(secureStore?.reads, 2); -// // expect(secureStore?.deletes, 0); -// // -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// }); -// -// tearDown(() async { -// await tearDownTestHive(); -// }); -// } +import 'package:bitcoindart/bitcoindart.dart'; +import 'package:decimal/decimal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:hive/hive.dart'; +import 'package:hive_test/hive_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; +import 'package:stackwallet/electrumx_rpc/electrumx.dart'; +import 'package:stackwallet/hive/db.dart'; +import 'package:stackwallet/models/paymint/fee_object_model.dart'; +import 'package:stackwallet/models/paymint/transactions_model.dart'; +import 'package:stackwallet/models/paymint/utxo_model.dart'; +import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'; +import 'package:stackwallet/services/price.dart'; +import 'package:stackwallet/services/transaction_notification_tracker.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; + +import 'bitcoincash_history_sample_data.dart'; +import 'bitcoincash_wallet_test.mocks.dart'; +import 'bitcoincash_wallet_test_parameters.dart'; + +@GenerateMocks( + [ElectrumX, CachedElectrumX, PriceAPI, TransactionNotificationTracker]) +void main() { + group("bitcoincash constants", () { + test("bitcoincash minimum confirmations", () async { + expect(MINIMUM_CONFIRMATIONS, 3); + }); + test("bitcoincash dust limit", () async { + expect(DUST_LIMIT, 546); + }); + test("bitcoincash mainnet genesis block hash", () async { + expect(GENESIS_HASH_MAINNET, + "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); + }); + + test("bitcoincash testnet genesis block hash", () async { + expect(GENESIS_HASH_TESTNET, + "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); + }); + }); + + test("bitcoincash DerivePathType enum", () { + expect(DerivePathType.values.length, 2); + expect(DerivePathType.values.toString(), + "[DerivePathType.bip44, DerivePathType.bip49]"); + }); + + group("bip32 node/root", () { + test("getBip32Root", () { + final root = getBip32Root(TEST_MNEMONIC, bitcoincash); + expect(root.toWIF(), ROOT_WIF); + }); + + test("basic getBip32Node", () { + final node = + getBip32Node(0, 0, TEST_MNEMONIC, bitcoincash, DerivePathType.bip44); + expect(node.toWIF(), NODE_WIF_44); + }); + }); + + group("validate mainnet bitcoincash addresses", () { + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + BitcoinCashWallet? mainnetWallet; + + setUp(() { + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + mainnetWallet = BitcoinCashWallet( + walletId: "validateAddressMainNet", + walletName: "validateAddressMainNet", + coin: Coin.bitcoincash, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + test("valid mainnet legacy/p2pkh address type", () { + expect( + mainnetWallet?.addressType( + address: "1DP3PUePwMa5CoZwzjznVKhzdLsZftjcAT"), + DerivePathType.bip44); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("invalid base58 address type", () { + expect( + () => mainnetWallet?.addressType( + address: "mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), + throwsArgumentError); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("invalid bech32 address type", () { + expect( + () => mainnetWallet?.addressType( + address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"), + throwsArgumentError); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("address has no matching script", () { + expect( + () => mainnetWallet?.addressType( + address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"), + throwsArgumentError); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("invalid mainnet bitcoincash legacy/p2pkh address", () { + expect( + mainnetWallet?.validateAddress("mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), + true); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + }); + + group("testNetworkConnection", () { + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + BitcoinCashWallet? bch; + + setUp(() { + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + bch = BitcoinCashWallet( + walletId: "testNetworkConnection", + walletName: "testNetworkConnection", + coin: Coin.bitcoincash, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + test("attempted connection fails due to server error", () async { + when(client?.ping()).thenAnswer((_) async => false); + final bool? result = await bch?.testNetworkConnection(); + expect(result, false); + expect(secureStore?.interactions, 0); + verify(client?.ping()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("attempted connection fails due to exception", () async { + when(client?.ping()).thenThrow(Exception); + final bool? result = await bch?.testNetworkConnection(); + expect(result, false); + expect(secureStore?.interactions, 0); + verify(client?.ping()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("attempted connection test success", () async { + when(client?.ping()).thenAnswer((_) async => true); + final bool? result = await bch?.testNetworkConnection(); + expect(result, true); + expect(secureStore?.interactions, 0); + verify(client?.ping()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + }); + + group("basic getters, setters, and functions", () { + final bchcoin = Coin.bitcoincash; + final testWalletId = "BCHtestWalletID"; + final testWalletName = "BCHWallet"; + + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + BitcoinCashWallet? bch; + + setUp(() async { + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + test("get networkType main", () async { + expect(bch?.coin, bchcoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get networkType test", () async { + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + expect(bch?.coin, bchcoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get cryptoCurrency", () async { + expect(Coin.bitcoincash, Coin.bitcoincash); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get coinName", () async { + expect(Coin.bitcoincash, Coin.bitcoincash); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get coinTicker", () async { + expect(Coin.bitcoincash, Coin.bitcoincash); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get and set walletName", () async { + expect(Coin.bitcoincash, Coin.bitcoincash); + bch?.walletName = "new name"; + expect(bch?.walletName, "new name"); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("estimateTxFee", () async { + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1), 356); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 900), 356); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 999), 356); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1000), 356); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1001), 712); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712); + expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get fees succeeds", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.estimateFee(blocks: 1)) + .thenAnswer((realInvocation) async => Decimal.zero); + when(client?.estimateFee(blocks: 5)) + .thenAnswer((realInvocation) async => Decimal.one); + when(client?.estimateFee(blocks: 20)) + .thenAnswer((realInvocation) async => Decimal.ten); + + final fees = await bch?.fees; + expect(fees, isA()); + expect(fees?.slow, 1000000000); + expect(fees?.medium, 100000000); + expect(fees?.fast, 0); + + verify(client?.estimateFee(blocks: 1)).called(1); + verify(client?.estimateFee(blocks: 5)).called(1); + verify(client?.estimateFee(blocks: 20)).called(1); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get fees fails", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.estimateFee(blocks: 1)) + .thenAnswer((realInvocation) async => Decimal.zero); + when(client?.estimateFee(blocks: 5)) + .thenAnswer((realInvocation) async => Decimal.one); + when(client?.estimateFee(blocks: 20)) + .thenThrow(Exception("some exception")); + + bool didThrow = false; + try { + await bch?.fees; + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.estimateFee(blocks: 1)).called(1); + verify(client?.estimateFee(blocks: 5)).called(1); + verify(client?.estimateFee(blocks: 20)).called(1); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("get maxFee", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.estimateFee(blocks: 20)) + .thenAnswer((realInvocation) async => Decimal.zero); + when(client?.estimateFee(blocks: 5)) + .thenAnswer((realInvocation) async => Decimal.one); + when(client?.estimateFee(blocks: 1)) + .thenAnswer((realInvocation) async => Decimal.ten); + + final maxFee = await bch?.maxFee; + expect(maxFee, 1000000000); + + verify(client?.estimateFee(blocks: 1)).called(1); + verify(client?.estimateFee(blocks: 5)).called(1); + verify(client?.estimateFee(blocks: 20)).called(1); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + }); + + group("BCHWallet service class functions that depend on shared storage", () { + final bchcoin = Coin.bitcoincash; + final bchtestcoin = Coin.bitcoincashTestnet; + final testWalletId = "BCHtestWalletID"; + final testWalletName = "BCHWallet"; + + bool hiveAdaptersRegistered = false; + + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + BitcoinCashWallet? bch; + + setUp(() async { + await setUpTestHive(); + if (!hiveAdaptersRegistered) { + hiveAdaptersRegistered = true; + + // Registering Transaction Model Adapters + Hive.registerAdapter(TransactionDataAdapter()); + Hive.registerAdapter(TransactionChunkAdapter()); + Hive.registerAdapter(TransactionAdapter()); + Hive.registerAdapter(InputAdapter()); + Hive.registerAdapter(OutputAdapter()); + + // Registering Utxo Model Adapters + Hive.registerAdapter(UtxoDataAdapter()); + Hive.registerAdapter(UtxoObjectAdapter()); + Hive.registerAdapter(StatusAdapter()); + + final wallets = await Hive.openBox('wallets'); + await wallets.put('currentWalletName', testWalletName); + } + + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + // test("initializeWallet no network", () async { + // when(client?.ping()).thenAnswer((_) async => false); + // await Hive.openBox(testWalletId); + // await Hive.openBox(DB.boxNamePrefs); + // expect(bch?.initializeNew(), false); + // expect(secureStore?.interactions, 0); + // verify(client?.ping()).called(0); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // test("initializeExisting no network exception", () async { + // when(client?.ping()).thenThrow(Exception("Network connection failed")); + // // bch?.initializeNew(); + // expect(bch?.initializeExisting(), false); + // expect(secureStore?.interactions, 0); + // verify(client?.ping()).called(1); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + test("initializeNew mainnet throws bad network", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + expectLater(() => bch?.initializeNew(), throwsA(isA())) + .then((_) { + expect(secureStore?.interactions, 0); + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + }); + + test("initializeNew throws mnemonic overwrite exception", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + await secureStore?.write( + key: "${testWalletId}_mnemonic", value: "some mnemonic"); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + expectLater(() => bch?.initializeNew(), throwsA(isA())) + .then((_) { + expect(secureStore?.interactions, 2); + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + }); + + test("initializeExisting testnet throws bad network", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + expectLater(() => bch?.initializeNew(), throwsA(isA())) + .then((_) { + expect(secureStore?.interactions, 0); + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + }); + + // test("getCurrentNode", () async { + // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) + // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); + // when(client?.ping()).thenAnswer((_) async => true); + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_MAINNET, + // "hash_function": "sha256", + // "services": [] + // }); + // // await DebugService.instance.init(); + // expect(bch?.initializeExisting(), true); + // + // bool didThrow = false; + // try { + // await bch?.getCurrentNode(); + // } catch (_) { + // didThrow = true; + // } + // // expect no nodes on a fresh wallet unless set in db externally + // expect(didThrow, true); + // + // // set node + // final wallet = await Hive.openBox(testWalletId); + // await wallet.put("nodes", { + // "default": { + // "id": "some nodeID", + // "ipAddress": "some address", + // "port": "9000", + // "useSSL": true, + // } + // }); + // await wallet.put("activeNodeName", "default"); + // + // // try fetching again + // final node = await bch?.getCurrentNode(); + // expect(node.toString(), + // "ElectrumXNode: {address: some address, port: 9000, name: default, useSSL: true}"); + // + // verify(client?.ping()).called(1); + // verify(client?.getServerFeatures()).called(1); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // test("initializeWallet new main net wallet", () async { + // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) + // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); + // when(client?.ping()).thenAnswer((_) async => true); + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_MAINNET, + // "hash_function": "sha256", + // "services": [] + // }); + // expect(await bch?.initializeWallet(), true); + // + // final wallet = await Hive.openBox(testWalletId); + // + // expect(await wallet.get("addressBookEntries"), {}); + // expect(await wallet.get('notes'), null); + // expect(await wallet.get("id"), testWalletId); + // expect(await wallet.get("preferredFiatCurrency"), null); + // expect(await wallet.get("blocked_tx_hashes"), ["0xdefault"]); + // + // final changeAddressesP2PKH = await wallet.get("changeAddressesP2PKH"); + // expect(changeAddressesP2PKH, isA>()); + // expect(changeAddressesP2PKH.length, 1); + // expect(await wallet.get("changeIndexP2PKH"), 0); + // + // final receivingAddressesP2PKH = + // await wallet.get("receivingAddressesP2PKH"); + // expect(receivingAddressesP2PKH, isA>()); + // expect(receivingAddressesP2PKH.length, 1); + // expect(await wallet.get("receivingIndexP2PKH"), 0); + // + // final p2pkhReceiveDerivations = jsonDecode(await secureStore?.read( + // key: "${testWalletId}_receiveDerivationsP2PKH")); + // expect(p2pkhReceiveDerivations.length, 1); + // + // final p2pkhChangeDerivations = jsonDecode(await secureStore.read( + // key: "${testWalletId}_changeDerivationsP2PKH")); + // expect(p2pkhChangeDerivations.length, 1); + // + // expect(secureStore?.interactions, 10); + // expect(secureStore?.reads, 7); + // expect(secureStore?.writes, 3); + // expect(secureStore?.deletes, 0); + // verify(client?.ping()).called(1); + // verify(client?.getServerFeatures()).called(1); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // // test("initializeWallet existing main net wallet", () async { + // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) + // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); + // // when(client?.ping()).thenAnswer((_) async => true); + // // when(client?.getBatchHistory(args: anyNamed("args"))) + // // .thenAnswer((_) async => {}); + // // when(client?.getServerFeatures()).thenAnswer((_) async => { + // // "hosts": {}, + // // "pruning": null, + // // "server_version": "Unit tests", + // // "protocol_min": "1.4", + // // "protocol_max": "1.4.2", + // // "genesis_hash": GENESIS_HASH_MAINNET, + // // "hash_function": "sha256", + // // "services": [] + // // }); + // // // init new wallet + // // expect(bch?.initializeNew(), true); + // // + // // // fetch data to compare later + // // final newWallet = await Hive.openBox(testWalletId); + // // + // // final addressBookEntries = await newWallet.get("addressBookEntries"); + // // final notes = await newWallet.get('notes'); + // // final wID = await newWallet.get("id"); + // // final currency = await newWallet.get("preferredFiatCurrency"); + // // final blockedHashes = await newWallet.get("blocked_tx_hashes"); + // // + // // final changeAddressesP2PKH = await newWallet.get("changeAddressesP2PKH"); + // // final changeIndexP2PKH = await newWallet.get("changeIndexP2PKH"); + // // + // // final receivingAddressesP2PKH = + // // await newWallet.get("receivingAddressesP2PKH"); + // // final receivingIndexP2PKH = await newWallet.get("receivingIndexP2PKH"); + // // + // // final p2pkhReceiveDerivations = jsonDecode(await secureStore?.read( + // // key: "${testWalletId}_receiveDerivationsP2PKH")); + // // + // // final p2pkhChangeDerivations = jsonDecode(await secureStore?.read( + // // key: "${testWalletId}_changeDerivationsP2PKH")); + // // + // // // exit new wallet + // // await bch?.exit(); + // // + // // // open existing/created wallet + // // bch = BitcoinCashWallet( + // // walletId: testWalletId, + // // walletName: testWalletName, + // // coin: dtestcoin, + // // client: client!, + // // cachedClient: cachedClient!, + // // priceAPI: priceAPI, + // // secureStore: secureStore, + // // ); + // // + // // // init existing + // // expect(bch?.initializeExisting(), true); + // // + // // // compare data to ensure state matches state of previously closed wallet + // // final wallet = await Hive.openBox(testWalletId); + // // + // // expect(await wallet.get("addressBookEntries"), addressBookEntries); + // // expect(await wallet.get('notes'), notes); + // // expect(await wallet.get("id"), wID); + // // expect(await wallet.get("preferredFiatCurrency"), currency); + // // expect(await wallet.get("blocked_tx_hashes"), blockedHashes); + // // + // // expect(await wallet.get("changeAddressesP2PKH"), changeAddressesP2PKH); + // // expect(await wallet.get("changeIndexP2PKH"), changeIndexP2PKH); + // // + // // expect( + // // await wallet.get("receivingAddressesP2PKH"), receivingAddressesP2PKH); + // // expect(await wallet.get("receivingIndexP2PKH"), receivingIndexP2PKH); + // // + // // expect( + // // jsonDecode(await secureStore?.read( + // // key: "${testWalletId}_receiveDerivationsP2PKH")), + // // p2pkhReceiveDerivations); + // // + // // expect( + // // jsonDecode(await secureStore?.read( + // // key: "${testWalletId}_changeDerivationsP2PKH")), + // // p2pkhChangeDerivations); + // // + // // expect(secureStore?.interactions, 12); + // // expect(secureStore?.reads, 9); + // // expect(secureStore?.writes, 3); + // // expect(secureStore?.deletes, 0); + // // verify(client?.ping()).called(2); + // // verify(client?.getServerFeatures()).called(1); + // // verifyNoMoreInteractions(client); + // // verifyNoMoreInteractions(cachedClient); + // // verifyNoMoreInteractions(priceAPI); + // // }); + + test("get current receiving addresses", () async { + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchtestcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + expect( + Address.validateAddress( + await bch!.currentReceivingAddress, bitcoincashtestnet), + true); + expect( + Address.validateAddress( + await bch!.currentReceivingAddress, bitcoincashtestnet), + true); + expect( + Address.validateAddress( + await bch!.currentReceivingAddress, bitcoincashtestnet), + true); + + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get allOwnAddresses", () async { + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchtestcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + final addresses = await bch?.allOwnAddresses; + expect(addresses, isA>()); + expect(addresses?.length, 2); + + for (int i = 0; i < 2; i++) { + expect( + Address.validateAddress(addresses![i], bitcoincashtestnet), true); + } + + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + // test("get utxos and balances", () async { + // bch = BitcoinCashWallet( + // walletId: testWalletId, + // walletName: testWalletName, + // coin: dtestcoin, + // client: client!, + // cachedClient: cachedClient!, + // tracker: tracker!, + // priceAPI: priceAPI, + // secureStore: secureStore, + // ); + // when(client?.ping()).thenAnswer((_) async => true); + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_TESTNET, + // "hash_function": "sha256", + // "services": [] + // }); + // + // await Hive.openBox(testWalletId); + // await Hive.openBox(DB.boxNamePrefs); + // + // when(client?.getBatchUTXOs(args: anyNamed("args"))) + // .thenAnswer((_) async => batchGetUTXOResponse0); + // + // when(client?.estimateFee(blocks: 20)) + // .thenAnswer((realInvocation) async => Decimal.zero); + // when(client?.estimateFee(blocks: 5)) + // .thenAnswer((realInvocation) async => Decimal.one); + // when(client?.estimateFee(blocks: 1)) + // .thenAnswer((realInvocation) async => Decimal.ten); + // + // when(cachedClient?.getTransaction( + // txHash: tx1.txid, + // coin: Coin.bitcoincashTestNet, + // )).thenAnswer((_) async => tx1Raw); + // when(cachedClient?.getTransaction( + // txHash: tx2.txid, + // coin: Coin.bitcoincashTestNet, + // )).thenAnswer((_) async => tx2Raw); + // when(cachedClient?.getTransaction( + // txHash: tx3.txid, + // coin: Coin.bitcoincashTestNet, + // )).thenAnswer((_) async => tx3Raw); + // when(cachedClient?.getTransaction( + // txHash: tx4.txid, + // coin: Coin.bitcoincashTestNet, + // )).thenAnswer((_) async => tx4Raw); + // + // await bch?.initializeNew(); + // await bch?.initializeExisting(); + // + // final utxoData = await bch?.utxoData; + // expect(utxoData, isA()); + // expect(utxoData.toString(), + // r"{totalUserCurrency: $103.2173, satoshiBalance: 1032173000, bitcoinBalance: null, unspentOutputArray: [{txid: 86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a, vout: 0, value: 800000000, fiat: $80, blocked: false, status: {confirmed: true, blockHash: e52cabb4445eb9ceb3f4f8d68cc64b1ede8884ce560296c27826a48ecc477370, blockHeight: 4274457, blockTime: 1655755742, confirmations: 100}}, {txid: a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469, vout: 0, value: 72173000, fiat: $7.2173, blocked: false, status: {confirmed: false, blockHash: bd239f922b3ecec299a90e4d1ce389334e8df4b95470fb5919966b0b650bb95b, blockHeight: 4270459, blockTime: 1655500912, confirmations: 0}}, {txid: 68c159dcc2f962cbc61f7dd3c8d0dcc14da8adb443811107115531c853fc0c60, vout: 1, value: 100000000, fiat: $10, blocked: false, status: {confirmed: false, blockHash: 9fee9b9446cfe81abb1a17bec56e6c160d9a6527e5b68b1141a827573bc2649f, blockHeight: 4255659, blockTime: 1654553247, confirmations: 0}}, {txid: 628a78606058ce4036aee3907e042742156c1894d34419578de5671b53ea5800, vout: 0, value: 60000000, fiat: $6, blocked: false, status: {confirmed: true, blockHash: bc461ab43e3a80d9a4d856ee9ff70f41d86b239d5f0581ffd6a5c572889a6b86, blockHeight: 4270352, blockTime: 1652888705, confirmations: 100}}]}"); + // + // final outputs = await bch?.unspentOutputs; + // expect(outputs, isA>()); + // expect(outputs?.length, 4); + // + // final availableBalance = await bch?.availableBalance; + // expect(availableBalance, Decimal.parse("8.6")); + // + // final totalBalance = await bch?.totalBalance; + // expect(totalBalance, Decimal.parse("10.32173")); + // + // final pendingBalance = await bch?.pendingBalance; + // expect(pendingBalance, Decimal.parse("1.72173")); + // + // final balanceMinusMaxFee = await bch?.balanceMinusMaxFee; + // expect(balanceMinusMaxFee, Decimal.parse("7.6")); + // + // verify(client?.ping()).called(1); + // verify(client?.getServerFeatures()).called(1); + // verify(client?.estimateFee(blocks: 1)).called(1); + // verify(client?.estimateFee(blocks: 5)).called(1); + // verify(client?.estimateFee(blocks: 20)).called(1); + // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); + // verify(cachedClient?.getTransaction( + // txHash: tx1.txid, + // coin: Coin.bitcoincashTestNet, + // )).called(1); + // verify(cachedClient?.getTransaction( + // txHash: tx2.txid, + // coin: Coin.bitcoincashTestNet, + // )).called(1); + // verify(cachedClient?.getTransaction( + // txHash: tx3.txid, + // coin: Coin.bitcoincashTestNet, + // )).called(1); + // verify(cachedClient?.getTransaction( + // txHash: tx4.txid, + // coin: Coin.bitcoincashTestNet, + // )).called(1); + // + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + // + // // test("get utxos - multiple batches", () async { + // // bch = BitcoinCashWallet( + // // walletId: testWalletId, + // // walletName: testWalletName, + // // coin: dtestcoin, + // // client: client!, + // // cachedClient: cachedClient!, + // // priceAPI: priceAPI, + // // secureStore: secureStore, + // // ); + // // when(client?.ping()).thenAnswer((_) async => true); + // // when(client?.getServerFeatures()).thenAnswer((_) async => { + // // "hosts": {}, + // // "pruning": null, + // // "server_version": "Unit tests", + // // "protocol_min": "1.4", + // // "protocol_max": "1.4.2", + // // "genesis_hash": GENESIS_HASH_TESTNET, + // // "hash_function": "sha256", + // // "services": [] + // // }); + // // + // // when(client?.getBatchUTXOs(args: anyNamed("args"))) + // // .thenAnswer((_) async => {}); + // // + // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) + // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); + // // + // // await bch?.initializeWallet(); + // // + // // // add some extra addresses to make sure we have more than the single batch size of 10 + // // final wallet = await Hive.openBox(testWalletId); + // // final addresses = await wallet.get("receivingAddressesP2PKH"); + // // addresses.add("DQaAi9R58GXMpDyhePys6hHCuif4fhc1sN"); + // // addresses.add("DBVhuF8QgeuxU2pssxzMgJqPhGCx5qyVkD"); + // // addresses.add("DCAokB2CXXPWC2JPj6jrK6hxANwTF2m21x"); + // // addresses.add("D6Y9brE3jUGPrqLmSEWh6yQdgY5b7ZkTib"); + // // addresses.add("DKdtobt3M5b3kQWZf1zRUZn3Ys6JTQwbPL"); + // // addresses.add("DBYiFr1BRc2zB19p8jxdSu6DvFGTdWvkVF"); + // // addresses.add("DE5ffowvbHPzzY6aRVGpzxR2QqikXxUKPG"); + // // addresses.add("DA97TLg1741J2aLK6z9bVZoWysgQbMR45K"); + // // addresses.add("DGGmf9q4PKcJXauPRstsFetu9DjW1VSBYk"); + // // addresses.add("D9bXqnTtufcb6oJyuZniCXbst8MMLzHxUd"); + // // addresses.add("DA6nv8M4kYL4RxxKrcsPaPUA1KrFA7CTfN"); + // // await wallet.put("receivingAddressesP2PKH", addresses); + // // + // // final utxoData = await bch?.utxoData; + // // expect(utxoData, isA()); + // // + // // final outputs = await bch?.unspentOutputs; + // // expect(outputs, isA>()); + // // expect(outputs?.length, 0); + // // + // // verify(client?.ping()).called(1); + // // verify(client?.getServerFeatures()).called(1); + // // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(2); + // // verify(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")).called(1); + // // + // // verifyNoMoreInteractions(client); + // // verifyNoMoreInteractions(cachedClient); + // // verifyNoMoreInteractions(priceAPI); + // // }); + // + test("get utxos fails", () async { + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchtestcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + when(client?.getBatchUTXOs(args: anyNamed("args"))) + .thenThrow(Exception("some exception")); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + + final utxoData = await bch?.utxoData; + expect(utxoData, isA()); + expect(utxoData.toString(), + r"{totalUserCurrency: 0.00, satoshiBalance: 0, bitcoinBalance: 0, unspentOutputArray: []}"); + + final outputs = await bch?.unspentOutputs; + expect(outputs, isA>()); + expect(outputs?.length, 0); + + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("chain height fetch, update, and get", () async { + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: bchtestcoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + + // get stored + expect(await bch?.storedChainHeight, 0); + + // fetch fails + when(client?.getBlockHeadTip()).thenThrow(Exception("Some exception")); + expect(await bch?.chainHeight, -1); + + // fetch succeeds + when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => { + "height": 100, + "hex": "some block hex", + }); + expect(await bch?.chainHeight, 100); + + // update + await bch?.updateStoredChainHeight(newHeight: 1000); + + // fetch updated + expect(await bch?.storedChainHeight, 1000); + + verifyNever(client?.ping()).called(0); + verify(client?.getServerFeatures()).called(1); + verify(client?.getBlockHeadTip()).called(2); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("getTxCount succeeds", () async { + when(client?.getHistory( + scripthash: + "1df1cab6d109d506aa424b00b6a013c5e1947dc13b78d62b4d0e9f518b3035d1")) + .thenAnswer((realInvocation) async => [ + { + "height": 757727, + "tx_hash": + "aaac451c49c2e3bcbccb8a9fded22257eeb94c1702b456171aa79250bc1b20e0" + }, + { + "height": 0, + "tx_hash": + "9ac29f35b72ca596bc45362d1f9556b0555e1fb633ca5ac9147a7fd467700afe" + } + ]); + + final count = + await bch?.getTxCount(address: "1MMi672ueYFXLLdtZqPe4FsrS46gNDyRq1"); + + expect(count, 2); + + verify(client?.getHistory( + scripthash: + "1df1cab6d109d506aa424b00b6a013c5e1947dc13b78d62b4d0e9f518b3035d1")) + .called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + //TODO - Needs refactoring + test("getTxCount fails", () async { + when(client?.getHistory( + scripthash: + "64953f7db441a21172de206bf70b920c8c718ed4f03df9a85073c0400be0053c")) + .thenThrow(Exception("some exception")); + + bool didThrow = false; + try { + await bch?.getTxCount(address: "D6biRASajCy7GcJ8R6ZP4RE94fNRerJLCC"); + } catch (_) { + didThrow = true; + } + expect(didThrow, true); + + verifyNever(client?.getHistory( + scripthash: + "64953f7db441a21172de206bf70b920c8c718ed4f03df9a85073c0400be0053c")) + .called(0); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("_checkCurrentReceivingAddressesForTransactions succeeds", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getHistory(scripthash: anyNamed("scripthash"))) + .thenAnswer((realInvocation) async => [ + { + "height": 4270385, + "tx_hash": + "c07f740ad72c0dd759741f4c9ab4b1586a22bc16545584364ac9b3d845766271" + }, + { + "height": 4270459, + "tx_hash": + "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a" + } + ]); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + + bool didThrow = false; + try { + await bch?.checkCurrentReceivingAddressesForTransactions(); + } catch (_) { + didThrow = true; + } + expect(didThrow, false); + + verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); + verify(client?.getServerFeatures()).called(1); + verifyNever(client?.ping()).called(0); + + expect(secureStore?.interactions, 20); + expect(secureStore?.reads, 13); + expect(secureStore?.writes, 7); + expect(secureStore?.deletes, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("_checkCurrentReceivingAddressesForTransactions fails", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getHistory(scripthash: anyNamed("scripthash"))) + .thenThrow(Exception("some exception")); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + + bool didThrow = false; + try { + await bch?.checkCurrentReceivingAddressesForTransactions(); + } catch (_) { + didThrow = true; + } + expect(didThrow, true); + + verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); + verify(client?.getServerFeatures()).called(1); + verifyNever(client?.ping()).called(0); + + expect(secureStore?.interactions, 14); + expect(secureStore?.reads, 9); + expect(secureStore?.writes, 5); + expect(secureStore?.deletes, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("_checkCurrentChangeAddressesForTransactions succeeds", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getHistory(scripthash: anyNamed("scripthash"))) + .thenAnswer((realInvocation) async => [ + { + "height": 4286283, + "tx_hash": + "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b" + }, + { + "height": 4286295, + "tx_hash": + "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a" + } + ]); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + + bool didThrow = false; + try { + await bch?.checkCurrentChangeAddressesForTransactions(); + } catch (_) { + didThrow = true; + } + expect(didThrow, false); + + verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); + verify(client?.getServerFeatures()).called(1); + verifyNever(client?.ping()).called(0); + + expect(secureStore?.interactions, 20); + expect(secureStore?.reads, 13); + expect(secureStore?.writes, 7); + expect(secureStore?.deletes, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("_checkCurrentChangeAddressesForTransactions fails", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getHistory(scripthash: anyNamed("scripthash"))) + .thenThrow(Exception("some exception")); + + await Hive.openBox(testWalletId); + await Hive.openBox(DB.boxNamePrefs); + + await bch?.initializeNew(); + await bch?.initializeExisting(); + + bool didThrow = false; + try { + await bch?.checkCurrentChangeAddressesForTransactions(); + } catch (_) { + didThrow = true; + } + expect(didThrow, true); + + verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); + verify(client?.getServerFeatures()).called(1); + verifyNever(client?.ping()).called(0); + + expect(secureStore?.interactions, 14); + expect(secureStore?.reads, 9); + expect(secureStore?.writes, 5); + expect(secureStore?.deletes, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + // test("getAllTxsToWatch", () async { + // TestWidgetsFlutterBinding.ensureInitialized(); + // var notifications = {"show": 0}; + // const MethodChannel('dexterous.com/flutter/local_notifications') + // .setMockMethodCallHandler((call) async { + // notifications[call.method]++; + // }); + // + // bch?.pastUnconfirmedTxs = { + // "88b7b5077d940dde1bc63eba37a09dec8e7b9dad14c183a2e879a21b6ec0ac1c", + // "b39bac02b65af46a49e2985278fe24ca00dd5d627395d88f53e35568a04e10fa", + // }; + // + // await bch?.getAllTxsToWatch(transactionData); + // expect(notifications.length, 1); + // expect(notifications["show"], 3); + // + // expect(bch?.unconfirmedTxs, { + // "b2f75a017a7435f1b8c2e080a865275d8f80699bba68d8dce99a94606e7b3528", + // 'dcca229760b44834478f0b266c9b3f5801e0139fdecacdc0820e447289a006d3', + // }); + // + // expect(secureStore?.interactions, 0); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + // + // test("refreshIfThereIsNewData true A", () async { + // when(client?.getTransaction( + // txHash: + // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", + // )).thenAnswer((_) async => tx2Raw); + // when(client?.getTransaction( + // txHash: + // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a", + // )).thenAnswer((_) async => tx1Raw); + // + // bch = BitcoinCashWallet( + // walletId: testWalletId, + // walletName: testWalletName, + // coin: dtestcoin, + // client: client!, + // cachedClient: cachedClient!, + // priceAPI: priceAPI, + // secureStore: secureStore, + // ); + // final wallet = await Hive.openBox(testWalletId); + // await wallet.put('receivingAddressesP2PKH', []); + // + // await wallet.put('changeAddressesP2PKH', []); + // + // bch?.unconfirmedTxs = { + // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", + // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a" + // }; + // + // final result = await bch?.refreshIfThereIsNewData(); + // + // expect(result, true); + // + // verify(client?.getTransaction( + // txHash: + // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", + // )).called(1); + // verify(client?.getTransaction( + // txHash: + // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a", + // )).called(1); + // + // expect(secureStore?.interactions, 0); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + // + // test("refreshIfThereIsNewData true B", () async { + // // when(priceAPI.getbitcoincashPrice(baseCurrency: "USD")) + // // .thenAnswer((_) async => Decimal.fromInt(10)); + // + // when(client?.getBatchHistory(args: anyNamed("args"))) + // .thenAnswer((realInvocation) async { + // final uuids = Map>.from(realInvocation + // .namedArguments.values.first as Map) + // .keys + // .toList(growable: false); + // return { + // uuids[0]: [ + // { + // "tx_hash": + // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", + // "height": 4286305 + // }, + // { + // "tx_hash": + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // "height": 4286295 + // } + // ], + // uuids[1]: [ + // { + // "tx_hash": + // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", + // "height": 4286283 + // } + // ], + // }; + // }); + // + // when(client?.getTransaction( + // txHash: + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // )).thenAnswer((_) async => tx2Raw); + // when(client?.getTransaction( + // txHash: + // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", + // )).thenAnswer((_) async => tx1Raw); + // + // when(cachedClient?.getTransaction( + // txHash: + // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx3Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx3Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx1Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "4493caff0e1b4f248e3c6219e7f288cfdb46c32b72a77aec469098c5f7f5154e", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx5Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "e095cbe5531d174c3fc5c9c39a0e6ba2769489cdabdc17b35b2e3a33a3c2fc61", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx6Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx7Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "7b34e60cc37306f866667deb67b14096f4ea2add941fd6e2238a639000642b82", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx4Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "a70c6f0690fa84712dc6b3d20ee13862fe015a08cf2dc8949c4300d49c3bdeb5", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx8Raw); + // + // bch = BitcoinCashWallet( + // walletId: testWalletId, + // walletName: testWalletName, + // coin: dtestcoin, + // client: client!, + // cachedClient: cachedClient!, + // priceAPI: priceAPI, + // secureStore: secureStore, + // ); + // final wallet = await Hive.openBox(testWalletId); + // await wallet.put('receivingAddressesP2PKH', []); + // + // await wallet.put('changeAddressesP2PKH', []); + // + // bch?.unconfirmedTxs = { + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // }; + // + // final result = await bch?.refreshIfThereIsNewData(); + // + // expect(result, true); + // + // verify(client?.getBatchHistory(args: anyNamed("args"))).called(2); + // verify(client?.getTransaction( + // txHash: + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // )).called(1); + // verify(cachedClient?.getTransaction( + // txHash: anyNamed("tx_hash"), + // verbose: true, + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .called(9); + // // verify(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")).called(1); + // + // expect(secureStore?.interactions, 0); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // test("refreshIfThereIsNewData false A", () async { + // // when(priceAPI.getbitcoincashPrice(baseCurrency: "USD")) + // // .thenAnswer((_) async => Decimal.fromInt(10)); + // + // when(client?.getBatchHistory(args: anyNamed("args"))) + // .thenAnswer((realInvocation) async { + // final uuids = Map>.from(realInvocation + // .namedArguments.values.first as Map) + // .keys + // .toList(growable: false); + // return { + // uuids[0]: [ + // { + // "tx_hash": + // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", + // "height": 4286305 + // }, + // { + // "tx_hash": + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // "height": 4286295 + // } + // ], + // uuids[1]: [ + // { + // "tx_hash": + // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", + // "height": 4286283 + // } + // ], + // }; + // }); + // + // when(client?.getTransaction( + // txHash: + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // )).thenAnswer((_) async => tx2Raw); + // when(client?.getTransaction( + // txHash: + // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", + // )).thenAnswer((_) async => tx1Raw); + // + // when(cachedClient?.getTransaction( + // txHash: + // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx1Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx2Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx3Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "4493caff0e1b4f248e3c6219e7f288cfdb46c32b72a77aec469098c5f7f5154e", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx5Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "7b34e60cc37306f866667deb67b14096f4ea2add941fd6e2238a639000642b82", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx4Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "e095cbe5531d174c3fc5c9c39a0e6ba2769489cdabdc17b35b2e3a33a3c2fc61", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx6Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx7Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "a70c6f0690fa84712dc6b3d20ee13862fe015a08cf2dc8949c4300d49c3bdeb5", + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx8Raw); + // + // bch = BitcoinCashWallet( + // walletId: testWalletId, + // walletName: testWalletName, + // coin: dtestcoin, + // client: client!, + // cachedClient: cachedClient!, + // tracker: tracker!, + // priceAPI: priceAPI, + // secureStore: secureStore, + // ); + // final wallet = await Hive.openBox(testWalletId); + // await wallet.put('receivingAddressesP2PKH', []); + // + // await wallet.put('changeAddressesP2PKH', []); + // + // bch?.unconfirmedTxs = { + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9" + // }; + // + // final result = await bch?.refreshIfThereIsNewData(); + // + // expect(result, false); + // + // verify(client?.getBatchHistory(args: anyNamed("args"))).called(2); + // verify(client?.getTransaction( + // txHash: + // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // )).called(1); + // verify(cachedClient?.getTransaction( + // txHash: anyNamed("tx_hash"), + // verbose: true, + // coin: Coin.bitcoincashTestNet, + // callOutSideMainIsolate: false)) + // .called(15); + // // verify(priceAPI.getbitcoincashPrice(baseCurrency: "USD")).called(1); + // + // expect(secureStore?.interactions, 0); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // // test("refreshIfThereIsNewData false B", () async { + // // when(client?.getBatchHistory(args: anyNamed("args"))) + // // .thenThrow(Exception("some exception")); + // // + // // when(client?.getTransaction( + // // txHash: + // // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // // )).thenAnswer((_) async => tx2Raw); + // // + // // bch = BitcoinCashWallet( + // // walletId: testWalletId, + // // walletName: testWalletName, + // // coin: dtestcoin, + // // client: client!, + // // cachedClient: cachedClient!, + // // tracker: tracker!, + // // priceAPI: priceAPI, + // // secureStore: secureStore, + // // ); + // // final wallet = await Hive.openBox(testWalletId); + // // await wallet.put('receivingAddressesP2PKH', []); + // // + // // await wallet.put('changeAddressesP2PKH', []); + // // + // // bch?.unconfirmedTxs = { + // // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", + // // }; + // // + // // final result = await bch?.refreshIfThereIsNewData(); + // // + // // expect(result, false); + // // + // // verify(client?.getBatchHistory(args: anyNamed("args"))).called(1); + // // verify(client?.getTransaction( + // // txHash: + // // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", + // // )).called(1); + // // + // // expect(secureStore?.interactions, 0); + // // verifyNoMoreInteractions(client); + // // verifyNoMoreInteractions(cachedClient); + // // verifyNoMoreInteractions(priceAPI); + // // }); + + test("get mnemonic list", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + + // when(client?.getBatchHistory(args: anyNamed("args"))) + // .thenAnswer((thing) async { + // print(jsonEncode(thing.namedArguments.entries.first.value)); + // return {}; + // }); + + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + + final wallet = await Hive.openBox(testWalletId); + + // add maxNumberOfIndexesToCheck and height + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + expect(await bch?.mnemonic, TEST_MNEMONIC.split(" ")); + // + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test( + "recoverFromMnemonic using empty seed on mainnet fails due to bad genesis hash match", + () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + bool hasThrown = false; + try { + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + verify(client?.getServerFeatures()).called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test( + "recoverFromMnemonic using empty seed on testnet fails due to bad genesis hash match", + () async { + bch = BitcoinCashWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: Coin.bitcoincashTestnet, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + + bool hasThrown = false; + try { + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + verify(client?.getServerFeatures()).called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test( + "recoverFromMnemonic using empty seed on mainnet fails due to attempted overwrite of mnemonic", + () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + + await secureStore?.write( + key: "${testWalletId}_mnemonic", value: "some mnemonic words"); + + bool hasThrown = false; + try { + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + verify(client?.getServerFeatures()).called(1); + + expect(secureStore?.interactions, 2); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("recoverFromMnemonic using non empty seed on mainnet succeeds", + () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + + List dynamicArgValues = []; + + when(client?.getBatchHistory(args: anyNamed("args"))) + .thenAnswer((realInvocation) async { + if (realInvocation.namedArguments.values.first.length == 1) { + dynamicArgValues.add(realInvocation.namedArguments.values.first); + } + + return historyBatchResponse; + }); + + // final wallet = await Hive.openBox(testWalletId); + await Hive.openBox(testWalletId); + + bool hasThrown = false; + try { + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, false); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + + for (final arg in dynamicArgValues) { + final map = Map>.from(arg as Map); + + verify(client?.getBatchHistory(args: map)).called(1); + expect(activeScriptHashes.contains(map.values.first.first as String), + true); + } + + expect(secureStore?.interactions, 10); + expect(secureStore?.writes, 5); + expect(secureStore?.reads, 5); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("fullRescan succeeds", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) + .thenAnswer((realInvocation) async {}); + + when(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).thenAnswer((_) async => {"0": []}); + + final wallet = await Hive.openBox(testWalletId); + + // restore so we have something to rescan + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + // fetch valid wallet data + final preReceivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + + final preReceivingAddressesP2SH = + await wallet.get('receivingAddressesP2SH'); + final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); + final preReceivingIndexP2SH = await wallet.get('receivingIndexP2PKH'); + final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); + + final preUtxoData = await wallet.get('latest_utxo_model'); + final preReceiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final preChangeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + + final preReceiveDerivationsStringP2SH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2SH"); + final preChangeDerivationsStringP2SH = + await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); + + // destroy the data that the rescan will fix + await wallet.put( + 'receivingAddressesP2PKH', ["some address", "some other address"]); + await wallet + .put('changeAddressesP2PKH', ["some address", "some other address"]); + + await wallet.put( + 'receivingAddressesP2SH', ["some address", "some other address"]); + await wallet + .put('changeAddressesP2SH', ["some address", "some other address"]); + + await wallet.put('receivingIndexP2PKH', 123); + await wallet.put('changeIndexP2PKH', 123); + + await wallet.put('receivingIndexP2SH', 123); + await wallet.put('changeIndexP2SH', 123); + + await secureStore?.write( + key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_changeDerivationsP2PKH", value: "{}"); + + await secureStore?.write( + key: "${testWalletId}_receiveDerivationsP2SH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_changeDerivationsP2SH", value: "{}"); + + bool hasThrown = false; + try { + await bch?.fullRescan(2, 1000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, false); + + // fetch wallet data again + final receivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + + final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); + final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); + final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); + final changeIndexP2SH = await wallet.get('changeIndexP2SH'); + + final utxoData = await wallet.get('latest_utxo_model'); + final receiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final changeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + + final receiveDerivationsStringP2SH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2SH"); + final changeDerivationsStringP2SH = + await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); + + expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); + expect(preChangeAddressesP2PKH, changeAddressesP2PKH); + expect(preReceivingIndexP2PKH, receivingIndexP2PKH); + expect(preChangeIndexP2PKH, changeIndexP2PKH); + + expect(preReceivingAddressesP2SH, receivingAddressesP2SH); + expect(preChangeAddressesP2SH, changeAddressesP2SH); + expect(preReceivingIndexP2SH, receivingIndexP2SH); + expect(preChangeIndexP2SH, changeIndexP2SH); + + expect(preUtxoData, utxoData); + + expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); + expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); + + expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); + expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); + verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) + .called(1); + + verify(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).called(2); + + expect(secureStore?.writes, 17); + expect(secureStore?.reads, 22); + expect(secureStore?.deletes, 4); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("fullRescan fails", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) + .thenAnswer((realInvocation) async {}); + + when(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).thenAnswer((_) async => {"0": []}); + + final wallet = await Hive.openBox(testWalletId); + + // restore so we have something to rescan + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + // fetch wallet data + final preReceivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + + final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + final preUtxoData = await wallet.get('latest_utxo_model'); + final preReceiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final preChangeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenThrow(Exception("fake exception")); + + bool hasThrown = false; + try { + await bch?.fullRescan(2, 1000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + // fetch wallet data again + final receivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + + final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + final utxoData = await wallet.get('latest_utxo_model'); + final receiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final changeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + + expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); + expect(preChangeAddressesP2PKH, changeAddressesP2PKH); + expect(preReceivingIndexP2PKH, receivingIndexP2PKH); + expect(preChangeIndexP2PKH, changeIndexP2PKH); + expect(preUtxoData, utxoData); + expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); + expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); + verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) + .called(1); + + verify(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).called(2); + + expect(secureStore?.writes, 13); + expect(secureStore?.reads, 18); + expect(secureStore?.deletes, 8); + }); + + // // test("fetchBuildTxData succeeds", () async { + // // when(client.getServerFeatures()).thenAnswer((_) async => { + // // "hosts": {}, + // // "pruning": null, + // // "server_version": "Unit tests", + // // "protocol_min": "1.4", + // // "protocol_max": "1.4.2", + // // "genesis_hash": GENESIS_HASH_MAINNET, + // // "hash_function": "sha256", + // // "services": [] + // // }); + // // when(client.getBatchHistory(args: historyBatchArgs0)) + // // .thenAnswer((_) async => historyBatchResponse); + // // when(client.getBatchHistory(args: historyBatchArgs1)) + // // .thenAnswer((_) async => historyBatchResponse); + // // when(cachedClient.getTransaction( + // // tx_hash: + // // "339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9", + // // coinName: "bitcoincash", + // // callOutSideMainIsolate: false)) + // // .thenAnswer((_) async => tx9Raw); + // // when(cachedClient.getTransaction( + // // tx_hash: + // // "c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e", + // // coinName: "bitcoincash", + // // callOutSideMainIsolate: false)) + // // .thenAnswer((_) async => tx10Raw); + // // when(cachedClient.getTransaction( + // // tx_hash: + // // "d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c", + // // coinName: "bitcoincash", + // // callOutSideMainIsolate: false)) + // // .thenAnswer((_) async => tx11Raw); + // // + // // // recover to fill data + // // await bch.recoverFromMnemonic( + // // mnemonic: TEST_MNEMONIC, + // // maxUnusedAddressGap: 2, + // // maxNumberOfIndexesToCheck: 1000, + // // height: 4000); + // // + // // // modify addresses to trigger all change code branches + // // final chg44 = + // // await secureStore.read(key: testWalletId + "_changeDerivationsP2PKH"); + // // await secureStore.write( + // // key: testWalletId + "_changeDerivationsP2PKH", + // // value: chg44.replaceFirst("1vFHF5q21GccoBwrB4zEUAs9i3Bfx797U", + // // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); + // // + // // final data = await bch.fetchBuildTxData(utxoList); + // // + // // expect(data.length, 3); + // // expect( + // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] + // // .length, + // // 2); + // // expect( + // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // .length, + // // 3); + // // expect( + // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] + // // .length, + // // 2); + // // expect( + // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] + // // ["output"], + // // isA()); + // // expect( + // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // ["output"], + // // isA()); + // // expect( + // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] + // // ["output"], + // // isA()); + // // expect( + // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] + // // ["keyPair"], + // // isA()); + // // expect( + // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // ["keyPair"], + // // isA()); + // // expect( + // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] + // // ["keyPair"], + // // isA()); + // // expect( + // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // ["redeemScript"], + // // isA()); + // // + // // // modify addresses to trigger all receiving code branches + // // final rcv44 = await secureStore.read( + // // key: testWalletId + "_receiveDerivationsP2PKH"); + // // await secureStore.write( + // // key: testWalletId + "_receiveDerivationsP2PKH", + // // value: rcv44.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", + // // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); + // // + // // final data2 = await bch.fetchBuildTxData(utxoList); + // // + // // expect(data2.length, 3); + // // expect( + // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] + // // .length, + // // 2); + // // expect( + // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // .length, + // // 3); + // // expect( + // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] + // // .length, + // // 2); + // // expect( + // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] + // // ["output"], + // // isA()); + // // expect( + // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // ["output"], + // // isA()); + // // expect( + // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] + // // ["output"], + // // isA()); + // // expect( + // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] + // // ["keyPair"], + // // isA()); + // // expect( + // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // ["keyPair"], + // // isA()); + // // expect( + // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] + // // ["keyPair"], + // // isA()); + // // expect( + // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] + // // ["redeemScript"], + // // isA()); + // // + // // verify(client.getServerFeatures()).called(1); + // // verify(cachedClient.getTransaction( + // // tx_hash: + // // "339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9", + // // coinName: "bitcoincash", + // // callOutSideMainIsolate: false)) + // // .called(2); + // // verify(cachedClient.getTransaction( + // // tx_hash: + // // "c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e", + // // coinName: "bitcoincash", + // // callOutSideMainIsolate: false)) + // // .called(2); + // // verify(cachedClient.getTransaction( + // // tx_hash: + // // "d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c", + // // coinName: "bitcoincash", + // // callOutSideMainIsolate: false)) + // // .called(2); + // // verify(client.getBatchHistory(args: historyBatchArgs0)).called(1); + // // verify(client.getBatchHistory(args: historyBatchArgs1)).called(1); + // // + // // expect(secureStore.interactions, 38); + // // expect(secureStore.writes, 13); + // // expect(secureStore.reads, 25); + // // expect(secureStore.deletes, 0); + // // + // // verifyNoMoreInteractions(client); + // // verifyNoMoreInteractions(cachedClient); + // // verifyNoMoreInteractions(priceAPI); + // // }); + + // test("fetchBuildTxData throws", () async { + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_MAINNET, + // "hash_function": "sha256", + // "services": [] + // }); + // when(client?.getBatchHistory(args: historyBatchArgs0)) + // .thenAnswer((_) async => historyBatchResponse); + // when(client?.getBatchHistory(args: historyBatchArgs1)) + // .thenAnswer((_) async => historyBatchResponse); + // when(cachedClient?.getTransaction( + // txHash: + // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx9Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx10Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .thenThrow(Exception("some exception")); + // + // // recover to fill data + // await bch?.recoverFromMnemonic( + // mnemonic: TEST_MNEMONIC, + // maxUnusedAddressGap: 2, + // maxNumberOfIndexesToCheck: 1000, + // height: 4000); + // + // bool didThrow = false; + // try { + // await bch?.fetchBuildTxData(utxoList); + // } catch (_) { + // didThrow = true; + // } + // expect(didThrow, true); + // + // verify(client?.getServerFeatures()).called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + // + // expect(secureStore?.interactions, 14); + // expect(secureStore?.writes, 7); + // expect(secureStore?.reads, 7); + // expect(secureStore?.deletes, 0); + // + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // test("build transaction succeeds", () async { + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_MAINNET, + // "hash_function": "sha256", + // "services": [] + // }); + // when(client?.getBatchHistory(args: historyBatchArgs0)) + // .thenAnswer((_) async => historyBatchResponse); + // when(client?.getBatchHistory(args: historyBatchArgs1)) + // .thenAnswer((_) async => historyBatchResponse); + // when(cachedClient?.getTransaction( + // txHash: + // "e9673acb3bfa928f92a7d5a545151a672e9613fdf972f3849e16094c1ed28268", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx9Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "fa5bfa4eb581bedb28ca96a65ee77d8e81159914b70d5b7e215994221cc02a63", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx10Raw); + // when(cachedClient?.getTransaction( + // txHash: + // "694617f0000499be2f6af5f8d1ddbcf1a70ad4710c0cee6f33a13a64bba454ed", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .thenAnswer((_) async => tx11Raw); + // + // // recover to fill data + // await bch?.recoverFromMnemonic( + // mnemonic: TEST_MNEMONIC, + // maxUnusedAddressGap: 2, + // maxNumberOfIndexesToCheck: 1000, + // height: 4000); + // + // // modify addresses to properly mock data to build a tx + // final rcv44 = await secureStore?.read( + // key: testWalletId + "_receiveDerivationsP2PKH"); + // await secureStore?.write( + // key: testWalletId + "_receiveDerivationsP2PKH", + // value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", + // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); + // + // final data = await bch?.fetchBuildTxData(utxoList); + // + // final txData = await bch?.buildTransaction( + // utxosToUse: utxoList, + // utxoSigningData: data!, + // recipients: ["DS7cKFKdfbarMrYjFBQqEcHR5km6D51c74"], + // satoshiAmounts: [13000]); + // + // expect(txData?.length, 2); + // expect(txData?["hex"], isA()); + // expect(txData?["vSize"], isA()); + // + // verify(client?.getServerFeatures()).called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "fa5bfa4eb581bedb28ca96a65ee77d8e81159914b70d5b7e215994221cc02a63", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "694617f0000499be2f6af5f8d1ddbcf1a70ad4710c0cee6f33a13a64bba454ed", + // coin: Coin.bitcoincash, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + // + // expect(secureStore?.interactions, 26); + // expect(secureStore?.writes, 10); + // expect(secureStore?.reads, 16); + // expect(secureStore?.deletes, 0); + // + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + test("confirmSend error 1", () async { + bool didThrow = false; + try { + await bch?.confirmSend(txData: 1); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend error 2", () async { + bool didThrow = false; + try { + await bch?.confirmSend(txData: 2); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend some other error code", () async { + bool didThrow = false; + try { + await bch?.confirmSend(txData: 42); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend no hex", () async { + bool didThrow = false; + try { + await bch?.confirmSend(txData: {"some": "strange map"}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend fails due to vSize being greater than fee", () async { + bool didThrow = false; + try { + await bch + ?.confirmSend(txData: {"hex": "a string", "fee": 1, "vSize": 10}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend fails when broadcast transactions throws", () async { + when(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .thenThrow(Exception("some exception")); + + bool didThrow = false; + try { + await bch + ?.confirmSend(txData: {"hex": "a string", "fee": 10, "vSize": 10}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("refresh wallet mutex locked", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + final wallet = await Hive.openBox(testWalletId); + // recover to fill data + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + bch?.refreshMutex = true; + + await bch?.refresh(); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + + verify(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).called(1); + + expect(secureStore?.interactions, 10); + expect(secureStore?.writes, 5); + expect(secureStore?.reads, 5); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("refresh wallet throws", () async { + when(client?.getBlockHeadTip()).thenThrow(Exception("some exception")); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + + when(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getHistory(scripthash: anyNamed("scripthash"))) + .thenThrow(Exception("some exception")); + + final wallet = await Hive.openBox(testWalletId); + + // recover to fill data + await bch?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + await bch?.refresh(); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + + verify(client?.getBatchHistory(args: { + "0": [ + "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "ff7f0d2a4b8e2805706ece77f4e672550fe4c505a150c781639814338eda1734" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "1c2336c32dc62f00862ee6a75643e01017c86edece10b5a9d7defbd5f66b0a80" + ] + })).called(1); + + verify(client?.getBlockHeadTip()).called(1); + verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); + + expect(secureStore?.interactions, 10); + expect(secureStore?.writes, 5); + expect(secureStore?.reads, 5); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + // test("refresh wallet normally", () async { + // when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => + // {"height": 520481, "hex": "some block hex"}); + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_MAINNET, + // "hash_function": "sha256", + // "services": [] + // }); + // when(client?.getBatchHistory(args: historyBatchArgs0)) + // .thenAnswer((_) async => historyBatchResponse); + // when(client?.getBatchHistory(args: historyBatchArgs1)) + // .thenAnswer((_) async => historyBatchResponse); + // when(client?.getHistory(scripthash: anyNamed("scripthash"))) + // .thenAnswer((_) async => []); + // when(client?.estimateFee(blocks: anyNamed("blocks"))) + // .thenAnswer((_) async => Decimal.one); + // // when(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")) + // // .thenAnswer((_) async => Decimal.one); + // + // await Hive.openBox(testWalletId); + // await Hive.openBox(DB.boxNamePrefs); + // + // // recover to fill data + // await bch?.recoverFromMnemonic( + // mnemonic: TEST_MNEMONIC, + // maxUnusedAddressGap: 2, + // maxNumberOfIndexesToCheck: 1000, + // height: 4000); + // + // when(client?.getBatchHistory(args: anyNamed("args"))) + // .thenAnswer((_) async => {}); + // when(client?.getBatchUTXOs(args: anyNamed("args"))) + // .thenAnswer((_) async => emptyHistoryBatchResponse); + // + // await bch?.refresh(); + // + // verify(client?.getServerFeatures()).called(1); + // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + // verify(client?.getBatchHistory(args: anyNamed("args"))).called(1); + // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); + // verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); + // verify(client?.estimateFee(blocks: anyNamed("blocks"))).called(3); + // verify(client?.getBlockHeadTip()).called(1); + // // verify(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")).called(2); + // + // expect(secureStore?.interactions, 6); + // expect(secureStore?.writes, 2); + // expect(secureStore?.reads, 2); + // expect(secureStore?.deletes, 0); + // + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + }); + + tearDown(() async { + await tearDownTestHive(); + }); +} diff --git a/test/services/coins/namecoin/namecoin_wallet_test.dart b/test/services/coins/namecoin/namecoin_wallet_test.dart index 50a82bd69..f6bc1b065 100644 --- a/test/services/coins/namecoin/namecoin_wallet_test.dart +++ b/test/services/coins/namecoin/namecoin_wallet_test.dart @@ -1,1743 +1,1743 @@ -// import 'package:decimal/decimal.dart'; -// import 'package:flutter_test/flutter_test.dart'; -// import 'package:hive/hive.dart'; -// import 'package:hive_test/hive_test.dart'; -// import 'package:mockito/annotations.dart'; -// import 'package:mockito/mockito.dart'; -// import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; -// import 'package:stackwallet/electrumx_rpc/electrumx.dart'; -// import 'package:stackwallet/hive/db.dart'; -// import 'package:stackwallet/models/paymint/fee_object_model.dart'; -// import 'package:stackwallet/models/paymint/transactions_model.dart'; -// import 'package:stackwallet/models/paymint/utxo_model.dart'; -// import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; -// import 'package:stackwallet/services/price.dart'; -// import 'package:stackwallet/services/transaction_notification_tracker.dart'; -// import 'package:stackwallet/utilities/enums/coin_enum.dart'; -// import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; -// import 'package:tuple/tuple.dart'; -// -// import 'namecoin_history_sample_data.dart'; -// import 'namecoin_transaction_data_samples.dart'; -// import 'namecoin_utxo_sample_data.dart'; -// import 'namecoin_wallet_test.mocks.dart'; -// import 'namecoin_wallet_test_parameters.dart'; -// -// @GenerateMocks( -// [ElectrumX, CachedElectrumX, PriceAPI, TransactionNotificationTracker]) -void main() {} -// group("namecoin constants", () { -// test("namecoin minimum confirmations", () async { -// expect(MINIMUM_CONFIRMATIONS, 2); -// }); -// test("namecoin dust limit", () async { -// expect(DUST_LIMIT, 546); -// }); -// test("namecoin mainnet genesis block hash", () async { -// expect(GENESIS_HASH_MAINNET, -// "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770"); -// }); -// test("namecoin testnet genesis block hash", () async { -// expect(GENESIS_HASH_TESTNET, -// "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"); -// }); -// }); -// -// test("namecoin DerivePathType enum", () { -// expect(DerivePathType.values.length, 3); -// expect(DerivePathType.values.toString(), -// "[DerivePathType.bip44, DerivePathType.bip49, DerivePathType.bip84]"); -// }); -// -// group("bip32 node/root", () { -// test("getBip32Root", () { -// final root = getBip32Root(TEST_MNEMONIC, namecoin); -// expect(root.toWIF(), ROOT_WIF); -// }); -// -// // test("getBip32NodeFromRoot", () { -// // final root = getBip32Root(TEST_MNEMONIC, namecoin); -// // // two mainnet -// // final node44 = getBip32NodeFromRoot(0, 0, root, DerivePathType.bip44); -// // expect(node44.toWIF(), NODE_WIF_44); -// // final node49 = getBip32NodeFromRoot(0, 0, root, DerivePathType.bip49); -// // expect(node49.toWIF(), NODE_WIF_49); -// // // and one on testnet -// // final node84 = getBip32NodeFromRoot( -// // 0, 0, getBip32Root(TEST_MNEMONIC, testnet), DerivePathType.bip84); -// // expect(node84.toWIF(), NODE_WIF_84); -// // // a bad derive path -// // bool didThrow = false; -// // try { -// // getBip32NodeFromRoot(0, 0, root, null); -// // } catch (_) { -// // didThrow = true; -// // } -// // expect(didThrow, true); -// // // finally an invalid network -// // didThrow = false; -// // final invalidNetwork = NetworkType( -// // messagePrefix: '\x18hello world\n', -// // bech32: 'gg', -// // bip32: Bip32Type(public: 0x055521e, private: 0x055555), -// // pubKeyHash: 0x55, -// // scriptHash: 0x55, -// // wif: 0x00); -// // try { -// // getBip32NodeFromRoot(0, 0, getBip32Root(TEST_MNEMONIC, invalidNetwork), -// // DerivePathType.bip44); -// // } catch (_) { -// // didThrow = true; -// // } -// // expect(didThrow, true); -// // }); -// -// // test("basic getBip32Node", () { -// // final node = -// // getBip32Node(0, 0, TEST_MNEMONIC, testnet, DerivePathType.bip84); -// // expect(node.toWIF(), NODE_WIF_84); -// // }); -// }); -// -// group("validate mainnet namecoin addresses", () { -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// NamecoinWallet? mainnetWallet; -// -// setUp(() { -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// mainnetWallet = NamecoinWallet( -// walletId: "validateAddressMainNet", -// walletName: "validateAddressMainNet", -// coin: Coin.namecoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// test("valid mainnet legacy/p2pkh address type", () { -// expect( -// mainnetWallet?.addressType( -// address: "N673DDbjPcrNgJmrhJ1xQXF9LLizQzvjEs"), -// DerivePathType.bip44); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("valid mainnet bech32 p2wpkh address type", () { -// expect( -// mainnetWallet?.addressType( -// address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v"), -// DerivePathType.bip84); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("invalid bech32 address type", () { -// expect( -// () => mainnetWallet?.addressType( -// address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"), -// throwsArgumentError); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("address has no matching script", () { -// expect( -// () => mainnetWallet?.addressType( -// address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"), -// throwsArgumentError); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// group("testNetworkConnection", () { -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// NamecoinWallet? nmc; -// -// setUp(() { -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// nmc = NamecoinWallet( -// walletId: "testNetworkConnection", -// walletName: "testNetworkConnection", -// coin: Coin.namecoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// test("attempted connection fails due to server error", () async { -// when(client?.ping()).thenAnswer((_) async => false); -// final bool? result = await nmc?.testNetworkConnection(); -// expect(result, false); -// expect(secureStore?.interactions, 0); -// verify(client?.ping()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("attempted connection fails due to exception", () async { -// when(client?.ping()).thenThrow(Exception); -// final bool? result = await nmc?.testNetworkConnection(); -// expect(result, false); -// expect(secureStore?.interactions, 0); -// verify(client?.ping()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("attempted connection test success", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// final bool? result = await nmc?.testNetworkConnection(); -// expect(result, true); -// expect(secureStore?.interactions, 0); -// verify(client?.ping()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// group("basic getters, setters, and functions", () { -// final testWalletId = "NMCtestWalletID"; -// final testWalletName = "NMCWallet"; -// -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// NamecoinWallet? nmc; -// -// setUp(() async { -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// nmc = NamecoinWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: Coin.namecoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// test("get networkType main", () async { -// expect(Coin.namecoin, Coin.namecoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get networkType test", () async { -// nmc = NamecoinWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: Coin.namecoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// expect(Coin.namecoin, Coin.namecoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get cryptoCurrency", () async { -// expect(Coin.namecoin, Coin.namecoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get coinName", () async { -// expect(Coin.namecoin, Coin.namecoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get coinTicker", () async { -// expect(Coin.namecoin, Coin.namecoin); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get and set walletName", () async { -// expect(Coin.namecoin, Coin.namecoin); -// nmc?.walletName = "new name"; -// expect(nmc?.walletName, "new name"); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("estimateTxFee", () async { -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1), 356); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 900), 356); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 999), 356); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1000), 356); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1001), 712); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712); -// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get fees succeeds", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.estimateFee(blocks: 1)) -// .thenAnswer((realInvocation) async => Decimal.zero); -// when(client?.estimateFee(blocks: 5)) -// .thenAnswer((realInvocation) async => Decimal.one); -// when(client?.estimateFee(blocks: 20)) -// .thenAnswer((realInvocation) async => Decimal.ten); -// -// final fees = await nmc?.fees; -// expect(fees, isA()); -// expect(fees?.slow, 1000000000); -// expect(fees?.medium, 100000000); -// expect(fees?.fast, 0); -// -// verify(client?.estimateFee(blocks: 1)).called(1); -// verify(client?.estimateFee(blocks: 5)).called(1); -// verify(client?.estimateFee(blocks: 20)).called(1); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get fees fails", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.estimateFee(blocks: 1)) -// .thenAnswer((realInvocation) async => Decimal.zero); -// when(client?.estimateFee(blocks: 5)) -// .thenAnswer((realInvocation) async => Decimal.one); -// when(client?.estimateFee(blocks: 20)) -// .thenThrow(Exception("some exception")); -// -// bool didThrow = false; -// try { -// await nmc?.fees; -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.estimateFee(blocks: 1)).called(1); -// verify(client?.estimateFee(blocks: 5)).called(1); -// verify(client?.estimateFee(blocks: 20)).called(1); -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// // test("get maxFee", () async { -// // when(client?.ping()).thenAnswer((_) async => true); -// // when(client?.getServerFeatures()).thenAnswer((_) async => { -// // "hosts": {}, -// // "pruning": null, -// // "server_version": "Unit tests", -// // "protocol_min": "1.4", -// // "protocol_max": "1.4.2", -// // "genesis_hash": GENESIS_HASH_TESTNET, -// // "hash_function": "sha256", -// // "services": [] -// // }); -// // when(client?.estimateFee(blocks: 20)) -// // .thenAnswer((realInvocation) async => Decimal.zero); -// // when(client?.estimateFee(blocks: 5)) -// // .thenAnswer((realInvocation) async => Decimal.one); -// // when(client?.estimateFee(blocks: 1)) -// // .thenAnswer((realInvocation) async => Decimal.ten); -// // -// // final maxFee = await nmc?.maxFee; -// // expect(maxFee, 1000000000); -// // -// // verify(client?.estimateFee(blocks: 1)).called(1); -// // verify(client?.estimateFee(blocks: 5)).called(1); -// // verify(client?.estimateFee(blocks: 20)).called(1); -// // expect(secureStore?.interactions, 0); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(tracker); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// }); -// -// group("Namecoin service class functions that depend on shared storage", () { -// final testWalletId = "NMCtestWalletID"; -// final testWalletName = "NMCWallet"; -// -// bool hiveAdaptersRegistered = false; -// -// MockElectrumX? client; -// MockCachedElectrumX? cachedClient; -// MockPriceAPI? priceAPI; -// FakeSecureStorage? secureStore; -// MockTransactionNotificationTracker? tracker; -// -// NamecoinWallet? nmc; -// -// setUp(() async { -// await setUpTestHive(); -// if (!hiveAdaptersRegistered) { -// hiveAdaptersRegistered = true; -// -// // Registering Transaction Model Adapters -// Hive.registerAdapter(TransactionDataAdapter()); -// Hive.registerAdapter(TransactionChunkAdapter()); -// Hive.registerAdapter(TransactionAdapter()); -// Hive.registerAdapter(InputAdapter()); -// Hive.registerAdapter(OutputAdapter()); -// -// // Registering Utxo Model Adapters -// Hive.registerAdapter(UtxoDataAdapter()); -// Hive.registerAdapter(UtxoObjectAdapter()); -// Hive.registerAdapter(StatusAdapter()); -// -// final wallets = await Hive.openBox('wallets'); -// await wallets.put('currentWalletName', testWalletName); -// } -// -// client = MockElectrumX(); -// cachedClient = MockCachedElectrumX(); -// priceAPI = MockPriceAPI(); -// secureStore = FakeSecureStorage(); -// tracker = MockTransactionNotificationTracker(); -// -// nmc = NamecoinWallet( -// walletId: testWalletId, -// walletName: testWalletName, -// coin: Coin.namecoin, -// client: client!, -// cachedClient: cachedClient!, -// tracker: tracker!, -// priceAPI: priceAPI, -// secureStore: secureStore, -// ); -// }); -// -// // test("initializeWallet no network", () async { -// // when(client?.ping()).thenAnswer((_) async => false); -// // expect(await nmc?.initializeWallet(), false); -// // expect(secureStore?.interactions, 0); -// // verify(client?.ping()).called(1); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// // test("initializeWallet no network exception", () async { -// // when(client?.ping()).thenThrow(Exception("Network connection failed")); -// // final wallets = await Hive.openBox(testWalletId); -// // expect(await nmc?.initializeExisting(), false); -// // expect(secureStore?.interactions, 0); -// // verify(client?.ping()).called(1); -// // verifyNoMoreInteractions(client); -// // verifyNoMoreInteractions(cachedClient); -// // verifyNoMoreInteractions(priceAPI); -// // }); -// -// test("initializeWallet mainnet throws bad network", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// // await nmc?.initializeNew(); -// final wallets = await Hive.openBox(testWalletId); -// -// expectLater(() => nmc?.initializeExisting(), throwsA(isA())) -// .then((_) { -// expect(secureStore?.interactions, 0); -// // verify(client?.ping()).called(1); -// // verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// test("initializeWallet throws mnemonic overwrite exception", () async { -// when(client?.ping()).thenAnswer((_) async => true); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// await secureStore?.write( -// key: "${testWalletId}_mnemonic", value: "some mnemonic"); -// -// final wallets = await Hive.openBox(testWalletId); -// expectLater(() => nmc?.initializeExisting(), throwsA(isA())) -// .then((_) { -// expect(secureStore?.interactions, 1); -// // verify(client?.ping()).called(1); -// // verify(client?.getServerFeatures()).called(1); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// }); -// -// test( -// "recoverFromMnemonic using empty seed on mainnet fails due to bad genesis hash match", -// () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_TESTNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// bool hasThrown = false; -// try { -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// verify(client?.getServerFeatures()).called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test( -// "recoverFromMnemonic using empty seed on mainnet fails due to attempted overwrite of mnemonic", -// () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// await secureStore?.write( -// key: "${testWalletId}_mnemonic", value: "some mnemonic words"); -// -// bool hasThrown = false; -// try { -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// verify(client?.getServerFeatures()).called(1); -// -// expect(secureStore?.interactions, 2); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("recoverFromMnemonic using empty seed on mainnet succeeds", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// await DB.instance.init(); -// final wallet = await Hive.openBox(testWalletId); -// bool hasThrown = false; -// try { -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, false); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); -// -// expect(secureStore?.interactions, 20); -// expect(secureStore?.writes, 7); -// expect(secureStore?.reads, 13); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("get mnemonic list", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// -// final wallet = await Hive.openBox(testWalletId); -// -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// expect(await nmc?.mnemonic, TEST_MNEMONIC.split(" ")); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("recoverFromMnemonic using non empty seed on mainnet succeeds", -// () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => historyBatchResponse); -// -// List dynamicArgValues = []; -// -// when(client?.getBatchHistory(args: anyNamed("args"))) -// .thenAnswer((realInvocation) async { -// if (realInvocation.namedArguments.values.first.length == 1) { -// dynamicArgValues.add(realInvocation.namedArguments.values.first); -// } -// -// return historyBatchResponse; -// }); -// -// await Hive.openBox(testWalletId); -// -// bool hasThrown = false; -// try { -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, false); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); -// -// for (final arg in dynamicArgValues) { -// final map = Map>.from(arg as Map); -// -// verify(client?.getBatchHistory(args: map)).called(1); -// expect(activeScriptHashes.contains(map.values.first.first as String), -// true); -// } -// -// expect(secureStore?.interactions, 14); -// expect(secureStore?.writes, 7); -// expect(secureStore?.reads, 7); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("fullRescan succeeds", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => historyBatchResponse); -// when(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) -// .thenAnswer((realInvocation) async {}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// when(client?.getBatchHistory(args: { -// "0": [ -// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// final wallet = await Hive.openBox(testWalletId); -// -// // restore so we have something to rescan -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// // fetch valid wallet data -// final preReceivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// final preReceivingAddressesP2SH = -// await wallet.get('receivingAddressesP2SH'); -// final preReceivingAddressesP2WPKH = -// await wallet.get('receivingAddressesP2WPKH'); -// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); -// final preChangeAddressesP2WPKH = -// await wallet.get('changeAddressesP2WPKH'); -// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final preReceivingIndexP2SH = await wallet.get('receivingIndexP2SH'); -// final preReceivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); -// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); -// final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); -// final preUtxoData = await wallet.get('latest_utxo_model'); -// final preReceiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final preChangeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// final preReceiveDerivationsStringP2SH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2SH"); -// final preChangeDerivationsStringP2SH = -// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); -// final preReceiveDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2WPKH"); -// final preChangeDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2WPKH"); -// -// // destroy the data that the rescan will fix -// await wallet.put( -// 'receivingAddressesP2PKH', ["some address", "some other address"]); -// await wallet.put( -// 'receivingAddressesP2SH', ["some address", "some other address"]); -// await wallet.put( -// 'receivingAddressesP2WPKH', ["some address", "some other address"]); -// await wallet -// .put('changeAddressesP2PKH', ["some address", "some other address"]); -// await wallet -// .put('changeAddressesP2SH', ["some address", "some other address"]); -// await wallet -// .put('changeAddressesP2WPKH', ["some address", "some other address"]); -// await wallet.put('receivingIndexP2PKH', 123); -// await wallet.put('receivingIndexP2SH', 123); -// await wallet.put('receivingIndexP2WPKH', 123); -// await wallet.put('changeIndexP2PKH', 123); -// await wallet.put('changeIndexP2SH', 123); -// await wallet.put('changeIndexP2WPKH', 123); -// await secureStore?.write( -// key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_changeDerivationsP2PKH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_receiveDerivationsP2SH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_changeDerivationsP2SH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_receiveDerivationsP2WPKH", value: "{}"); -// await secureStore?.write( -// key: "${testWalletId}_changeDerivationsP2WPKH", value: "{}"); -// -// bool hasThrown = false; -// try { -// await nmc?.fullRescan(2, 1000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, false); -// -// // fetch wallet data again -// final receivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); -// final receivingAddressesP2WPKH = -// await wallet.get('receivingAddressesP2WPKH'); -// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); -// final changeAddressesP2WPKH = await wallet.get('changeAddressesP2WPKH'); -// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); -// final receivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); -// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// final changeIndexP2SH = await wallet.get('changeIndexP2SH'); -// final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); -// final utxoData = await wallet.get('latest_utxo_model'); -// final receiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final changeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// final receiveDerivationsStringP2SH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2SH"); -// final changeDerivationsStringP2SH = -// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); -// final receiveDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2WPKH"); -// final changeDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2WPKH"); -// -// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); -// expect(preReceivingAddressesP2SH, receivingAddressesP2SH); -// expect(preReceivingAddressesP2WPKH, receivingAddressesP2WPKH); -// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); -// expect(preChangeAddressesP2SH, changeAddressesP2SH); -// expect(preChangeAddressesP2WPKH, changeAddressesP2WPKH); -// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); -// expect(preReceivingIndexP2SH, receivingIndexP2SH); -// expect(preReceivingIndexP2WPKH, receivingIndexP2WPKH); -// expect(preChangeIndexP2PKH, changeIndexP2PKH); -// expect(preChangeIndexP2SH, changeIndexP2SH); -// expect(preChangeIndexP2WPKH, changeIndexP2WPKH); -// expect(preUtxoData, utxoData); -// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); -// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); -// expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); -// expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); -// expect(preReceiveDerivationsStringP2WPKH, receiveDerivationsStringP2WPKH); -// expect(preChangeDerivationsStringP2WPKH, changeDerivationsStringP2WPKH); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" -// ] -// })).called(2); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" -// ] -// })).called(2); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" -// ] -// })).called(2); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" -// ] -// })).called(2); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" -// ] -// })).called(2); -// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) -// .called(1); -// -// // for (final arg in dynamicArgValues) { -// // final map = Map>.from(arg as Map); -// // Map argCount = {}; -// // -// // // verify(client?.getBatchHistory(args: map)).called(1); -// // // expect(activeScriptHashes.contains(map.values.first.first as String), -// // // true); -// // } -// -// // Map argCount = {}; -// // -// // for (final arg in dynamicArgValues) { -// // final map = Map>.from(arg as Map); -// // -// // final str = jsonEncode(map); -// // -// // if (argCount[str] == null) { -// // argCount[str] = 1; -// // } else { -// // argCount[str] = argCount[str]! + 1; -// // } -// // } -// // -// // argCount.forEach((key, value) => print("arg: $key\ncount: $value")); -// -// expect(secureStore?.writes, 25); -// expect(secureStore?.reads, 32); -// expect(secureStore?.deletes, 6); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("fullRescan fails", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => historyBatchResponse); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(client?.getBatchHistory(args: { -// "0": [ -// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" -// ] -// })).thenAnswer((realInvocation) async => {"0": []}); -// -// when(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) -// .thenAnswer((realInvocation) async {}); -// -// final wallet = await Hive.openBox(testWalletId); -// -// // restore so we have something to rescan -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// // fetch wallet data -// final preReceivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// final preReceivingAddressesP2SH = -// await wallet.get('receivingAddressesP2SH'); -// final preReceivingAddressesP2WPKH = -// await wallet.get('receivingAddressesP2WPKH'); -// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); -// final preChangeAddressesP2WPKH = -// await wallet.get('changeAddressesP2WPKH'); -// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final preReceivingIndexP2SH = await wallet.get('receivingIndexP2SH'); -// final preReceivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); -// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); -// final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); -// final preUtxoData = await wallet.get('latest_utxo_model'); -// final preReceiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final preChangeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// final preReceiveDerivationsStringP2SH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2SH"); -// final preChangeDerivationsStringP2SH = -// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); -// final preReceiveDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2WPKH"); -// final preChangeDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2WPKH"); -// -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenThrow(Exception("fake exception")); -// -// bool hasThrown = false; -// try { -// await nmc?.fullRescan(2, 1000); -// } catch (_) { -// hasThrown = true; -// } -// expect(hasThrown, true); -// -// // fetch wallet data again -// final receivingAddressesP2PKH = -// await wallet.get('receivingAddressesP2PKH'); -// final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); -// final receivingAddressesP2WPKH = -// await wallet.get('receivingAddressesP2WPKH'); -// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); -// final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); -// final changeAddressesP2WPKH = await wallet.get('changeAddressesP2WPKH'); -// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); -// final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); -// final receivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); -// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); -// final changeIndexP2SH = await wallet.get('changeIndexP2SH'); -// final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); -// final utxoData = await wallet.get('latest_utxo_model'); -// final receiveDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2PKH"); -// final changeDerivationsStringP2PKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2PKH"); -// final receiveDerivationsStringP2SH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2SH"); -// final changeDerivationsStringP2SH = -// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); -// final receiveDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_receiveDerivationsP2WPKH"); -// final changeDerivationsStringP2WPKH = await secureStore?.read( -// key: "${testWalletId}_changeDerivationsP2WPKH"); -// -// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); -// expect(preReceivingAddressesP2SH, receivingAddressesP2SH); -// expect(preReceivingAddressesP2WPKH, receivingAddressesP2WPKH); -// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); -// expect(preChangeAddressesP2SH, changeAddressesP2SH); -// expect(preChangeAddressesP2WPKH, changeAddressesP2WPKH); -// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); -// expect(preReceivingIndexP2SH, receivingIndexP2SH); -// expect(preReceivingIndexP2WPKH, receivingIndexP2WPKH); -// expect(preChangeIndexP2PKH, changeIndexP2PKH); -// expect(preChangeIndexP2SH, changeIndexP2SH); -// expect(preChangeIndexP2WPKH, changeIndexP2WPKH); -// expect(preUtxoData, utxoData); -// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); -// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); -// expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); -// expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); -// expect(preReceiveDerivationsStringP2WPKH, receiveDerivationsStringP2WPKH); -// expect(preChangeDerivationsStringP2WPKH, changeDerivationsStringP2WPKH); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(2); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(2); -// -// verify(client?.getBatchHistory(args: { -// "0": [ -// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" -// ] -// })).called(1); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" -// ] -// })).called(2); -// verify(client?.getBatchHistory(args: { -// "0": [ -// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" -// ] -// })).called(2); -// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) -// .called(1); -// -// expect(secureStore?.writes, 19); -// expect(secureStore?.reads, 32); -// expect(secureStore?.deletes, 12); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("prepareSend fails", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => historyBatchResponse); -// -// List dynamicArgValues = []; -// -// when(client?.getBatchHistory(args: anyNamed("args"))) -// .thenAnswer((realInvocation) async { -// if (realInvocation.namedArguments.values.first.length == 1) { -// dynamicArgValues.add(realInvocation.namedArguments.values.first); -// } -// -// return historyBatchResponse; -// }); -// -// await Hive.openBox(testWalletId); -// -// when(cachedClient?.getTransaction( -// txHash: -// "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", -// coin: Coin.namecoin)) -// .thenAnswer((_) async => tx2Raw); -// when(cachedClient?.getTransaction( -// txHash: -// "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", -// coin: Coin.namecoin)) -// .thenAnswer((_) async => tx3Raw); -// when(cachedClient?.getTransaction( -// txHash: -// "c7e700f7e23a85bbdd9de86d502322a933607ee7ea7e16adaf02e477cdd849b9", -// coin: Coin.namecoin, -// )).thenAnswer((_) async => tx4Raw); -// -// // recover to fill data -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// // modify addresses to properly mock data to build a tx -// final rcv44 = await secureStore?.read( -// key: testWalletId + "_receiveDerivationsP2PKH"); -// await secureStore?.write( -// key: testWalletId + "_receiveDerivationsP2PKH", -// value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", -// "16FuTPaeRSPVxxCnwQmdyx2PQWxX6HWzhQ")); -// final rcv49 = await secureStore?.read( -// key: testWalletId + "_receiveDerivationsP2SH"); -// await secureStore?.write( -// key: testWalletId + "_receiveDerivationsP2SH", -// value: rcv49?.replaceFirst("3AV74rKfibWmvX34F99yEvUcG4LLQ9jZZk", -// "36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g")); -// final rcv84 = await secureStore?.read( -// key: testWalletId + "_receiveDerivationsP2WPKH"); -// await secureStore?.write( -// key: testWalletId + "_receiveDerivationsP2WPKH", -// value: rcv84?.replaceFirst( -// "bc1qggtj4ka8jsaj44hhd5mpamx7mp34m2d3w7k0m0", -// "bc1q42lja79elem0anu8q8s3h2n687re9jax556pcc")); -// -// nmc?.outputsList = utxoList; -// -// bool didThrow = false; -// try { -// await nmc?.prepareSend( -// address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v", -// satoshiAmount: 15000); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.getServerFeatures()).called(1); -// -// /// verify transaction no matching calls -// -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", -// // coin: Coin.namecoin, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", -// // coin: Coin.namecoin, -// // callOutSideMainIsolate: false)) -// // .called(1); -// // verify(cachedClient?.getTransaction( -// // txHash: -// // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", -// // coin: Coin.namecoin, -// // callOutSideMainIsolate: false)) -// // .called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); -// -// for (final arg in dynamicArgValues) { -// final map = Map>.from(arg as Map); -// -// verify(client?.getBatchHistory(args: map)).called(1); -// expect(activeScriptHashes.contains(map.values.first.first as String), -// true); -// } -// -// expect(secureStore?.interactions, 20); -// expect(secureStore?.writes, 10); -// expect(secureStore?.reads, 10); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend no hex", () async { -// bool didThrow = false; -// try { -// await nmc?.confirmSend(txData: {"some": "strange map"}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend hex is not string", () async { -// bool didThrow = false; -// try { -// await nmc?.confirmSend(txData: {"hex": true}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend hex is string but missing other data", () async { -// bool didThrow = false; -// try { -// await nmc?.confirmSend(txData: {"hex": "a string"}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend fails due to vSize being greater than fee", () async { -// bool didThrow = false; -// try { -// await nmc -// ?.confirmSend(txData: {"hex": "a string", "fee": 1, "vSize": 10}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("confirmSend fails when broadcast transactions throws", () async { -// when(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .thenThrow(Exception("some exception")); -// -// bool didThrow = false; -// try { -// await nmc -// ?.confirmSend(txData: {"hex": "a string", "fee": 10, "vSize": 10}); -// } catch (_) { -// didThrow = true; -// } -// -// expect(didThrow, true); -// -// verify(client?.broadcastTransaction( -// rawTx: "a string", requestID: anyNamed("requestID"))) -// .called(1); -// -// expect(secureStore?.interactions, 0); -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// // -// // // this test will create a non mocked electrumx client that will try to connect -// // // to the provided ipAddress below. This will throw a bunch of errors -// // // which what we want here as actually calling electrumx calls here is unwanted. -// // // test("listen to NodesChangedEvent", () async { -// // // nmc = NamecoinWallet( -// // // walletId: testWalletId, -// // // walletName: testWalletName, -// // // networkType: BasicNetworkType.test, -// // // client: client, -// // // cachedClient: cachedClient, -// // // priceAPI: priceAPI, -// // // secureStore: secureStore, -// // // ); -// // // -// // // // set node -// // // final wallet = await Hive.openBox(testWalletId); -// // // await wallet.put("nodes", { -// // // "default": { -// // // "id": "some nodeID", -// // // "ipAddress": "some address", -// // // "port": "9000", -// // // "useSSL": true, -// // // } -// // // }); -// // // await wallet.put("activeNodeID_Bitcoin", "default"); -// // // -// // // final a = nmc.cachedElectrumXClient; -// // // -// // // // return when refresh is called on node changed trigger -// // // nmc.longMutex = true; -// // // -// // // GlobalEventBus.instance -// // // .fire(NodesChangedEvent(NodesChangedEventType.updatedCurrentNode)); -// // // -// // // // make sure event has processed before continuing -// // // await Future.delayed(Duration(seconds: 5)); -// // // -// // // final b = nmc.cachedElectrumXClient; -// // // -// // // expect(identical(a, b), false); -// // // -// // // await nmc.exit(); -// // // -// // // expect(secureStore.interactions, 0); -// // // verifyNoMoreInteractions(client); -// // // verifyNoMoreInteractions(cachedClient); -// // // verifyNoMoreInteractions(priceAPI); -// // // }); -// -// test("refresh wallet mutex locked", () async { -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getBatchHistory(args: historyBatchArgs0)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs1)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs2)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs3)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs4)) -// .thenAnswer((_) async => historyBatchResponse); -// when(client?.getBatchHistory(args: historyBatchArgs5)) -// .thenAnswer((_) async => historyBatchResponse); -// -// List dynamicArgValues = []; -// -// when(client?.getBatchHistory(args: anyNamed("args"))) -// .thenAnswer((realInvocation) async { -// if (realInvocation.namedArguments.values.first.length == 1) { -// dynamicArgValues.add(realInvocation.namedArguments.values.first); -// } -// -// return historyBatchResponse; -// }); -// -// await Hive.openBox(testWalletId); -// -// // recover to fill data -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// nmc?.refreshMutex = true; -// -// await nmc?.refresh(); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); -// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); -// -// for (final arg in dynamicArgValues) { -// final map = Map>.from(arg as Map); -// -// verify(client?.getBatchHistory(args: map)).called(1); -// expect(activeScriptHashes.contains(map.values.first.first as String), -// true); -// } -// -// expect(secureStore?.interactions, 14); -// expect(secureStore?.writes, 7); -// expect(secureStore?.reads, 7); -// expect(secureStore?.deletes, 0); -// -// verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(tracker); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// test("refresh wallet normally", () async { -// when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => -// {"height": 520481, "hex": "some block hex"}); -// when(client?.getServerFeatures()).thenAnswer((_) async => { -// "hosts": {}, -// "pruning": null, -// "server_version": "Unit tests", -// "protocol_min": "1.4", -// "protocol_max": "1.4.2", -// "genesis_hash": GENESIS_HASH_MAINNET, -// "hash_function": "sha256", -// "services": [] -// }); -// when(client?.getHistory(scripthash: anyNamed("scripthash"))) -// .thenAnswer((_) async => []); -// when(client?.estimateFee(blocks: anyNamed("blocks"))) -// .thenAnswer((_) async => Decimal.one); -// -// when(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")) -// .thenAnswer((_) async => {Coin.namecoin: Tuple2(Decimal.one, 0.3)}); -// -// final List dynamicArgValues = []; -// -// when(client?.getBatchHistory(args: anyNamed("args"))) -// .thenAnswer((realInvocation) async { -// dynamicArgValues.add(realInvocation.namedArguments.values.first); -// return historyBatchResponse; -// }); -// -// await Hive.openBox(testWalletId); -// -// // recover to fill data -// await nmc?.recoverFromMnemonic( -// mnemonic: TEST_MNEMONIC, -// maxUnusedAddressGap: 2, -// maxNumberOfIndexesToCheck: 1000, -// height: 4000); -// -// when(client?.getBatchHistory(args: anyNamed("args"))) -// .thenAnswer((_) async => {}); -// when(client?.getBatchUTXOs(args: anyNamed("args"))) -// .thenAnswer((_) async => emptyHistoryBatchResponse); -// -// await nmc?.refresh(); -// -// verify(client?.getServerFeatures()).called(1); -// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(4); -// verify(client?.estimateFee(blocks: anyNamed("blocks"))).called(3); -// verify(client?.getBlockHeadTip()).called(1); -// verify(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")).called(2); -// -// for (final arg in dynamicArgValues) { -// final map = Map>.from(arg as Map); -// -// verify(client?.getBatchHistory(args: map)).called(1); -// } -// -// expect(secureStore?.interactions, 14); -// expect(secureStore?.writes, 7); -// expect(secureStore?.reads, 7); -// expect(secureStore?.deletes, 0); -// -// // verifyNoMoreInteractions(client); -// verifyNoMoreInteractions(cachedClient); -// verifyNoMoreInteractions(priceAPI); -// }); -// -// tearDown(() async { -// await tearDownTestHive(); -// }); -// }); -// } +import 'package:decimal/decimal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:hive/hive.dart'; +import 'package:hive_test/hive_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; +import 'package:stackwallet/electrumx_rpc/electrumx.dart'; +import 'package:stackwallet/hive/db.dart'; +import 'package:stackwallet/models/paymint/fee_object_model.dart'; +import 'package:stackwallet/models/paymint/transactions_model.dart'; +import 'package:stackwallet/models/paymint/utxo_model.dart'; +import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; +import 'package:stackwallet/services/price.dart'; +import 'package:stackwallet/services/transaction_notification_tracker.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +import 'package:tuple/tuple.dart'; + +import 'namecoin_history_sample_data.dart'; +import 'namecoin_transaction_data_samples.dart'; +import 'namecoin_utxo_sample_data.dart'; +import 'namecoin_wallet_test.mocks.dart'; +import 'namecoin_wallet_test_parameters.dart'; + +@GenerateMocks( + [ElectrumX, CachedElectrumX, PriceAPI, TransactionNotificationTracker]) +void main() { + group("namecoin constants", () { + test("namecoin minimum confirmations", () async { + expect(MINIMUM_CONFIRMATIONS, 2); + }); + test("namecoin dust limit", () async { + expect(DUST_LIMIT, 546); + }); + test("namecoin mainnet genesis block hash", () async { + expect(GENESIS_HASH_MAINNET, + "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770"); + }); + test("namecoin testnet genesis block hash", () async { + expect(GENESIS_HASH_TESTNET, + "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"); + }); + }); + + test("namecoin DerivePathType enum", () { + expect(DerivePathType.values.length, 3); + expect(DerivePathType.values.toString(), + "[DerivePathType.bip44, DerivePathType.bip49, DerivePathType.bip84]"); + }); + + group("bip32 node/root", () { + test("getBip32Root", () { + final root = getBip32Root(TEST_MNEMONIC, namecoin); + expect(root.toWIF(), ROOT_WIF); + }); + + // test("getBip32NodeFromRoot", () { + // final root = getBip32Root(TEST_MNEMONIC, namecoin); + // // two mainnet + // final node44 = getBip32NodeFromRoot(0, 0, root, DerivePathType.bip44); + // expect(node44.toWIF(), NODE_WIF_44); + // final node49 = getBip32NodeFromRoot(0, 0, root, DerivePathType.bip49); + // expect(node49.toWIF(), NODE_WIF_49); + // // and one on testnet + // final node84 = getBip32NodeFromRoot( + // 0, 0, getBip32Root(TEST_MNEMONIC, testnet), DerivePathType.bip84); + // expect(node84.toWIF(), NODE_WIF_84); + // // a bad derive path + // bool didThrow = false; + // try { + // getBip32NodeFromRoot(0, 0, root, null); + // } catch (_) { + // didThrow = true; + // } + // expect(didThrow, true); + // // finally an invalid network + // didThrow = false; + // final invalidNetwork = NetworkType( + // messagePrefix: '\x18hello world\n', + // bech32: 'gg', + // bip32: Bip32Type(public: 0x055521e, private: 0x055555), + // pubKeyHash: 0x55, + // scriptHash: 0x55, + // wif: 0x00); + // try { + // getBip32NodeFromRoot(0, 0, getBip32Root(TEST_MNEMONIC, invalidNetwork), + // DerivePathType.bip44); + // } catch (_) { + // didThrow = true; + // } + // expect(didThrow, true); + // }); + + // test("basic getBip32Node", () { + // final node = + // getBip32Node(0, 0, TEST_MNEMONIC, testnet, DerivePathType.bip84); + // expect(node.toWIF(), NODE_WIF_84); + // }); + }); + + group("validate mainnet namecoin addresses", () { + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + NamecoinWallet? mainnetWallet; + + setUp(() { + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + mainnetWallet = NamecoinWallet( + walletId: "validateAddressMainNet", + walletName: "validateAddressMainNet", + coin: Coin.namecoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + test("valid mainnet legacy/p2pkh address type", () { + expect( + mainnetWallet?.addressType( + address: "N673DDbjPcrNgJmrhJ1xQXF9LLizQzvjEs"), + DerivePathType.bip44); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("valid mainnet bech32 p2wpkh address type", () { + expect( + mainnetWallet?.addressType( + address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v"), + DerivePathType.bip84); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("invalid bech32 address type", () { + expect( + () => mainnetWallet?.addressType( + address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"), + throwsArgumentError); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("address has no matching script", () { + expect( + () => mainnetWallet?.addressType( + address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"), + throwsArgumentError); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + }); + + group("testNetworkConnection", () { + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + NamecoinWallet? nmc; + + setUp(() { + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + nmc = NamecoinWallet( + walletId: "testNetworkConnection", + walletName: "testNetworkConnection", + coin: Coin.namecoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + test("attempted connection fails due to server error", () async { + when(client?.ping()).thenAnswer((_) async => false); + final bool? result = await nmc?.testNetworkConnection(); + expect(result, false); + expect(secureStore?.interactions, 0); + verify(client?.ping()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("attempted connection fails due to exception", () async { + when(client?.ping()).thenThrow(Exception); + final bool? result = await nmc?.testNetworkConnection(); + expect(result, false); + expect(secureStore?.interactions, 0); + verify(client?.ping()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("attempted connection test success", () async { + when(client?.ping()).thenAnswer((_) async => true); + final bool? result = await nmc?.testNetworkConnection(); + expect(result, true); + expect(secureStore?.interactions, 0); + verify(client?.ping()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + }); + + group("basic getters, setters, and functions", () { + final testWalletId = "NMCtestWalletID"; + final testWalletName = "NMCWallet"; + + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + NamecoinWallet? nmc; + + setUp(() async { + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + nmc = NamecoinWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: Coin.namecoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + test("get networkType main", () async { + expect(Coin.namecoin, Coin.namecoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get networkType test", () async { + nmc = NamecoinWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: Coin.namecoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + expect(Coin.namecoin, Coin.namecoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get cryptoCurrency", () async { + expect(Coin.namecoin, Coin.namecoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get coinName", () async { + expect(Coin.namecoin, Coin.namecoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get coinTicker", () async { + expect(Coin.namecoin, Coin.namecoin); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get and set walletName", () async { + expect(Coin.namecoin, Coin.namecoin); + nmc?.walletName = "new name"; + expect(nmc?.walletName, "new name"); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("estimateTxFee", () async { + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1), 356); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 900), 356); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 999), 356); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1000), 356); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1001), 712); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712); + expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get fees succeeds", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.estimateFee(blocks: 1)) + .thenAnswer((realInvocation) async => Decimal.zero); + when(client?.estimateFee(blocks: 5)) + .thenAnswer((realInvocation) async => Decimal.one); + when(client?.estimateFee(blocks: 20)) + .thenAnswer((realInvocation) async => Decimal.ten); + + final fees = await nmc?.fees; + expect(fees, isA()); + expect(fees?.slow, 1000000000); + expect(fees?.medium, 100000000); + expect(fees?.fast, 0); + + verify(client?.estimateFee(blocks: 1)).called(1); + verify(client?.estimateFee(blocks: 5)).called(1); + verify(client?.estimateFee(blocks: 20)).called(1); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get fees fails", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.estimateFee(blocks: 1)) + .thenAnswer((realInvocation) async => Decimal.zero); + when(client?.estimateFee(blocks: 5)) + .thenAnswer((realInvocation) async => Decimal.one); + when(client?.estimateFee(blocks: 20)) + .thenThrow(Exception("some exception")); + + bool didThrow = false; + try { + await nmc?.fees; + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.estimateFee(blocks: 1)).called(1); + verify(client?.estimateFee(blocks: 5)).called(1); + verify(client?.estimateFee(blocks: 20)).called(1); + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + // test("get maxFee", () async { + // when(client?.ping()).thenAnswer((_) async => true); + // when(client?.getServerFeatures()).thenAnswer((_) async => { + // "hosts": {}, + // "pruning": null, + // "server_version": "Unit tests", + // "protocol_min": "1.4", + // "protocol_max": "1.4.2", + // "genesis_hash": GENESIS_HASH_TESTNET, + // "hash_function": "sha256", + // "services": [] + // }); + // when(client?.estimateFee(blocks: 20)) + // .thenAnswer((realInvocation) async => Decimal.zero); + // when(client?.estimateFee(blocks: 5)) + // .thenAnswer((realInvocation) async => Decimal.one); + // when(client?.estimateFee(blocks: 1)) + // .thenAnswer((realInvocation) async => Decimal.ten); + // + // final maxFee = await nmc?.maxFee; + // expect(maxFee, 1000000000); + // + // verify(client?.estimateFee(blocks: 1)).called(1); + // verify(client?.estimateFee(blocks: 5)).called(1); + // verify(client?.estimateFee(blocks: 20)).called(1); + // expect(secureStore?.interactions, 0); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(tracker); + // verifyNoMoreInteractions(priceAPI); + // }); + }); + + group("Namecoin service class functions that depend on shared storage", () { + final testWalletId = "NMCtestWalletID"; + final testWalletName = "NMCWallet"; + + bool hiveAdaptersRegistered = false; + + MockElectrumX? client; + MockCachedElectrumX? cachedClient; + MockPriceAPI? priceAPI; + FakeSecureStorage? secureStore; + MockTransactionNotificationTracker? tracker; + + NamecoinWallet? nmc; + + setUp(() async { + await setUpTestHive(); + if (!hiveAdaptersRegistered) { + hiveAdaptersRegistered = true; + + // Registering Transaction Model Adapters + Hive.registerAdapter(TransactionDataAdapter()); + Hive.registerAdapter(TransactionChunkAdapter()); + Hive.registerAdapter(TransactionAdapter()); + Hive.registerAdapter(InputAdapter()); + Hive.registerAdapter(OutputAdapter()); + + // Registering Utxo Model Adapters + Hive.registerAdapter(UtxoDataAdapter()); + Hive.registerAdapter(UtxoObjectAdapter()); + Hive.registerAdapter(StatusAdapter()); + + final wallets = await Hive.openBox('wallets'); + await wallets.put('currentWalletName', testWalletName); + } + + client = MockElectrumX(); + cachedClient = MockCachedElectrumX(); + priceAPI = MockPriceAPI(); + secureStore = FakeSecureStorage(); + tracker = MockTransactionNotificationTracker(); + + nmc = NamecoinWallet( + walletId: testWalletId, + walletName: testWalletName, + coin: Coin.namecoin, + client: client!, + cachedClient: cachedClient!, + tracker: tracker!, + priceAPI: priceAPI, + secureStore: secureStore, + ); + }); + + // test("initializeWallet no network", () async { + // when(client?.ping()).thenAnswer((_) async => false); + // expect(await nmc?.initializeWallet(), false); + // expect(secureStore?.interactions, 0); + // verify(client?.ping()).called(1); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + // test("initializeWallet no network exception", () async { + // when(client?.ping()).thenThrow(Exception("Network connection failed")); + // final wallets = await Hive.openBox(testWalletId); + // expect(await nmc?.initializeExisting(), false); + // expect(secureStore?.interactions, 0); + // verify(client?.ping()).called(1); + // verifyNoMoreInteractions(client); + // verifyNoMoreInteractions(cachedClient); + // verifyNoMoreInteractions(priceAPI); + // }); + + test("initializeWallet mainnet throws bad network", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + // await nmc?.initializeNew(); + final wallets = await Hive.openBox(testWalletId); + + expectLater(() => nmc?.initializeExisting(), throwsA(isA())) + .then((_) { + expect(secureStore?.interactions, 0); + // verify(client?.ping()).called(1); + // verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + }); + + test("initializeWallet throws mnemonic overwrite exception", () async { + when(client?.ping()).thenAnswer((_) async => true); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + await secureStore?.write( + key: "${testWalletId}_mnemonic", value: "some mnemonic"); + + final wallets = await Hive.openBox(testWalletId); + expectLater(() => nmc?.initializeExisting(), throwsA(isA())) + .then((_) { + expect(secureStore?.interactions, 1); + // verify(client?.ping()).called(1); + // verify(client?.getServerFeatures()).called(1); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + }); + + test( + "recoverFromMnemonic using empty seed on mainnet fails due to bad genesis hash match", + () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_TESTNET, + "hash_function": "sha256", + "services": [] + }); + + bool hasThrown = false; + try { + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + verify(client?.getServerFeatures()).called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test( + "recoverFromMnemonic using empty seed on mainnet fails due to attempted overwrite of mnemonic", + () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + + await secureStore?.write( + key: "${testWalletId}_mnemonic", value: "some mnemonic words"); + + bool hasThrown = false; + try { + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + verify(client?.getServerFeatures()).called(1); + + expect(secureStore?.interactions, 2); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("recoverFromMnemonic using empty seed on mainnet succeeds", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + await DB.instance.init(); + final wallet = await Hive.openBox(testWalletId); + bool hasThrown = false; + try { + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, false); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); + + expect(secureStore?.interactions, 20); + expect(secureStore?.writes, 7); + expect(secureStore?.reads, 13); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("get mnemonic list", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => emptyHistoryBatchResponse); + + final wallet = await Hive.openBox(testWalletId); + + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + expect(await nmc?.mnemonic, TEST_MNEMONIC.split(" ")); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("recoverFromMnemonic using non empty seed on mainnet succeeds", + () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => historyBatchResponse); + + List dynamicArgValues = []; + + when(client?.getBatchHistory(args: anyNamed("args"))) + .thenAnswer((realInvocation) async { + if (realInvocation.namedArguments.values.first.length == 1) { + dynamicArgValues.add(realInvocation.namedArguments.values.first); + } + + return historyBatchResponse; + }); + + await Hive.openBox(testWalletId); + + bool hasThrown = false; + try { + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, false); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); + + for (final arg in dynamicArgValues) { + final map = Map>.from(arg as Map); + + verify(client?.getBatchHistory(args: map)).called(1); + expect(activeScriptHashes.contains(map.values.first.first as String), + true); + } + + expect(secureStore?.interactions, 14); + expect(secureStore?.writes, 7); + expect(secureStore?.reads, 7); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("fullRescan succeeds", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => historyBatchResponse); + when(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) + .thenAnswer((realInvocation) async {}); + + when(client?.getBatchHistory(args: { + "0": [ + "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + final wallet = await Hive.openBox(testWalletId); + + // restore so we have something to rescan + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + // fetch valid wallet data + final preReceivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + final preReceivingAddressesP2SH = + await wallet.get('receivingAddressesP2SH'); + final preReceivingAddressesP2WPKH = + await wallet.get('receivingAddressesP2WPKH'); + final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); + final preChangeAddressesP2WPKH = + await wallet.get('changeAddressesP2WPKH'); + final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final preReceivingIndexP2SH = await wallet.get('receivingIndexP2SH'); + final preReceivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); + final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); + final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); + final preUtxoData = await wallet.get('latest_utxo_model'); + final preReceiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final preChangeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + final preReceiveDerivationsStringP2SH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2SH"); + final preChangeDerivationsStringP2SH = + await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); + final preReceiveDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2WPKH"); + final preChangeDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2WPKH"); + + // destroy the data that the rescan will fix + await wallet.put( + 'receivingAddressesP2PKH', ["some address", "some other address"]); + await wallet.put( + 'receivingAddressesP2SH', ["some address", "some other address"]); + await wallet.put( + 'receivingAddressesP2WPKH', ["some address", "some other address"]); + await wallet + .put('changeAddressesP2PKH', ["some address", "some other address"]); + await wallet + .put('changeAddressesP2SH', ["some address", "some other address"]); + await wallet + .put('changeAddressesP2WPKH', ["some address", "some other address"]); + await wallet.put('receivingIndexP2PKH', 123); + await wallet.put('receivingIndexP2SH', 123); + await wallet.put('receivingIndexP2WPKH', 123); + await wallet.put('changeIndexP2PKH', 123); + await wallet.put('changeIndexP2SH', 123); + await wallet.put('changeIndexP2WPKH', 123); + await secureStore?.write( + key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_changeDerivationsP2PKH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_receiveDerivationsP2SH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_changeDerivationsP2SH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_receiveDerivationsP2WPKH", value: "{}"); + await secureStore?.write( + key: "${testWalletId}_changeDerivationsP2WPKH", value: "{}"); + + bool hasThrown = false; + try { + await nmc?.fullRescan(2, 1000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, false); + + // fetch wallet data again + final receivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); + final receivingAddressesP2WPKH = + await wallet.get('receivingAddressesP2WPKH'); + final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); + final changeAddressesP2WPKH = await wallet.get('changeAddressesP2WPKH'); + final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); + final receivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); + final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + final changeIndexP2SH = await wallet.get('changeIndexP2SH'); + final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); + final utxoData = await wallet.get('latest_utxo_model'); + final receiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final changeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + final receiveDerivationsStringP2SH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2SH"); + final changeDerivationsStringP2SH = + await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); + final receiveDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2WPKH"); + final changeDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2WPKH"); + + expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); + expect(preReceivingAddressesP2SH, receivingAddressesP2SH); + expect(preReceivingAddressesP2WPKH, receivingAddressesP2WPKH); + expect(preChangeAddressesP2PKH, changeAddressesP2PKH); + expect(preChangeAddressesP2SH, changeAddressesP2SH); + expect(preChangeAddressesP2WPKH, changeAddressesP2WPKH); + expect(preReceivingIndexP2PKH, receivingIndexP2PKH); + expect(preReceivingIndexP2SH, receivingIndexP2SH); + expect(preReceivingIndexP2WPKH, receivingIndexP2WPKH); + expect(preChangeIndexP2PKH, changeIndexP2PKH); + expect(preChangeIndexP2SH, changeIndexP2SH); + expect(preChangeIndexP2WPKH, changeIndexP2WPKH); + expect(preUtxoData, utxoData); + expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); + expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); + expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); + expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); + expect(preReceiveDerivationsStringP2WPKH, receiveDerivationsStringP2WPKH); + expect(preChangeDerivationsStringP2WPKH, changeDerivationsStringP2WPKH); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" + ] + })).called(2); + + verify(client?.getBatchHistory(args: { + "0": [ + "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" + ] + })).called(2); + + verify(client?.getBatchHistory(args: { + "0": [ + "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" + ] + })).called(2); + + verify(client?.getBatchHistory(args: { + "0": [ + "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" + ] + })).called(2); + + verify(client?.getBatchHistory(args: { + "0": [ + "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" + ] + })).called(2); + verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) + .called(1); + + // for (final arg in dynamicArgValues) { + // final map = Map>.from(arg as Map); + // Map argCount = {}; + // + // // verify(client?.getBatchHistory(args: map)).called(1); + // // expect(activeScriptHashes.contains(map.values.first.first as String), + // // true); + // } + + // Map argCount = {}; + // + // for (final arg in dynamicArgValues) { + // final map = Map>.from(arg as Map); + // + // final str = jsonEncode(map); + // + // if (argCount[str] == null) { + // argCount[str] = 1; + // } else { + // argCount[str] = argCount[str]! + 1; + // } + // } + // + // argCount.forEach((key, value) => print("arg: $key\ncount: $value")); + + expect(secureStore?.writes, 25); + expect(secureStore?.reads, 32); + expect(secureStore?.deletes, 6); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("fullRescan fails", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => historyBatchResponse); + + when(client?.getBatchHistory(args: { + "0": [ + "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(client?.getBatchHistory(args: { + "0": [ + "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" + ] + })).thenAnswer((realInvocation) async => {"0": []}); + + when(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) + .thenAnswer((realInvocation) async {}); + + final wallet = await Hive.openBox(testWalletId); + + // restore so we have something to rescan + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + // fetch wallet data + final preReceivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + final preReceivingAddressesP2SH = + await wallet.get('receivingAddressesP2SH'); + final preReceivingAddressesP2WPKH = + await wallet.get('receivingAddressesP2WPKH'); + final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); + final preChangeAddressesP2WPKH = + await wallet.get('changeAddressesP2WPKH'); + final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final preReceivingIndexP2SH = await wallet.get('receivingIndexP2SH'); + final preReceivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); + final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); + final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); + final preUtxoData = await wallet.get('latest_utxo_model'); + final preReceiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final preChangeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + final preReceiveDerivationsStringP2SH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2SH"); + final preChangeDerivationsStringP2SH = + await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); + final preReceiveDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2WPKH"); + final preChangeDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2WPKH"); + + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenThrow(Exception("fake exception")); + + bool hasThrown = false; + try { + await nmc?.fullRescan(2, 1000); + } catch (_) { + hasThrown = true; + } + expect(hasThrown, true); + + // fetch wallet data again + final receivingAddressesP2PKH = + await wallet.get('receivingAddressesP2PKH'); + final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); + final receivingAddressesP2WPKH = + await wallet.get('receivingAddressesP2WPKH'); + final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); + final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); + final changeAddressesP2WPKH = await wallet.get('changeAddressesP2WPKH'); + final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); + final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); + final receivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); + final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); + final changeIndexP2SH = await wallet.get('changeIndexP2SH'); + final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); + final utxoData = await wallet.get('latest_utxo_model'); + final receiveDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2PKH"); + final changeDerivationsStringP2PKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2PKH"); + final receiveDerivationsStringP2SH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2SH"); + final changeDerivationsStringP2SH = + await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); + final receiveDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_receiveDerivationsP2WPKH"); + final changeDerivationsStringP2WPKH = await secureStore?.read( + key: "${testWalletId}_changeDerivationsP2WPKH"); + + expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); + expect(preReceivingAddressesP2SH, receivingAddressesP2SH); + expect(preReceivingAddressesP2WPKH, receivingAddressesP2WPKH); + expect(preChangeAddressesP2PKH, changeAddressesP2PKH); + expect(preChangeAddressesP2SH, changeAddressesP2SH); + expect(preChangeAddressesP2WPKH, changeAddressesP2WPKH); + expect(preReceivingIndexP2PKH, receivingIndexP2PKH); + expect(preReceivingIndexP2SH, receivingIndexP2SH); + expect(preReceivingIndexP2WPKH, receivingIndexP2WPKH); + expect(preChangeIndexP2PKH, changeIndexP2PKH); + expect(preChangeIndexP2SH, changeIndexP2SH); + expect(preChangeIndexP2WPKH, changeIndexP2WPKH); + expect(preUtxoData, utxoData); + expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); + expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); + expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); + expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); + expect(preReceiveDerivationsStringP2WPKH, receiveDerivationsStringP2WPKH); + expect(preChangeDerivationsStringP2WPKH, changeDerivationsStringP2WPKH); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(2); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(2); + + verify(client?.getBatchHistory(args: { + "0": [ + "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" + ] + })).called(1); + verify(client?.getBatchHistory(args: { + "0": [ + "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" + ] + })).called(2); + verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) + .called(1); + + expect(secureStore?.writes, 19); + expect(secureStore?.reads, 32); + expect(secureStore?.deletes, 12); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("prepareSend fails", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => historyBatchResponse); + + List dynamicArgValues = []; + + when(client?.getBatchHistory(args: anyNamed("args"))) + .thenAnswer((realInvocation) async { + if (realInvocation.namedArguments.values.first.length == 1) { + dynamicArgValues.add(realInvocation.namedArguments.values.first); + } + + return historyBatchResponse; + }); + + await Hive.openBox(testWalletId); + + when(cachedClient?.getTransaction( + txHash: + "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", + coin: Coin.namecoin)) + .thenAnswer((_) async => tx2Raw); + when(cachedClient?.getTransaction( + txHash: + "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", + coin: Coin.namecoin)) + .thenAnswer((_) async => tx3Raw); + when(cachedClient?.getTransaction( + txHash: + "c7e700f7e23a85bbdd9de86d502322a933607ee7ea7e16adaf02e477cdd849b9", + coin: Coin.namecoin, + )).thenAnswer((_) async => tx4Raw); + + // recover to fill data + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + // modify addresses to properly mock data to build a tx + final rcv44 = await secureStore?.read( + key: testWalletId + "_receiveDerivationsP2PKH"); + await secureStore?.write( + key: testWalletId + "_receiveDerivationsP2PKH", + value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", + "16FuTPaeRSPVxxCnwQmdyx2PQWxX6HWzhQ")); + final rcv49 = await secureStore?.read( + key: testWalletId + "_receiveDerivationsP2SH"); + await secureStore?.write( + key: testWalletId + "_receiveDerivationsP2SH", + value: rcv49?.replaceFirst("3AV74rKfibWmvX34F99yEvUcG4LLQ9jZZk", + "36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g")); + final rcv84 = await secureStore?.read( + key: testWalletId + "_receiveDerivationsP2WPKH"); + await secureStore?.write( + key: testWalletId + "_receiveDerivationsP2WPKH", + value: rcv84?.replaceFirst( + "bc1qggtj4ka8jsaj44hhd5mpamx7mp34m2d3w7k0m0", + "bc1q42lja79elem0anu8q8s3h2n687re9jax556pcc")); + + nmc?.outputsList = utxoList; + + bool didThrow = false; + try { + await nmc?.prepareSend( + address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v", + satoshiAmount: 15000); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.getServerFeatures()).called(1); + + /// verify transaction no matching calls + + // verify(cachedClient?.getTransaction( + // txHash: + // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", + // coin: Coin.namecoin, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", + // coin: Coin.namecoin, + // callOutSideMainIsolate: false)) + // .called(1); + // verify(cachedClient?.getTransaction( + // txHash: + // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", + // coin: Coin.namecoin, + // callOutSideMainIsolate: false)) + // .called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); + + for (final arg in dynamicArgValues) { + final map = Map>.from(arg as Map); + + verify(client?.getBatchHistory(args: map)).called(1); + expect(activeScriptHashes.contains(map.values.first.first as String), + true); + } + + expect(secureStore?.interactions, 20); + expect(secureStore?.writes, 10); + expect(secureStore?.reads, 10); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend no hex", () async { + bool didThrow = false; + try { + await nmc?.confirmSend(txData: {"some": "strange map"}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend hex is not string", () async { + bool didThrow = false; + try { + await nmc?.confirmSend(txData: {"hex": true}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend hex is string but missing other data", () async { + bool didThrow = false; + try { + await nmc?.confirmSend(txData: {"hex": "a string"}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend fails due to vSize being greater than fee", () async { + bool didThrow = false; + try { + await nmc + ?.confirmSend(txData: {"hex": "a string", "fee": 1, "vSize": 10}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + test("confirmSend fails when broadcast transactions throws", () async { + when(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .thenThrow(Exception("some exception")); + + bool didThrow = false; + try { + await nmc + ?.confirmSend(txData: {"hex": "a string", "fee": 10, "vSize": 10}); + } catch (_) { + didThrow = true; + } + + expect(didThrow, true); + + verify(client?.broadcastTransaction( + rawTx: "a string", requestID: anyNamed("requestID"))) + .called(1); + + expect(secureStore?.interactions, 0); + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + // + // // this test will create a non mocked electrumx client that will try to connect + // // to the provided ipAddress below. This will throw a bunch of errors + // // which what we want here as actually calling electrumx calls here is unwanted. + // // test("listen to NodesChangedEvent", () async { + // // nmc = NamecoinWallet( + // // walletId: testWalletId, + // // walletName: testWalletName, + // // networkType: BasicNetworkType.test, + // // client: client, + // // cachedClient: cachedClient, + // // priceAPI: priceAPI, + // // secureStore: secureStore, + // // ); + // // + // // // set node + // // final wallet = await Hive.openBox(testWalletId); + // // await wallet.put("nodes", { + // // "default": { + // // "id": "some nodeID", + // // "ipAddress": "some address", + // // "port": "9000", + // // "useSSL": true, + // // } + // // }); + // // await wallet.put("activeNodeID_Bitcoin", "default"); + // // + // // final a = nmc.cachedElectrumXClient; + // // + // // // return when refresh is called on node changed trigger + // // nmc.longMutex = true; + // // + // // GlobalEventBus.instance + // // .fire(NodesChangedEvent(NodesChangedEventType.updatedCurrentNode)); + // // + // // // make sure event has processed before continuing + // // await Future.delayed(Duration(seconds: 5)); + // // + // // final b = nmc.cachedElectrumXClient; + // // + // // expect(identical(a, b), false); + // // + // // await nmc.exit(); + // // + // // expect(secureStore.interactions, 0); + // // verifyNoMoreInteractions(client); + // // verifyNoMoreInteractions(cachedClient); + // // verifyNoMoreInteractions(priceAPI); + // // }); + + test("refresh wallet mutex locked", () async { + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getBatchHistory(args: historyBatchArgs0)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs1)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs2)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs3)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs4)) + .thenAnswer((_) async => historyBatchResponse); + when(client?.getBatchHistory(args: historyBatchArgs5)) + .thenAnswer((_) async => historyBatchResponse); + + List dynamicArgValues = []; + + when(client?.getBatchHistory(args: anyNamed("args"))) + .thenAnswer((realInvocation) async { + if (realInvocation.namedArguments.values.first.length == 1) { + dynamicArgValues.add(realInvocation.namedArguments.values.first); + } + + return historyBatchResponse; + }); + + await Hive.openBox(testWalletId); + + // recover to fill data + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + nmc?.refreshMutex = true; + + await nmc?.refresh(); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); + verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); + + for (final arg in dynamicArgValues) { + final map = Map>.from(arg as Map); + + verify(client?.getBatchHistory(args: map)).called(1); + expect(activeScriptHashes.contains(map.values.first.first as String), + true); + } + + expect(secureStore?.interactions, 14); + expect(secureStore?.writes, 7); + expect(secureStore?.reads, 7); + expect(secureStore?.deletes, 0); + + verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(tracker); + verifyNoMoreInteractions(priceAPI); + }); + + test("refresh wallet normally", () async { + when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => + {"height": 520481, "hex": "some block hex"}); + when(client?.getServerFeatures()).thenAnswer((_) async => { + "hosts": {}, + "pruning": null, + "server_version": "Unit tests", + "protocol_min": "1.4", + "protocol_max": "1.4.2", + "genesis_hash": GENESIS_HASH_MAINNET, + "hash_function": "sha256", + "services": [] + }); + when(client?.getHistory(scripthash: anyNamed("scripthash"))) + .thenAnswer((_) async => []); + when(client?.estimateFee(blocks: anyNamed("blocks"))) + .thenAnswer((_) async => Decimal.one); + + when(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")) + .thenAnswer((_) async => {Coin.namecoin: Tuple2(Decimal.one, 0.3)}); + + final List dynamicArgValues = []; + + when(client?.getBatchHistory(args: anyNamed("args"))) + .thenAnswer((realInvocation) async { + dynamicArgValues.add(realInvocation.namedArguments.values.first); + return historyBatchResponse; + }); + + await Hive.openBox(testWalletId); + + // recover to fill data + await nmc?.recoverFromMnemonic( + mnemonic: TEST_MNEMONIC, + maxUnusedAddressGap: 2, + maxNumberOfIndexesToCheck: 1000, + height: 4000); + + when(client?.getBatchHistory(args: anyNamed("args"))) + .thenAnswer((_) async => {}); + when(client?.getBatchUTXOs(args: anyNamed("args"))) + .thenAnswer((_) async => emptyHistoryBatchResponse); + + await nmc?.refresh(); + + verify(client?.getServerFeatures()).called(1); + verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(4); + verify(client?.estimateFee(blocks: anyNamed("blocks"))).called(3); + verify(client?.getBlockHeadTip()).called(1); + verify(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")).called(2); + + for (final arg in dynamicArgValues) { + final map = Map>.from(arg as Map); + + verify(client?.getBatchHistory(args: map)).called(1); + } + + expect(secureStore?.interactions, 14); + expect(secureStore?.writes, 7); + expect(secureStore?.reads, 7); + expect(secureStore?.deletes, 0); + + // verifyNoMoreInteractions(client); + verifyNoMoreInteractions(cachedClient); + verifyNoMoreInteractions(priceAPI); + }); + + tearDown(() async { + await tearDownTestHive(); + }); + }); +}