diff --git a/cw_zcash/lib/src/zcash_taddress_rotation.dart b/cw_zcash/lib/src/zcash_taddress_rotation.dart index 14bdc530e..1c2ef1f20 100644 --- a/cw_zcash/lib/src/zcash_taddress_rotation.dart +++ b/cw_zcash/lib/src/zcash_taddress_rotation.dart @@ -313,6 +313,7 @@ class ZcashTaddressRotation { final recipient = Recipient(recipientBuilder.toBytes()); final fee = FeeT(fee: 10000, minFee: 0, maxFee: 0, scheme: 0); + await ZcashWalletBase.loadProver(); final txPlan = await ZcashWalletService.runInDbMutex( () => WarpApi.prepareTx( coin, diff --git a/cw_zcash/lib/src/zcash_wallet.dart b/cw_zcash/lib/src/zcash_wallet.dart index 4599fa9b3..bfce46d41 100644 --- a/cw_zcash/lib/src/zcash_wallet.dart +++ b/cw_zcash/lib/src/zcash_wallet.dart @@ -11,6 +11,7 @@ import 'package:cw_core/sync_status.dart'; import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/utils/print_verbose.dart'; +import 'package:cw_core/utils/proxy_wrapper.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; @@ -220,6 +221,7 @@ abstract class ZcashWalletBase // pools parameter: bitmask for which pools to use for sending // 1=Transparent, 2=Sapling, 4=Orchard, 7=All pools + await ZcashWalletBase.loadProver(); // Using 7 (all pools) allows spending from any pool type final txPlan = await ZcashWalletService.runInDbMutex( () => WarpApi.prepareTx( @@ -333,6 +335,8 @@ abstract class ZcashWalletBase "privateViewKey": backup.fvk, "uvk": backup.uvk, "tsk": backup.tsk, + if (lastKnownRestoreHeight != null) + "restoreHeight": lastKnownRestoreHeight.toString(), }; } @@ -354,12 +358,14 @@ abstract class ZcashWalletBase bool get hasRescan => true; static Future storeZcashHeight(final int height) async { + lastKnownRestoreHeight = height; final zcashDir = await pathForWalletTypeDir(type: WalletType.zcash); final zcashInitialSync = File(p.join(zcashDir, ".initial-sync-marker")); zcashInitialSync.writeAsBytesSync([0x00]); zcashInitialSync.writeAsStringSync(height.toString(), mode: FileMode.writeOnlyAppend); } + static int? lastKnownRestoreHeight = null; static Future loadZcashHeight() async { final zcashDir = await pathForWalletTypeDir(type: WalletType.zcash); final zcashInitialSync = File(p.join(zcashDir, ".initial-sync-marker")); @@ -371,7 +377,8 @@ abstract class ZcashWalletBase return null; } final heightString = String.fromCharCodes(bytes.skip(1)); - return int.tryParse(heightString); + lastKnownRestoreHeight = int.tryParse(heightString); + return lastKnownRestoreHeight; } static int zashiAnnouncedBlockHeight = 2419420; @@ -749,6 +756,7 @@ abstract class ZcashWalletBase final recipient = Recipient(recipientBuilder.toBytes()); final fee = FeeT(fee: 10000, minFee: 0, maxFee: 0, scheme: 0); + await ZcashWalletBase.loadProver(); final txPlan = await ZcashWalletService.runInDbMutex( () => WarpApi.prepareTx( coin, @@ -1039,13 +1047,45 @@ abstract class ZcashWalletBase } catch (e) { printV("zec init failed: $e"); } // do not fail on network exception - final spend = await rootBundle.load('scripts/zcash_lib/assets/sapling-spend.params'); - final output = await rootBundle.load('scripts/zcash_lib/assets/sapling-output.params'); - WarpApi.initProver(spend.buffer.asUint8List(), output.buffer.asUint8List()); + await loadZcashHeight(); + + unawaited(loadProver()); + await ZcashTaddressRotation.init(); await ZcashTransactionInfo.init(); _initialized = true; } + + static bool isProverLoaded = false; + static Future loadProver() async { + Uint8List? spend; + Uint8List? output; + final cacheDir = await getApplicationCacheDirectory(); + try { + final spendBundle = await rootBundle.load('scripts/zcash_lib/assets/sapling-spend.params'); + final outputBundle = await rootBundle.load('scripts/zcash_lib/assets/sapling-output.params'); + spend = spendBundle.buffer.asUint8List(); + output = outputBundle.buffer.asUint8List(); + if (spend.length == 0 || output.length == 0) throw Exception("NUH UH"); + spend = await File(cacheDir.path+"/sapling-spend.params").readAsBytesSync(); + output = await File(cacheDir.path+"/sapling-output.params").readAsBytesSync(); + if (spend.length == 0 || output.length == 0) throw Exception("NUH UH"); + } catch (e) { + printV("$e. Fine, I'll download them."); + final spendResponse = await ProxyWrapper().get( + clearnetUri: Uri.parse("https://download.z.cash/downloads/sapling-spend.params"), + ); + final outputResponse = await ProxyWrapper().get( + clearnetUri: Uri.parse("https://download.z.cash/downloads/sapling-output.params"), + ); + spend = spendResponse.bodyBytes; + output = outputResponse.bodyBytes; + await File(cacheDir.path+"/sapling-spend.params").writeAsBytes(spend); + await File(cacheDir.path+"/sapling-output.params").writeAsBytes(output); + } + WarpApi.initProver(spend, output); + isProverLoaded = true; + } static Future getBlockHeightByTime(final DateTime time) async { final genesisTime = DateTime.utc(2016, 10, 28); diff --git a/lib/src/screens/wallet_keys/wallet_keys_page.dart b/lib/src/screens/wallet_keys/wallet_keys_page.dart index 4048636fc..1a250ef47 100644 --- a/lib/src/screens/wallet_keys/wallet_keys_page.dart +++ b/lib/src/screens/wallet_keys/wallet_keys_page.dart @@ -183,7 +183,7 @@ class _WalletKeysPageBodyState extends State Widget _buildSeedTab(BuildContext context, bool isLegacySeed) { return Column( children: [ - if (isLegacySeedOnly || isLegacySeed || widget.walletKeysViewModel.isBitcoin) ...[ + if (isLegacySeedOnly || isLegacySeed ||widget.walletKeysViewModel.shouldShowHeightBox) ...[ _buildHeightBox(), const SizedBox(height: 20), ], diff --git a/lib/view_model/wallet_keys_view_model.dart b/lib/view_model/wallet_keys_view_model.dart index 83d14853a..a1f68a4c3 100644 --- a/lib/view_model/wallet_keys_view_model.dart +++ b/lib/view_model/wallet_keys_view_model.dart @@ -62,7 +62,9 @@ abstract class WalletKeysViewModelBase with Store { } bool get isBitcoin => _wallet.type == WalletType.bitcoin; - + + // this is incomplete, needs legacy seed toggle for XMR + bool get shouldShowHeightBox => [WalletType.bitcoin, WalletType.zcash].contains(_wallet.type); final ObservableList items; @observable @@ -318,6 +320,9 @@ abstract class WalletKeysViewModelBase with Store { if (_wallet.type == WalletType.wownero) { return wownero!.getRestoreHeight(_wallet)?.toString(); } + if (_wallet.type == WalletType.zcash) { + return zcash!.getKeys(_wallet)["restoreHeight"]?.toString(); + } if (_restoreHeightByTransactions != 0) return getRoundedRestoreHeight(_restoreHeightByTransactions); if (_restoreHeight != 0) return _restoreHeight.toString();