mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Nuke Zcash from build infra (chain already disabled at config layer)
Removed:
- cw_zcash/ directory (Dart wrapper, no longer needed)
- assets/zcash_node_list.yml
- scripts/prepare_zcash.sh
- scripts/{android,ios,linux,macos}/build_zcash.sh
- scripts/android/docker/Dockerfile.zcash
- scripts/zcash_lib/ if cloned (rebuildable from prepare_zcash.sh which is also gone)
Edited:
- scripts/lint.sh: replaced cw_zcash loop target with the actual modules we
ship (cw_core, cw_monero, cw_wownero, cw_bitcoin, cw_bitcoin_cash,
cw_dogecoin, cw_evm, cw_nano).
- hashwallet.bat: trimmed mobx codegen loop to enabled chains.
- pubspec_base.yaml: dropped zcash_node_list.yml + zcash_lib sapling
asset references.
- scripts/android/docker/{build.sh,Dockerfile.final}: removed zcash image
build + COPY stage.
tool/configure.dart still has the zcash codegen functions intact (they
just don't fire because we don't pass --zcash); leaving them as harmless
dead code rather than risking a regression in the codegen pipeline.
This commit is contained in:
@@ -1,12 +0,0 @@
|
||||
- uri: zec.rocks:443
|
||||
is_default: false
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
- uri: zec-node.cakewallet.com:443
|
||||
is_default: true
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
- uri: 2c4whzg26j6hgjh22rxynj3oig4gm22ga7x74weclujywxye23v3u5id.onion:9067
|
||||
useSSL: false
|
||||
- uri: bvp2l442g5ogma7rywzahm7eqyhpp3g26n3gvvxeioqn5csio2ir6myd.onion:9067
|
||||
useSSL: false
|
||||
@@ -1,7 +0,0 @@
|
||||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
|
||||
# Avoid committing pubspec.lock for library packages; see
|
||||
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
pubspec.lock
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.0.0
|
||||
|
||||
- Initial version.
|
||||
@@ -1 +0,0 @@
|
||||
# cw_zcash
|
||||
@@ -1,31 +0,0 @@
|
||||
analyzer:
|
||||
errors:
|
||||
implementation_imports: ignore
|
||||
must_be_immutable: ignore
|
||||
overridden_fields: ignore
|
||||
exclude:
|
||||
- "**.g.dart"
|
||||
- "external/**"
|
||||
|
||||
linter:
|
||||
rules:
|
||||
unawaited_futures: true
|
||||
avoid_print: false
|
||||
parameter_assignments: true
|
||||
prefer_const_declarations: true
|
||||
prefer_final_fields: true
|
||||
prefer_final_in_for_each: true
|
||||
prefer_final_locals: true
|
||||
prefer_final_parameters: true
|
||||
avoid_void_async: true
|
||||
require_trailing_commas: true
|
||||
sort_child_properties_last: true
|
||||
sort_constructors_first: true
|
||||
sort_unnamed_constructors_first: true
|
||||
unnecessary_async: true
|
||||
unnecessary_await_in_return: true
|
||||
unnecessary_string_interpolations: true
|
||||
always_declare_return_types: true
|
||||
|
||||
formatter:
|
||||
page_width: 100
|
||||
@@ -1,15 +0,0 @@
|
||||
/// Support for doing something awesome.
|
||||
///
|
||||
/// More dartdocs go here.
|
||||
library;
|
||||
|
||||
export 'src/zcash_balance.dart';
|
||||
export 'src/zcash_mnemonic_is_incorrect_exception.dart';
|
||||
export 'src/zcash_transaction_info.dart';
|
||||
export 'src/zcash_transactions.dart';
|
||||
export 'src/zcash_wallet.dart';
|
||||
export 'src/zcash_wallet_service.dart';
|
||||
export 'src/models.dart';
|
||||
export 'src/zcash_transaction_credentials.dart';
|
||||
export 'src/pending_zcash_transaction.dart';
|
||||
export 'src/zcash_receive_page_options.dart';
|
||||
@@ -1,196 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:zkool/src/rust/api/account.dart' as zkool_account;
|
||||
import 'package:zkool/src/rust/api/coin.dart' as zkool_coin;
|
||||
import 'package:zkool/src/rust/api/sync.dart' as zkool_sync;
|
||||
import 'package:zkool/src/rust/api/pay.dart' as zkool_pay;
|
||||
import 'package:zkool/src/rust/api/key.dart' as zkool_key;
|
||||
import 'package:zkool/src/rust/api/network.dart' as zkool_network;
|
||||
import 'package:zkool/src/rust/pay.dart' as zkool_paydart;
|
||||
import 'package:zkool/src/rust/frb_generated.dart' as zkool_frb;
|
||||
|
||||
class ZkoolSweep {
|
||||
ZkoolSweep({
|
||||
required this.currentBalance,
|
||||
required this.cacheDir,
|
||||
required this.seed,
|
||||
required this.passphrase,
|
||||
required this.address,
|
||||
required this.url,
|
||||
required this.height,
|
||||
});
|
||||
final int currentBalance;
|
||||
final String seed;
|
||||
final String cacheDir;
|
||||
final String passphrase;
|
||||
final String address;
|
||||
final String url;
|
||||
final int height;
|
||||
static SweepUpdate msg = SweepUpdate(message: 'Idling', currentHeight: 0, networkHeight: 0);
|
||||
Future<void> start() async {
|
||||
try {
|
||||
await _init();
|
||||
if (!zkool_key.isValidAddress(address: address)) {
|
||||
msg.message = "$address is not valid";
|
||||
return;
|
||||
}
|
||||
|
||||
msg = SweepUpdate(message: 'Starting import', currentHeight: 0, networkHeight: 0);
|
||||
await _newAccount();
|
||||
msg.message = "Starting sync";
|
||||
await warpSync();
|
||||
msg.message = "Waiting";
|
||||
while (msg.blocksLeft != 0 && msg.networkHeight != 0) {
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
}
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
final balance = await getBalance();
|
||||
if (balance.toInt() == balance) {
|
||||
msg.message = "No need to sweep, balance is the same";
|
||||
return;
|
||||
}
|
||||
msg.message = "Sweeping";
|
||||
await sweep(balance);
|
||||
} catch (e) {
|
||||
msg.message = e.toString();
|
||||
printV("zkool_sweep: $e");
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<BigInt> getBalance() async {
|
||||
final b = await zkool_sync.balance(c: c);
|
||||
return b.field0.reduce((final a, final b) => a + b);
|
||||
}
|
||||
|
||||
Future<void> sweep(final BigInt amount) async {
|
||||
msg.message = "prepare";
|
||||
final tx = await zkool_pay.prepare(
|
||||
recipients: [zkool_paydart.Recipient(address: address, amount: amount)],
|
||||
options: zkool_pay.PaymentOptions(
|
||||
srcPools: 7,
|
||||
recipientPaysFee: true,
|
||||
smartTransparent: false,
|
||||
),
|
||||
c: c,
|
||||
);
|
||||
msg.message = "getLatestHeight";
|
||||
final height = await getLatestHeight();
|
||||
msg.message = "signTransaction";
|
||||
final signTx = await zkool_pay.signTransaction(pczt: tx, c: c);
|
||||
msg.message = "extractTransaction";
|
||||
final txBytes = await zkool_pay.extractTransaction(package: signTx);
|
||||
msg.message = "broadcastTransaction";
|
||||
final result = await zkool_pay.broadcastTransaction(height: height, txBytes: txBytes, c: c);
|
||||
msg.message = "result";
|
||||
if (result.isEmpty) {
|
||||
msg.message = "Unknown error";
|
||||
throw Exception(result);
|
||||
}
|
||||
}
|
||||
|
||||
static var c = zkool_coin.Coin();
|
||||
|
||||
static bool _isInit = false;
|
||||
|
||||
File get dbFile => File(p.join(cacheDir, "zkool-tmp-mirror.db"));
|
||||
|
||||
Future<int> warpSync() async {
|
||||
final currentHeight = await getLatestHeight();
|
||||
msg.networkHeight = currentHeight;
|
||||
final sync = zkool_sync.synchronize(
|
||||
accounts: [currentAccount],
|
||||
currentHeight: currentHeight,
|
||||
actionsPerSync: 10000,
|
||||
transparentLimit: 100,
|
||||
checkpointAge: 200,
|
||||
c: c,
|
||||
);
|
||||
bool success = false;
|
||||
await sync.listen(
|
||||
(final syncProgress) {
|
||||
msg.currentHeight = syncProgress.height;
|
||||
msg.message = "Sync ${syncProgress.height} / ${syncProgress.time}";
|
||||
},
|
||||
onError: (final e) {
|
||||
msg.message = e.toString();
|
||||
},
|
||||
onDone: () {
|
||||
msg.message = "Sync done!";
|
||||
success = true;
|
||||
},
|
||||
);
|
||||
|
||||
if (msg.currentHeight != currentHeight && msg.currentHeight != 0) {
|
||||
msg.message = "Canceling sync";
|
||||
await zkool_sync.cancelSync();
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
return warpSync();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Future<int> getLatestHeight() async {
|
||||
try {
|
||||
return await zkool_network.getCurrentHeight(c: c);
|
||||
} catch (e) {
|
||||
printV("getLatestHeight: $e");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Future<void> _newAccount() async {
|
||||
final id = await zkool_account.newAccount(
|
||||
na: zkool_account.NewAccount(
|
||||
name: 'restoretmp' + DateTime.now().microsecondsSinceEpoch.toString(),
|
||||
restore: true,
|
||||
passphrase: "",
|
||||
key: seed,
|
||||
aindex: 0,
|
||||
birth: height,
|
||||
folder: '',
|
||||
useInternal: true,
|
||||
internal: false,
|
||||
ledger: false,
|
||||
),
|
||||
c: c,
|
||||
);
|
||||
currentAccount = id;
|
||||
c = await c.setAccount(account: id);
|
||||
}
|
||||
|
||||
int currentAccount = 0;
|
||||
|
||||
Future<void> _init() async {
|
||||
if (_isInit) return;
|
||||
_isInit = true;
|
||||
printV(".init()");
|
||||
await zkool_frb.RustLib.init();
|
||||
await zkool_network.initDatadir(directory: dbFile.parent.path);
|
||||
c = await c.openDatabase(dbFilepath: dbFile.path, password: 'cw_zcash_migration');
|
||||
c = c.setLwd(url: url, serverType: 0);
|
||||
printV(".init(): Done");
|
||||
}
|
||||
}
|
||||
|
||||
class SweepUpdate {
|
||||
SweepUpdate({required this.message, required this.currentHeight, required this.networkHeight});
|
||||
String message;
|
||||
int currentHeight;
|
||||
int networkHeight;
|
||||
double get progress {
|
||||
if (networkHeight == 0) return 0.01;
|
||||
return currentHeight / networkHeight;
|
||||
}
|
||||
|
||||
int get blocksLeft => networkHeight - currentHeight;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"message": message,
|
||||
"currentHeight": currentHeight,
|
||||
"networkHeight": networkHeight,
|
||||
"progress": progress,
|
||||
};
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
|
||||
class ZcashNewWalletCredentials extends WalletCredentials {
|
||||
ZcashNewWalletCredentials({
|
||||
required final String name,
|
||||
final String? password,
|
||||
required final String? passphrase,
|
||||
final String? mnemonic,
|
||||
final int? seedPhraseLength,
|
||||
}) : super(
|
||||
name: name,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
seedPhraseLength: seedPhraseLength,
|
||||
) {
|
||||
this.mnemonic = mnemonic;
|
||||
}
|
||||
|
||||
String? mnemonic;
|
||||
}
|
||||
|
||||
class ZcashFromSeedWalletCredentials extends WalletCredentials {
|
||||
ZcashFromSeedWalletCredentials({
|
||||
required final String name,
|
||||
final String? password,
|
||||
required final String? passphrase,
|
||||
required this.seed,
|
||||
required super.height,
|
||||
}) : super(name: name, password: password, passphrase: passphrase);
|
||||
final String? seed;
|
||||
}
|
||||
|
||||
class ZcashFromKeysWalletCredentials extends WalletCredentials {
|
||||
ZcashFromKeysWalletCredentials({
|
||||
required final String name,
|
||||
final String? password,
|
||||
required final int? height,
|
||||
required this.privateKey,
|
||||
}) : super(name: name, password: password, height: height);
|
||||
final String? privateKey;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cw_core/output_info.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_zcash/cw_zcash.dart';
|
||||
import 'package:cw_core/currency_for_wallet_type.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_zcash/src/zcash_taddress_rotation.dart';
|
||||
import 'package:warp_api/data_fb_generated.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
|
||||
class PendingZcashTransaction with PendingTransaction {
|
||||
PendingZcashTransaction({
|
||||
required this.zcashWallet,
|
||||
required this.credentials,
|
||||
required this.txPlan,
|
||||
required this.fee,
|
||||
required this.availableBalance,
|
||||
});
|
||||
|
||||
final ZcashWallet zcashWallet;
|
||||
final ZcashTransactionCredentials credentials;
|
||||
final String txPlan;
|
||||
String? _txId;
|
||||
final int availableBalance;
|
||||
|
||||
@override
|
||||
String get id => _txId ?? '';
|
||||
|
||||
@override
|
||||
String get hex => '';
|
||||
|
||||
@override
|
||||
String get amountFormatted {
|
||||
return walletTypeToCryptoCurrency(WalletType.zcash).formatAmount(BigInt.from(totalAmount));
|
||||
}
|
||||
|
||||
int get totalAmount {
|
||||
final isAll = credentials.outputs.fold<bool>(false, (final a, final b) => a || (b.sendAll));
|
||||
if (isAll) {
|
||||
return availableBalance;
|
||||
}
|
||||
return credentials.outputs.fold<int>(
|
||||
0,
|
||||
(final a, final b) => a + (b.formattedCryptoAmount ?? 0),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get feeFormatted =>
|
||||
'$feeFormattedValue ${walletTypeToCryptoCurrency(WalletType.zcash).title}';
|
||||
|
||||
@override
|
||||
late String feeFormattedValue = walletTypeToCryptoCurrency(
|
||||
WalletType.zcash,
|
||||
).formatAmount(BigInt.from(fee));
|
||||
|
||||
int fee;
|
||||
|
||||
@override
|
||||
Future<void> commit() async {
|
||||
_txId = await ZcashWalletService.runInDbMutex(
|
||||
() => WarpApi.signAndBroadcast(ZcashWalletBase.coin, zcashWallet.accountId, txPlan),
|
||||
);
|
||||
ZcashWalletBase.temporarySentTx[zcashWallet.accountId] ??= [];
|
||||
ZcashWalletBase.temporarySentTx[zcashWallet.accountId]?.add(
|
||||
ShieldedTx(
|
||||
base64.decode(
|
||||
ZcashTaddressRotation.flatBuffersPack(
|
||||
ShieldedTxT(
|
||||
id: Random().nextInt(pow(2, 32).toInt()),
|
||||
txId: _txId,
|
||||
height: 0,
|
||||
timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||
value: -totalAmount,
|
||||
).pack,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await ZcashTransactionInfo.addCachedDestinationAddress(
|
||||
_txId ?? '',
|
||||
credentials.outputs.reduce((final o1, final o2) {
|
||||
return OutputInfo(
|
||||
address: o1.address + "," + o2.address,
|
||||
sendAll: false,
|
||||
isParsedAddress: false,
|
||||
);
|
||||
}).address,
|
||||
);
|
||||
await zcashWallet.updateTransactions();
|
||||
await zcashWallet.updateBalance();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, String>> commitUR() {
|
||||
throw UnimplementedError('UR not supported for Zcash');
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldCommitUR() => false;
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
/// CRC32
|
||||
/// Copyright (C) 2012, Kai Sellgren
|
||||
/// Licensed under the MIT License.
|
||||
/// http://www.opensource.org/licenses/mit-license.php
|
||||
/// source: https://raw.githubusercontent.com/kaisellgren/CRC32/refs/heads/master/lib/crc32.dart
|
||||
// ignore_for_file: parameter_assignments
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
/// Computes Cyclic Redundancy Check values.
|
||||
class CRC32 {
|
||||
/// Computes a CRC32 value for the given input.
|
||||
///
|
||||
/// The return value is an unsigned integer.
|
||||
///
|
||||
/// You may optionally specify the beginning CRC value.
|
||||
static int compute(dynamic input, [int crc = 0]) {
|
||||
if (input == null) throw new ArgumentError.notNull('input');
|
||||
if (input is String) input = utf8.encode(input);
|
||||
|
||||
crc = crc ^ (0xffffffff);
|
||||
|
||||
for (final byte in input) {
|
||||
if (!(byte >= -128 && byte <= 255))
|
||||
throw new FormatException("Invalid value in input: $byte");
|
||||
|
||||
final x = CRC32._table[(crc ^ byte) & 0xff];
|
||||
crc = (crc & 0xffffffff) >> 8; // crc >>> 8 (32-bit unsigned integer)
|
||||
crc ^= x;
|
||||
}
|
||||
|
||||
crc = crc ^ (0xffffffff);
|
||||
|
||||
// Turns the signed integer into an unsigned integer.
|
||||
return crc & 0xffffffff;
|
||||
}
|
||||
|
||||
static const _table = const [
|
||||
0x00000000,
|
||||
0x77073096,
|
||||
0xEE0E612C,
|
||||
0x990951BA,
|
||||
0x076DC419,
|
||||
0x706AF48F,
|
||||
0xE963A535,
|
||||
0x9E6495A3,
|
||||
0x0EDB8832,
|
||||
0x79DCB8A4,
|
||||
0xE0D5E91E,
|
||||
0x97D2D988,
|
||||
0x09B64C2B,
|
||||
0x7EB17CBD,
|
||||
0xE7B82D07,
|
||||
0x90BF1D91,
|
||||
0x1DB71064,
|
||||
0x6AB020F2,
|
||||
0xF3B97148,
|
||||
0x84BE41DE,
|
||||
0x1ADAD47D,
|
||||
0x6DDDE4EB,
|
||||
0xF4D4B551,
|
||||
0x83D385C7,
|
||||
0x136C9856,
|
||||
0x646BA8C0,
|
||||
0xFD62F97A,
|
||||
0x8A65C9EC,
|
||||
0x14015C4F,
|
||||
0x63066CD9,
|
||||
0xFA0F3D63,
|
||||
0x8D080DF5,
|
||||
0x3B6E20C8,
|
||||
0x4C69105E,
|
||||
0xD56041E4,
|
||||
0xA2677172,
|
||||
0x3C03E4D1,
|
||||
0x4B04D447,
|
||||
0xD20D85FD,
|
||||
0xA50AB56B,
|
||||
0x35B5A8FA,
|
||||
0x42B2986C,
|
||||
0xDBBBC9D6,
|
||||
0xACBCF940,
|
||||
0x32D86CE3,
|
||||
0x45DF5C75,
|
||||
0xDCD60DCF,
|
||||
0xABD13D59,
|
||||
0x26D930AC,
|
||||
0x51DE003A,
|
||||
0xC8D75180,
|
||||
0xBFD06116,
|
||||
0x21B4F4B5,
|
||||
0x56B3C423,
|
||||
0xCFBA9599,
|
||||
0xB8BDA50F,
|
||||
0x2802B89E,
|
||||
0x5F058808,
|
||||
0xC60CD9B2,
|
||||
0xB10BE924,
|
||||
0x2F6F7C87,
|
||||
0x58684C11,
|
||||
0xC1611DAB,
|
||||
0xB6662D3D,
|
||||
0x76DC4190,
|
||||
0x01DB7106,
|
||||
0x98D220BC,
|
||||
0xEFD5102A,
|
||||
0x71B18589,
|
||||
0x06B6B51F,
|
||||
0x9FBFE4A5,
|
||||
0xE8B8D433,
|
||||
0x7807C9A2,
|
||||
0x0F00F934,
|
||||
0x9609A88E,
|
||||
0xE10E9818,
|
||||
0x7F6A0DBB,
|
||||
0x086D3D2D,
|
||||
0x91646C97,
|
||||
0xE6635C01,
|
||||
0x6B6B51F4,
|
||||
0x1C6C6162,
|
||||
0x856530D8,
|
||||
0xF262004E,
|
||||
0x6C0695ED,
|
||||
0x1B01A57B,
|
||||
0x8208F4C1,
|
||||
0xF50FC457,
|
||||
0x65B0D9C6,
|
||||
0x12B7E950,
|
||||
0x8BBEB8EA,
|
||||
0xFCB9887C,
|
||||
0x62DD1DDF,
|
||||
0x15DA2D49,
|
||||
0x8CD37CF3,
|
||||
0xFBD44C65,
|
||||
0x4DB26158,
|
||||
0x3AB551CE,
|
||||
0xA3BC0074,
|
||||
0xD4BB30E2,
|
||||
0x4ADFA541,
|
||||
0x3DD895D7,
|
||||
0xA4D1C46D,
|
||||
0xD3D6F4FB,
|
||||
0x4369E96A,
|
||||
0x346ED9FC,
|
||||
0xAD678846,
|
||||
0xDA60B8D0,
|
||||
0x44042D73,
|
||||
0x33031DE5,
|
||||
0xAA0A4C5F,
|
||||
0xDD0D7CC9,
|
||||
0x5005713C,
|
||||
0x270241AA,
|
||||
0xBE0B1010,
|
||||
0xC90C2086,
|
||||
0x5768B525,
|
||||
0x206F85B3,
|
||||
0xB966D409,
|
||||
0xCE61E49F,
|
||||
0x5EDEF90E,
|
||||
0x29D9C998,
|
||||
0xB0D09822,
|
||||
0xC7D7A8B4,
|
||||
0x59B33D17,
|
||||
0x2EB40D81,
|
||||
0xB7BD5C3B,
|
||||
0xC0BA6CAD,
|
||||
0xEDB88320,
|
||||
0x9ABFB3B6,
|
||||
0x03B6E20C,
|
||||
0x74B1D29A,
|
||||
0xEAD54739,
|
||||
0x9DD277AF,
|
||||
0x04DB2615,
|
||||
0x73DC1683,
|
||||
0xE3630B12,
|
||||
0x94643B84,
|
||||
0x0D6D6A3E,
|
||||
0x7A6A5AA8,
|
||||
0xE40ECF0B,
|
||||
0x9309FF9D,
|
||||
0x0A00AE27,
|
||||
0x7D079EB1,
|
||||
0xF00F9344,
|
||||
0x8708A3D2,
|
||||
0x1E01F268,
|
||||
0x6906C2FE,
|
||||
0xF762575D,
|
||||
0x806567CB,
|
||||
0x196C3671,
|
||||
0x6E6B06E7,
|
||||
0xFED41B76,
|
||||
0x89D32BE0,
|
||||
0x10DA7A5A,
|
||||
0x67DD4ACC,
|
||||
0xF9B9DF6F,
|
||||
0x8EBEEFF9,
|
||||
0x17B7BE43,
|
||||
0x60B08ED5,
|
||||
0xD6D6A3E8,
|
||||
0xA1D1937E,
|
||||
0x38D8C2C4,
|
||||
0x4FDFF252,
|
||||
0xD1BB67F1,
|
||||
0xA6BC5767,
|
||||
0x3FB506DD,
|
||||
0x48B2364B,
|
||||
0xD80D2BDA,
|
||||
0xAF0A1B4C,
|
||||
0x36034AF6,
|
||||
0x41047A60,
|
||||
0xDF60EFC3,
|
||||
0xA867DF55,
|
||||
0x316E8EEF,
|
||||
0x4669BE79,
|
||||
0xCB61B38C,
|
||||
0xBC66831A,
|
||||
0x256FD2A0,
|
||||
0x5268E236,
|
||||
0xCC0C7795,
|
||||
0xBB0B4703,
|
||||
0x220216B9,
|
||||
0x5505262F,
|
||||
0xC5BA3BBE,
|
||||
0xB2BD0B28,
|
||||
0x2BB45A92,
|
||||
0x5CB36A04,
|
||||
0xC2D7FFA7,
|
||||
0xB5D0CF31,
|
||||
0x2CD99E8B,
|
||||
0x5BDEAE1D,
|
||||
0x9B64C2B0,
|
||||
0xEC63F226,
|
||||
0x756AA39C,
|
||||
0x026D930A,
|
||||
0x9C0906A9,
|
||||
0xEB0E363F,
|
||||
0x72076785,
|
||||
0x05005713,
|
||||
0x95BF4A82,
|
||||
0xE2B87A14,
|
||||
0x7BB12BAE,
|
||||
0x0CB61B38,
|
||||
0x92D28E9B,
|
||||
0xE5D5BE0D,
|
||||
0x7CDCEFB7,
|
||||
0x0BDBDF21,
|
||||
0x86D3D2D4,
|
||||
0xF1D4E242,
|
||||
0x68DDB3F8,
|
||||
0x1FDA836E,
|
||||
0x81BE16CD,
|
||||
0xF6B9265B,
|
||||
0x6FB077E1,
|
||||
0x18B74777,
|
||||
0x88085AE6,
|
||||
0xFF0F6A70,
|
||||
0x66063BCA,
|
||||
0x11010B5C,
|
||||
0x8F659EFF,
|
||||
0xF862AE69,
|
||||
0x616BFFD3,
|
||||
0x166CCF45,
|
||||
0xA00AE278,
|
||||
0xD70DD2EE,
|
||||
0x4E048354,
|
||||
0x3903B3C2,
|
||||
0xA7672661,
|
||||
0xD06016F7,
|
||||
0x4969474D,
|
||||
0x3E6E77DB,
|
||||
0xAED16A4A,
|
||||
0xD9D65ADC,
|
||||
0x40DF0B66,
|
||||
0x37D83BF0,
|
||||
0xA9BCAE53,
|
||||
0xDEBB9EC5,
|
||||
0x47B2CF7F,
|
||||
0x30B5FFE9,
|
||||
0xBDBDF21C,
|
||||
0xCABAC28A,
|
||||
0x53B39330,
|
||||
0x24B4A3A6,
|
||||
0xBAD03605,
|
||||
0xCDD70693,
|
||||
0x54DE5729,
|
||||
0x23D967BF,
|
||||
0xB3667A2E,
|
||||
0xC4614AB8,
|
||||
0x5D681B02,
|
||||
0x2A6F2B94,
|
||||
0xB40BBE37,
|
||||
0xC30C8EA1,
|
||||
0x5A05DF1B,
|
||||
0x2D02EF8D,
|
||||
];
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class ZcashBalance extends Balance {
|
||||
ZcashBalance({required this.confirmed, required this.unconfirmed, required final int frozen})
|
||||
: _frozen = frozen,
|
||||
super.fromInt(confirmed, unconfirmed);
|
||||
|
||||
factory ZcashBalance.zero() => ZcashBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
|
||||
|
||||
final int confirmed;
|
||||
final int unconfirmed;
|
||||
final int _frozen;
|
||||
BigInt get frozen => BigInt.from(_frozen);
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance {
|
||||
return CryptoCurrency.zec.formatAmount(BigInt.from(confirmed));
|
||||
}
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance {
|
||||
if (unconfirmed == 0) return '0.0';
|
||||
return CryptoCurrency.zec.formatAmount(BigInt.from(unconfirmed));
|
||||
}
|
||||
|
||||
@override
|
||||
String get formattedUnAvailableBalance {
|
||||
if (frozen == 0) return '';
|
||||
return CryptoCurrency.zec.formatAmount(BigInt.from(_frozen));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
class ZcashMnemonicIsIncorrectException implements Exception {
|
||||
@override
|
||||
String toString() =>
|
||||
'Zcash mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.';
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
|
||||
enum ZcashAddressType {
|
||||
transparent,
|
||||
transparentRotated,
|
||||
shieldedSapling,
|
||||
shieldedOrchard,
|
||||
unifiedType,
|
||||
}
|
||||
|
||||
class ZcashReceivePageOption implements ReceivePageOption {
|
||||
factory ZcashReceivePageOption.fromType(final ZcashAddressType type) {
|
||||
switch (type) {
|
||||
case ZcashAddressType.transparent:
|
||||
return transparent;
|
||||
case ZcashAddressType.transparentRotated:
|
||||
return transparentRotated;
|
||||
case ZcashAddressType.shieldedSapling:
|
||||
return shieldedSapling;
|
||||
case ZcashAddressType.shieldedOrchard:
|
||||
return shieldedOrchard;
|
||||
case ZcashAddressType.unifiedType:
|
||||
return unified;
|
||||
}
|
||||
}
|
||||
const ZcashReceivePageOption._(
|
||||
this.type,
|
||||
this.value, {
|
||||
this.iconPath,
|
||||
this.description,
|
||||
this.isCommon = false,
|
||||
});
|
||||
|
||||
final String value;
|
||||
final String? iconPath;
|
||||
final String? description;
|
||||
final bool isCommon;
|
||||
final bool addAddressWord = false;
|
||||
|
||||
static const transparent = ZcashReceivePageOption._(
|
||||
ZcashAddressType.transparent,
|
||||
"Public",
|
||||
description: "Static & Transparent",
|
||||
iconPath: "assets/new-ui/address-type-picker-icons/zec/public.svg",
|
||||
);
|
||||
static const transparentRotated = ZcashReceivePageOption._(
|
||||
ZcashAddressType.transparentRotated,
|
||||
"Transparent",
|
||||
description: "Disposable",
|
||||
iconPath: "assets/new-ui/address-type-picker-icons/zec/transparent.svg",
|
||||
isCommon: true,
|
||||
);
|
||||
static const shieldedSapling = ZcashReceivePageOption._(
|
||||
ZcashAddressType.shieldedSapling,
|
||||
"Legacy Shielded",
|
||||
description: "Sapling",
|
||||
iconPath: "assets/new-ui/address-type-picker-icons/zec/sapling.svg",
|
||||
);
|
||||
static const shieldedOrchard = ZcashReceivePageOption._(
|
||||
ZcashAddressType.shieldedOrchard,
|
||||
"Shielded",
|
||||
description: "Default (Orchard)",
|
||||
iconPath: "assets/new-ui/address-type-picker-icons/zec/shielded.svg",
|
||||
isCommon: true,
|
||||
);
|
||||
static const unified = ZcashReceivePageOption._(
|
||||
ZcashAddressType.unifiedType,
|
||||
"Unified",
|
||||
description: "Compatible Shielded",
|
||||
iconPath: "assets/new-ui/address-type-picker-icons/zec/unified.svg",
|
||||
isCommon: true,
|
||||
);
|
||||
|
||||
final ZcashAddressType type;
|
||||
|
||||
String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
static const all = [
|
||||
ZcashReceivePageOption.shieldedOrchard,
|
||||
ZcashReceivePageOption.shieldedSapling,
|
||||
ZcashReceivePageOption.unified,
|
||||
ZcashReceivePageOption.transparentRotated,
|
||||
ZcashReceivePageOption.transparent,
|
||||
];
|
||||
|
||||
ZcashAddressType toType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
static ZcashAddressType typeFromString(final String str) {
|
||||
for (int i = 0; i < ZcashAddressType.values.length; i++) {
|
||||
if (str == ZcashAddressType.values[i].toString()) {
|
||||
return ZcashAddressType.values[i];
|
||||
}
|
||||
}
|
||||
printV("Not found for: $str");
|
||||
return ZcashAddressType.shieldedOrchard;
|
||||
}
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
// create offset wallets for T address rotation.
|
||||
// Each address is considered one time use, if it receives less than 15000 zatoshi balance will be essentially burned.
|
||||
//
|
||||
// This class takes address index as constructor, and will create 10 addresses by default, if any of the addresses gets used
|
||||
// it will be moved out of the pool
|
||||
//
|
||||
// T addresses are generated by creating new wallets with an extra seed word (or appending to "passphrase") the following
|
||||
// :tgen:${CRC32(seed)}
|
||||
// It is highly unlikely for users to create a wallet with that specific last word and add index to it
|
||||
// We could leverage other fields such as native account index alone, but users may want to set that in future
|
||||
// This solution is rather simple and if standard would get estabilished for this purpose it can be easily
|
||||
// turned off and replaced with proper solution.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_zcash/src/util/crc32.dart';
|
||||
import 'package:cw_zcash/src/zcash_wallet.dart';
|
||||
import 'package:cw_zcash/src/zcash_wallet_service.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:warp_api/data_fb_generated.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class ZcashTaddressRotation {
|
||||
ZcashTaddressRotation(this.accountIndex);
|
||||
final int accountIndex;
|
||||
|
||||
static bool _isStarted = false;
|
||||
|
||||
static const coin = ZcashWalletBase.coin;
|
||||
static String seedForOffset(final String seed) {
|
||||
final seedWords = seed.split(" ");
|
||||
if ([12, 24].contains(seedWords.length)) {
|
||||
seedWords.add("");
|
||||
}
|
||||
final lastI = seedWords.length - 1;
|
||||
final crc = CRC32.compute(seed);
|
||||
seedWords[lastI] += ":tgen:${crc}";
|
||||
return seedWords.join(" ");
|
||||
}
|
||||
|
||||
static bool isSeedForWallet(final String? mainWallet, final String? subWallet) {
|
||||
if (mainWallet == null || subWallet == null) return false;
|
||||
return seedForOffset(mainWallet.trim()) == subWallet;
|
||||
}
|
||||
|
||||
static Map<int, List<Account>> rotationAccounts = {};
|
||||
static Map<int, List<Account>> rotationAccountsUsable = {};
|
||||
static Map<int, List<ShieldedTx>> shieldedAccountsTx = {};
|
||||
static Future<void> init() async {
|
||||
printV("Deserializing previous state");
|
||||
if (_isStarted) {
|
||||
return;
|
||||
}
|
||||
_isStarted = true;
|
||||
final pfw = await pathForWalletTypeDir(type: WalletType.zcash);
|
||||
try {
|
||||
final f = File(p.join(pfw, "zec-taddr.json"));
|
||||
if (!f.existsSync()) {
|
||||
f.writeAsBytesSync(serialize());
|
||||
}
|
||||
deserialize(f.readAsBytesSync());
|
||||
} catch (e) {
|
||||
printV("Failed to deserialize T address DB for zcash, it doesn't really matter: $e");
|
||||
}
|
||||
|
||||
unawaited(
|
||||
(() async {
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
return _jobRunner();
|
||||
})(),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> serializeToFile() async {
|
||||
final pfw = await pathForWalletTypeDir(type: WalletType.zcash);
|
||||
final f = File(p.join(pfw, "zec-taddr.json"));
|
||||
f.writeAsBytesSync(serialize());
|
||||
}
|
||||
|
||||
static Uint8List serialize() {
|
||||
final data = {
|
||||
"rotationAccounts": rotationAccounts.map(
|
||||
(final k, final v) => MapEntry(
|
||||
k.toRadixString(16),
|
||||
v.map((final a) => flatBuffersPack(a.unpack().pack)).toList(),
|
||||
),
|
||||
),
|
||||
if (kDebugMode)
|
||||
"_rotationAccounts": rotationAccounts.map(
|
||||
(final k, final v) =>
|
||||
MapEntry(k.toRadixString(16), v.map((final a) => a.toString()).toList()),
|
||||
),
|
||||
"rotationAccountsUsable": rotationAccountsUsable.map(
|
||||
(final k, final v) => MapEntry(
|
||||
k.toRadixString(16),
|
||||
v.map((final a) => flatBuffersPack(a.unpack().pack)).toList(),
|
||||
),
|
||||
),
|
||||
if (kDebugMode)
|
||||
"_rotationAccountsUsable": rotationAccountsUsable.map(
|
||||
(final k, final v) =>
|
||||
MapEntry(k.toRadixString(16), v.map((final a) => a.toString()).toList()),
|
||||
),
|
||||
"shieldedAccountsTx": shieldedAccountsTx.map(
|
||||
(final k, final v) => MapEntry(
|
||||
k.toRadixString(16),
|
||||
v.map((final a) => flatBuffersPack(a.unpack().pack)).toList(),
|
||||
),
|
||||
),
|
||||
if (kDebugMode)
|
||||
"_shieldedAccountsTx": shieldedAccountsTx.map(
|
||||
(final k, final v) =>
|
||||
MapEntry(k.toRadixString(16), v.map((final a) => a.toString()).toList()),
|
||||
),
|
||||
};
|
||||
|
||||
if (kDebugMode) {
|
||||
return utf8.encode(JsonEncoder.withIndent(" ").convert(data));
|
||||
}
|
||||
return utf8.encode(jsonEncode(data));
|
||||
}
|
||||
|
||||
static String flatBuffersPack(final int Function(fb.Builder fbBuilder) pack) {
|
||||
final fbBuilder = fb.Builder();
|
||||
final offset = pack(fbBuilder);
|
||||
fbBuilder.finish(offset);
|
||||
return base64.encode(fbBuilder.buffer);
|
||||
}
|
||||
|
||||
static void deserialize(final Uint8List bytes) {
|
||||
// todo: replace keys with sums and reverse in serialize
|
||||
// final List<String> seeds = [];
|
||||
// for (int i = 0; i < accounts.length; i++) {
|
||||
// final acc = accounts[i];
|
||||
// final backup = WarpApi.getBackup(coin, acc.id);
|
||||
// await WarpApi.transparentSync(coin, acc.id, syncHeight);
|
||||
// seeds.add(backup.seed!);
|
||||
// }
|
||||
try {
|
||||
final Map<dynamic, dynamic> data = jsonDecode(utf8.decode(bytes));
|
||||
rotationAccounts = (data["rotationAccounts"] as Map<String, dynamic>).map(
|
||||
(final k, final v) => MapEntry(
|
||||
int.parse(k, radix: 16),
|
||||
(v as List).map((final a) => Account(atob(a))).toList(),
|
||||
),
|
||||
);
|
||||
rotationAccountsUsable = (data["rotationAccountsUsable"] as Map<String, dynamic>).map(
|
||||
(final k, final v) => MapEntry(
|
||||
int.parse(k, radix: 16),
|
||||
(v as List).map((final a) => Account(atob(a))).toList(),
|
||||
),
|
||||
);
|
||||
shieldedAccountsTx = (data["shieldedAccountsTx"] as Map<String, dynamic>).map(
|
||||
(final k, final v) => MapEntry(
|
||||
int.parse(k, radix: 16),
|
||||
(v as List).map((final a) => ShieldedTx(atob(a))).toList(),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8List atob(final String value) =>
|
||||
Uint8List.fromList(List<int>.from(base64.decode(value)));
|
||||
|
||||
static Future<void> createAndSweepTAddresses() async {
|
||||
int chainHeight = 0;
|
||||
try {
|
||||
chainHeight = await WarpApi.getLatestHeight(coin);
|
||||
} catch (e) {
|
||||
printV("Error getting latest height: $e");
|
||||
}
|
||||
final dbHeight = WarpApi.getDbHeight(coin);
|
||||
final height = dbHeight.unpack();
|
||||
final syncHeight = height.height;
|
||||
if (chainHeight != syncHeight) {
|
||||
printV(
|
||||
"Waiting for sync to finish: chainHeight(${chainHeight}) != syncHeight(${syncHeight})",
|
||||
);
|
||||
return;
|
||||
}
|
||||
final Map<int, List<ShieldedTx>> newShieldedAccountsTx = {};
|
||||
final accounts = WarpApi.getAccountList(coin);
|
||||
if (accounts.isEmpty) return;
|
||||
final Map<int, String> seeds = {};
|
||||
for (int i = 0; i < accounts.length; i++) {
|
||||
final acc = accounts[i];
|
||||
final backup = WarpApi.getBackup(coin, acc.id);
|
||||
await WarpApi.transparentSync(coin, acc.id, syncHeight);
|
||||
if (backup.seed == null) continue;
|
||||
seeds[acc.id] = backup.seed!;
|
||||
}
|
||||
for (int i = 0; i < accounts.length; i++) {
|
||||
final seed = seeds[accounts[i].id]!;
|
||||
if ([12, 13, 24, 25].contains(seed.split(" ").length)) {
|
||||
if (seed.split(" ").last.contains(":tgen:")) continue;
|
||||
rotationAccounts[accounts[i].id] = [];
|
||||
}
|
||||
}
|
||||
final raKeys = rotationAccounts.keys.toList();
|
||||
seeds.removeWhere((_, final val) => raKeys.contains(val));
|
||||
printV("raKeys: ${raKeys.length}");
|
||||
for (int i = 0; i < raKeys.length; i++) {
|
||||
final accs = accounts.where((final a) {
|
||||
final seed = WarpApi.getBackup(coin, a.id).seed;
|
||||
return isSeedForWallet(seeds[raKeys[i]], seed);
|
||||
}).toList();
|
||||
rotationAccounts[raKeys[i]]!.addAll(accs);
|
||||
final acc = accountForSeed(seeds[raKeys[i]]!)!;
|
||||
final txs = WarpApi.getTxsSync(coin, acc.id);
|
||||
newShieldedAccountsTx[acc.id] ??= [];
|
||||
newShieldedAccountsTx[acc.id]!.addAll(txs);
|
||||
}
|
||||
rotationAccountsUsable = rotationAccounts.map((final k, final v) => MapEntry(k, v.toList()));
|
||||
printV("rotationAccounts: ${rotationAccounts.length}");
|
||||
|
||||
for (int i = 0; i < raKeys.length; i++) {
|
||||
final acc = accountForSeed(seeds[raKeys[i]]!)!;
|
||||
newShieldedAccountsTx[acc.id] = [];
|
||||
for (int j = 0; j < (rotationAccounts[raKeys[i]]?.length ?? 0); j++) {
|
||||
final txs = WarpApi.getTxsSync(coin, rotationAccounts[raKeys[i]]![j].id);
|
||||
rotationAccounts[raKeys[i]]![j];
|
||||
newShieldedAccountsTx[acc.id]!.addAll(txs);
|
||||
}
|
||||
rotationAccountsUsable[raKeys[i]]!.removeWhere((final a) {
|
||||
final txs = WarpApi.getTxsSync(coin, a.id);
|
||||
return txs.isNotEmpty;
|
||||
});
|
||||
|
||||
// remove hidden addresses
|
||||
final wis = await WalletInfo.selectList('type = ?', [WalletType.zcash.index]);
|
||||
|
||||
final List<String> hiddenAddresses_ = [];
|
||||
for (int k = 0; k < wis.length; k++) {
|
||||
final addrs = await wis[k].getHiddenAddresses();
|
||||
final addr2 = await wis[k].getUsedAddresses();
|
||||
hiddenAddresses_.addAll(addrs);
|
||||
hiddenAddresses_.addAll(addr2);
|
||||
}
|
||||
final Set<String> hiddenAddresses = hiddenAddresses_.toSet();
|
||||
rotationAccountsUsable[raKeys[i]]!.removeWhere((final a) {
|
||||
return hiddenAddresses.contains(WarpApi.getTAddr(coin, a.id));
|
||||
});
|
||||
}
|
||||
printV("rotationAccountsUsable: ${rotationAccountsUsable.length}");
|
||||
|
||||
bool didAddNewAccount = false;
|
||||
for (int i = 0; i < raKeys.length; i++) {
|
||||
if (rotationAccountsUsable[raKeys[i]]!.length < 5) {
|
||||
final seed = seedForOffset(seeds[raKeys[i]]!);
|
||||
final name = CRC32.compute(raKeys[i].toString()).toString();
|
||||
final id = await ZcashWalletService.runInDbMutex(
|
||||
() => WarpApi.newAccount(coin, name, seed, rotationAccounts[raKeys[i]]!.length),
|
||||
);
|
||||
printV("new id: $id / $seed");
|
||||
printV("${rotationAccounts[raKeys[i]]}");
|
||||
printV(raKeys[i]);
|
||||
rotationAccounts[raKeys[i]]!.forEach((final a) {
|
||||
final b = WarpApi.getBackup(coin, a.id);
|
||||
printV("${a.id}");
|
||||
});
|
||||
didAddNewAccount = true;
|
||||
}
|
||||
}
|
||||
printV("didAddNewAccount: ${didAddNewAccount}");
|
||||
if (didAddNewAccount) {
|
||||
return createAndSweepTAddresses();
|
||||
}
|
||||
|
||||
for (var i = 0; i < raKeys.length; i++) {
|
||||
final accs = rotationAccounts[raKeys[i]]!;
|
||||
inner:
|
||||
for (var j = 0; j < accs.length; j++) {
|
||||
int bal = 0;
|
||||
try {
|
||||
bal += await WarpApi.getTBalance(coin, accs[j].id);
|
||||
} catch (e) {
|
||||
printV("getTBalance: $e");
|
||||
return;
|
||||
}
|
||||
if (bal < 30000) continue inner;
|
||||
final to = accountForSeed(seeds[raKeys[i]]!)!;
|
||||
// final toAddress = WarpApi.getTAddr(coin, to.id);
|
||||
// final fromSeed = WarpApi.getBackup(coin, to.id);
|
||||
// final txId = await ZcashWalletService.runInDbMutex(
|
||||
// () => WarpApi.sweepTransparentSeed(
|
||||
// to.coin,
|
||||
// to.id,
|
||||
// chainHeight,
|
||||
// fromSeed.seed!,
|
||||
// 7,
|
||||
// toAddress,
|
||||
// 0,
|
||||
// 1,
|
||||
// FeeT(fee: 10000, minFee: 0, maxFee: 0, scheme: 0),
|
||||
// ),
|
||||
// );
|
||||
final recipientBuilder = RecipientObjectBuilder(
|
||||
address: WarpApi.getAddress(coin, to.id, 4),
|
||||
pools: 4,
|
||||
feeIncluded: true,
|
||||
amount: bal,
|
||||
);
|
||||
|
||||
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,
|
||||
accs[j].id,
|
||||
[recipient],
|
||||
3, // pools: (Transparent + Sapling)
|
||||
1,
|
||||
0, // anchorOffset
|
||||
fee,
|
||||
),
|
||||
);
|
||||
final _txId = await ZcashWalletService.runInDbMutex(
|
||||
() => WarpApi.signAndBroadcast(ZcashWalletBase.coin, accs[j].id, txPlan),
|
||||
);
|
||||
await ZcashWalletService.addShieldedTx(_txId);
|
||||
printV("shielded: $_txId");
|
||||
|
||||
await Future.delayed(Duration(seconds: 120)); // let it be
|
||||
return createAndSweepTAddresses();
|
||||
}
|
||||
}
|
||||
final nsatKeys = newShieldedAccountsTx.keys.toList();
|
||||
for (int i = 0; i < nsatKeys.length; i++) {
|
||||
inner:
|
||||
for (int j = 0; j < newShieldedAccountsTx[nsatKeys[i]]!.length; j++) {
|
||||
final tx = newShieldedAccountsTx[nsatKeys[i]]?[j];
|
||||
if (tx == null) {
|
||||
continue inner;
|
||||
}
|
||||
final _txId = tx.txId;
|
||||
if (_txId == null) {
|
||||
continue inner;
|
||||
}
|
||||
if (tx.value < 0) {
|
||||
await ZcashWalletService.addShieldedTx(_txId);
|
||||
// continue inner;
|
||||
}
|
||||
if (ZcashWalletService.autoshieldTx.contains(_txId)) {
|
||||
continue inner;
|
||||
}
|
||||
}
|
||||
}
|
||||
shieldedAccountsTx = newShieldedAccountsTx.map((final k, final v) => MapEntry(k, v.toList()));
|
||||
await serializeToFile();
|
||||
return;
|
||||
}
|
||||
|
||||
static ShieldedTx reverseAmount(final ShieldedTx t) {
|
||||
final tt = t.unpack();
|
||||
tt.value = -tt.value;
|
||||
return ShieldedTx(base64.decode(flatBuffersPack(tt.pack)));
|
||||
}
|
||||
|
||||
static Account? accountForSeed(final String seed) {
|
||||
final accounts = WarpApi.getAccountList(coin);
|
||||
if (accounts.isEmpty) return null;
|
||||
for (int i = 0; i < accounts.length; i++) {
|
||||
final acc = accounts[i];
|
||||
final backup = WarpApi.getBackup(coin, acc.id);
|
||||
if (backup.seed == seed) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<void> _jobRunner() async {
|
||||
for (;;) {
|
||||
try {
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
await createAndSweepTAddresses();
|
||||
} catch (e, s) {
|
||||
printV(e);
|
||||
s.toString().split("\n").forEach(printV);
|
||||
rethrow;
|
||||
} finally {
|
||||
await Future.delayed(Duration(seconds: 30));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String? addressForAccount(final int accountId, final Set<String>? hiddenAddresses) {
|
||||
final accs = rotationAccountsUsable[accountId] ?? [];
|
||||
for (int i = 0; i < accs.length; i++) {
|
||||
final addr = WarpApi.getTAddr(coin, accs[i].id);
|
||||
if (hiddenAddresses?.contains(addr) == true) {
|
||||
continue;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<String>? allAddressesForAccount(final int accountId) {
|
||||
final acc = rotationAccounts[accountId];
|
||||
if (acc == null) {
|
||||
printV("Nothing found");
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < acc.length; i++) {
|
||||
final b = WarpApi.getBackup(coin, acc[i].id);
|
||||
printV("$i. ${b.seed?.split(" ").last}, ${b.index}, ${WarpApi.getTAddr(coin, acc[i].id)}");
|
||||
}
|
||||
return acc.map((final a) => WarpApi.getTAddr(coin, a.id)).toList();
|
||||
}
|
||||
|
||||
static List<String>? allUsedAddressesForAccount(final int accountId) {
|
||||
final seed = WarpApi.getBackup(coin, accountId).seed;
|
||||
if (seed == null) return [];
|
||||
final acc = rotationAccounts[seed]?.toList();
|
||||
if (acc == null) {
|
||||
printV("Nothing found");
|
||||
return null;
|
||||
}
|
||||
acc.removeWhere((final a1) {
|
||||
for (int i = 0; i < (rotationAccountsUsable[seed]?.length ?? 0); i++) {
|
||||
if (rotationAccountsUsable[seed]?[i].id == a1.id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
for (int i = 0; i < acc.length; i++) {
|
||||
final b = WarpApi.getBackup(coin, acc[i].id);
|
||||
printV("$i. ${b.seed?.split(" ").last}, ${b.index}, ${WarpApi.getTAddr(coin, acc[i].id)}");
|
||||
}
|
||||
return acc.map((final a) => WarpApi.getTAddr(coin, a.id)).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
import 'package:cw_core/output_info.dart';
|
||||
|
||||
class ZcashTransactionCredentials {
|
||||
ZcashTransactionCredentials({
|
||||
required this.outputs,
|
||||
required this.priority,
|
||||
required this.currency,
|
||||
});
|
||||
|
||||
final List<OutputInfo> outputs;
|
||||
final MoneroTransactionPriority priority;
|
||||
final CryptoCurrency currency;
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/currency_for_wallet_type.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/format_amount.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_zcash/cw_zcash.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class ZcashTransactionInfo extends TransactionInfo {
|
||||
ZcashTransactionInfo({
|
||||
required final String id,
|
||||
required final int amount,
|
||||
required final int fee,
|
||||
required final TransactionDirection direction,
|
||||
required final bool isPending,
|
||||
required final DateTime date,
|
||||
required final int height,
|
||||
required final int confirmations,
|
||||
required final String to,
|
||||
final String? memo,
|
||||
}) {
|
||||
this.id = id;
|
||||
this.amount = amount;
|
||||
this.fee = fee;
|
||||
this.height = height;
|
||||
this.direction = direction;
|
||||
this.date = date;
|
||||
this.isPending = isPending;
|
||||
this.confirmations = confirmations;
|
||||
this.to = getCachedDestinationAddress(id);
|
||||
if (memo != null && memo.isNotEmpty) {
|
||||
additionalInfo['memo'] = memo;
|
||||
}
|
||||
additionalInfo['autoShield'] = false;
|
||||
// note: this won't work yet, fee is not in zcash_lib metadata,
|
||||
// leaving here so it can start working automagically in future
|
||||
if (amount == fee && to.startsWith("u")) {
|
||||
additionalInfo['autoShield'] = true;
|
||||
}
|
||||
// remove below when above starts working
|
||||
additionalInfo['autoShield'] = ZcashWalletService.autoshieldTx.contains(txHash);
|
||||
// --- == === cut here === == ---
|
||||
if (additionalInfo['autoShield'] == true) {
|
||||
additionalInfo['memo'] ??= '';
|
||||
additionalInfo['memo'] += '\This is an auto-shielding transaction. Enjoy default privacy!';
|
||||
additionalInfo['memo'] = additionalInfo['memo'].trim();
|
||||
}
|
||||
}
|
||||
|
||||
String? _fiatAmount;
|
||||
|
||||
@override
|
||||
String amountFormatted() =>
|
||||
'${walletTypeToCryptoCurrency(WalletType.zcash).formatAmount(BigInt.from(amount))} ${walletTypeToCryptoCurrency(WalletType.zcash).title}';
|
||||
|
||||
@override
|
||||
String? feeFormatted() {
|
||||
if (fee == null || fee == 0) return null;
|
||||
return '${walletTypeToCryptoCurrency(WalletType.zcash).formatAmount(BigInt.from(fee!))} ${walletTypeToCryptoCurrency(WalletType.zcash).title}';
|
||||
}
|
||||
|
||||
@override
|
||||
String fiatAmount() => _fiatAmount ?? '';
|
||||
|
||||
@override
|
||||
void changeFiatAmount(final String amount) => _fiatAmount = formatAmount(amount);
|
||||
|
||||
String? get memo => additionalInfo['memo'] as String?;
|
||||
|
||||
static final Map<String, String> _destinationAddressMap = {};
|
||||
|
||||
static String? getCachedDestinationAddress(final String txId) {
|
||||
return _destinationAddressMap[txId] ??
|
||||
_destinationAddressMap['"$txId"'] ??
|
||||
_destinationAddressMap[txId.replaceAll('"', '')];
|
||||
}
|
||||
|
||||
static Future<void> addCachedDestinationAddress(final String txId, final String address) async {
|
||||
_destinationAddressMap[txId] = address;
|
||||
final pfwt = await pathForWalletTypeDir(type: WalletType.zcash);
|
||||
final f = File(p.join(pfwt, "sent-tx-map.json"));
|
||||
f.writeAsStringSync(json.encode(_destinationAddressMap));
|
||||
}
|
||||
|
||||
static Future<void> init() async {
|
||||
try {
|
||||
final pfwt = await pathForWalletTypeDir(type: WalletType.zcash);
|
||||
final f = File(p.join(pfwt, "sent-tx-map.json"));
|
||||
if (!f.existsSync()) {
|
||||
f.writeAsStringSync('{}');
|
||||
}
|
||||
final tmpMap = json.decode(f.readAsStringSync());
|
||||
tmpMap.forEach((final k, final v) {
|
||||
_destinationAddressMap[k.toString()] = v.toString();
|
||||
});
|
||||
} catch (e, s) {
|
||||
printV("failed to deserialize: $e, $s");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
|
||||
class ZcashTransactionHistory extends TransactionHistoryBase<TransactionInfo> {
|
||||
ZcashTransactionHistory() {
|
||||
transactions = ObservableMap<String, TransactionInfo>();
|
||||
}
|
||||
|
||||
@override
|
||||
void addMany(final Map<String, TransactionInfo> txs) {
|
||||
transactions.addAll(txs);
|
||||
}
|
||||
|
||||
@override
|
||||
void addOne(final TransactionInfo txs) {
|
||||
transactions[txs.txHash] = txs;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> save() async {
|
||||
// No need to save anything, backend is taking care of that
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,247 +0,0 @@
|
||||
import 'package:cw_core/payment_uris.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_addresses.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_zcash/cw_zcash.dart';
|
||||
import 'package:cw_zcash/src/zcash_taddress_rotation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
|
||||
part 'zcash_wallet_addresses.g.dart';
|
||||
|
||||
class ZcashWalletAddresses = ZcashWalletAddressesBase with _$ZcashWalletAddresses;
|
||||
|
||||
abstract class ZcashWalletAddressesBase extends WalletAddresses with Store {
|
||||
ZcashWalletAddressesBase(this.accountId, final WalletInfo walletInfo) : super(walletInfo) {
|
||||
addressPageType = ZcashReceivePageOption.typeFromString(walletInfo.addressPageType ?? "");
|
||||
}
|
||||
|
||||
final int accountId;
|
||||
|
||||
static const int transparentType = 0;
|
||||
static const int shieldedSaplingType = 1;
|
||||
static const int shieldedOrchardType = 2;
|
||||
static const int unifiedType = 3;
|
||||
|
||||
String? _transparentAddress;
|
||||
String? _saplingAddress;
|
||||
String? _orchardAddress;
|
||||
String? _unifiedAddress;
|
||||
|
||||
@override
|
||||
@computed
|
||||
String get latestAddress {
|
||||
switch (addressPageType) {
|
||||
case ZcashAddressType.transparent:
|
||||
return transparentAddress;
|
||||
case ZcashAddressType.transparentRotated:
|
||||
// just to display something, after the wallet is synced the address
|
||||
// will start rotating, and since we can't rotate address until the wallet syncs
|
||||
// we can't know if some T address already got used, so we would still default to
|
||||
// the same address.
|
||||
// So.. we can
|
||||
// 1) display placeholder text (looks ugly)
|
||||
// 2) display static address
|
||||
// 3) display first address from rotated pool which is also static until synced
|
||||
// 2 seems like an obvious winner simply because it offers little to no benefit over 3
|
||||
// and is noticably less complex in implementation
|
||||
return transparentAddressRotated ?? transparentAddress;
|
||||
case ZcashAddressType.shieldedSapling:
|
||||
return saplingAddress;
|
||||
case ZcashAddressType.shieldedOrchard:
|
||||
return orchardAddress;
|
||||
case ZcashAddressType.unifiedType:
|
||||
if (_unifiedAddress == null) {
|
||||
_unifiedAddress = WarpApi.getAddress(ZcashWalletBase.coin, accountId, 6);
|
||||
}
|
||||
return _unifiedAddress ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
@observable
|
||||
ZcashAddressType? _addressPageType;
|
||||
|
||||
@computed
|
||||
ZcashAddressType get addressPageType => _addressPageType ?? ZcashAddressType.shieldedOrchard;
|
||||
|
||||
@computed
|
||||
set addressPageType(final ZcashAddressType newZat) {
|
||||
_addressPageType = newZat;
|
||||
init();
|
||||
address = latestAddress;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> setAddressType(final ZcashAddressType type) async {
|
||||
addressPageType = ZcashReceivePageOption.typeFromString(type.toString());
|
||||
walletInfo.addressPageType = type.toString();
|
||||
await walletInfo.save();
|
||||
}
|
||||
|
||||
String get transparentAddress {
|
||||
try {
|
||||
if (_transparentAddress == null) {
|
||||
_transparentAddress = WarpApi.getTAddr(ZcashWalletBase.coin, accountId);
|
||||
}
|
||||
return _transparentAddress ?? "";
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
String? get transparentAddressRotated {
|
||||
try {
|
||||
return ZcashTaddressRotation.addressForAccount(accountId, hiddenAddresses);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String get saplingAddress {
|
||||
try {
|
||||
if (_saplingAddress == null) {
|
||||
_saplingAddress = WarpApi.getAddress(ZcashWalletBase.coin, accountId, 2);
|
||||
}
|
||||
return _saplingAddress ?? "";
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
String get orchardAddress {
|
||||
try {
|
||||
if (_orchardAddress == null) {
|
||||
_orchardAddress = WarpApi.getAddress(ZcashWalletBase.coin, accountId, 4);
|
||||
}
|
||||
return _orchardAddress ?? "";
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@computed
|
||||
String get addressForExchange => transparentAddressRotated ?? transparentAddress;
|
||||
|
||||
@override
|
||||
@computed
|
||||
String get addressForBuy => transparentAddressRotated ?? transparentAddress;
|
||||
|
||||
@override
|
||||
bool containsAddress(final String address) {
|
||||
return this.address == address || addressesMap.values.contains(address);
|
||||
}
|
||||
|
||||
static int get coin => ZcashWalletBase.coin;
|
||||
|
||||
@override
|
||||
@observable
|
||||
Set<String> hiddenAddresses = {};
|
||||
|
||||
Future<void> _initAddresses() async {
|
||||
addressesMap = await walletInfo.getAddresses();
|
||||
addressInfos = await walletInfo.getAddressInfos();
|
||||
usedAddresses = await walletInfo.getUsedAddresses();
|
||||
manualAddresses = await walletInfo.getManualAddresses();
|
||||
hiddenAddresses = await walletInfo.getHiddenAddresses();
|
||||
address = latestAddress;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
await _initAddresses();
|
||||
|
||||
await ZcashTaddressRotation.init();
|
||||
int accountIndex = 0;
|
||||
addressInfos = {
|
||||
0:
|
||||
ZcashTaddressRotation.allAddressesForAccount(accountId)?.map((final v) {
|
||||
return WalletInfoAddressInfo(
|
||||
walletInfoId: walletInfo.internalId,
|
||||
mapKey: ++accountIndex,
|
||||
accountIndex: 0,
|
||||
address: v,
|
||||
label: "",
|
||||
);
|
||||
}).toList() ??
|
||||
[],
|
||||
};
|
||||
hiddenAddresses.addAll(
|
||||
ZcashTaddressRotation.allUsedAddressesForAccount(accountId)?.toSet() ?? {},
|
||||
);
|
||||
|
||||
// addressInfos[0]?.removeWhere((final test) => hiddenAddresses.contains(test.address));
|
||||
if (_addressPageType == ZcashAddressType.transparentRotated) {
|
||||
final addr = ZcashTaddressRotation.addressForAccount(accountId, hiddenAddresses);
|
||||
if (addr != null) {
|
||||
address = addr;
|
||||
}
|
||||
}
|
||||
await saveAddressesInBox();
|
||||
}
|
||||
|
||||
@observable
|
||||
late String _address = latestAddress;
|
||||
|
||||
@computed
|
||||
String get address {
|
||||
return _address;
|
||||
}
|
||||
|
||||
void set address(final String _$address) => _address = _$address;
|
||||
|
||||
@override
|
||||
String get primaryAddress => address;
|
||||
|
||||
@override
|
||||
Future<void> saveAddressesInBox() async {
|
||||
try {
|
||||
await walletInfo.setAddresses(addressesMap);
|
||||
await walletInfo.setAddressInfos(addressInfos);
|
||||
await walletInfo.setUsedAddresses(usedAddresses.toList());
|
||||
await walletInfo.setHiddenAddresses(hiddenAddresses.toList());
|
||||
await walletInfo.setManualAddresses(manualAddresses.toList());
|
||||
await _initAddresses();
|
||||
} catch (e) {
|
||||
printV("Error saving addresses: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateAddressesInBox() async {
|
||||
_transparentAddress = null;
|
||||
_saplingAddress = null;
|
||||
_orchardAddress = null;
|
||||
_unifiedAddress = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> get usableAddressesMap => addressesMap;
|
||||
|
||||
@override
|
||||
Map<String, String> get usableAllAddressesMap => allAddressesMap;
|
||||
|
||||
List<WalletInfoAddressInfo> getAddressInfos() {
|
||||
if (addressPageType != ZcashAddressType.transparentRotated) {
|
||||
return [];
|
||||
}
|
||||
final List<WalletInfoAddressInfo> allInfos = [];
|
||||
for (final entry in addressInfos.entries) {
|
||||
allInfos.addAll(entry.value);
|
||||
}
|
||||
return allInfos;
|
||||
}
|
||||
|
||||
@override
|
||||
List<ReceivePageOption> get receivePageOptions {
|
||||
return [
|
||||
...ZcashReceivePageOption.all,
|
||||
...ReceivePageOptions.where((final element) => element != ReceivePageOption.mainnet),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
PaymentURI getPaymentUri(final String amount) => ZcashURI(amount: amount, address: address);
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_zcash/cw_zcash.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class ZcashWalletService
|
||||
extends
|
||||
WalletService<
|
||||
ZcashNewWalletCredentials,
|
||||
ZcashFromSeedWalletCredentials,
|
||||
ZcashFromKeysWalletCredentials,
|
||||
ZcashNewWalletCredentials
|
||||
> {
|
||||
ZcashWalletService();
|
||||
|
||||
static Mutex dbMutex = Mutex();
|
||||
static int dbMutexQueue = 0;
|
||||
static Future<T> runInDbMutex<T>(final Future<T> Function() call) async {
|
||||
try {
|
||||
printV("dbMutexQueue: ${dbMutexQueue++}");
|
||||
await dbMutex.acquire();
|
||||
return await call();
|
||||
} finally {
|
||||
dbMutex.release();
|
||||
dbMutexQueue--;
|
||||
}
|
||||
}
|
||||
|
||||
static Set<String> autoshieldTx = {};
|
||||
|
||||
static Future<void> addShieldedTx(final String txId) async {
|
||||
final pathForWalletType = await pathForWalletTypeDir(type: type);
|
||||
final shieldedListFile = p.join(pathForWalletType, "autoshield_list.txt");
|
||||
autoshieldTx.add(txId.replaceAll(RegExp(r'[^a-zA-Z0-9 ]'), ''));
|
||||
final shieldedList = File(shieldedListFile);
|
||||
shieldedList.writeAsStringSync(autoshieldTx.join("\n"));
|
||||
}
|
||||
|
||||
static Future<void> loadShieldTxs() async {
|
||||
try {
|
||||
final pathForWalletType = await pathForWalletTypeDir(type: type);
|
||||
final shieldedListFile = p.join(pathForWalletType, "autoshield_list.txt");
|
||||
final shieldedList = File(shieldedListFile);
|
||||
if (!shieldedList.existsSync()) {
|
||||
return;
|
||||
}
|
||||
autoshieldTx = shieldedList.readAsLinesSync().toSet();
|
||||
} catch (e) {
|
||||
printV("loadShieldTxs failed: $e");
|
||||
}
|
||||
}
|
||||
|
||||
static bool walletFilesExist(final String path) =>
|
||||
!File(path).existsSync() && !File('$path.keys').existsSync();
|
||||
|
||||
@override
|
||||
WalletType getType() => type;
|
||||
|
||||
static WalletType get type => WalletType.zcash;
|
||||
|
||||
@override
|
||||
Future<ZcashWallet> create(final WalletCredentials credentials, {final bool? isTestnet}) {
|
||||
return ZcashWalletBase.create(credentials);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isWalletExit(final String name) async {
|
||||
final path = await pathForWallet(name: name, type: getType());
|
||||
return File(path).existsSync();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ZcashWallet> openWallet(final String name, final String password) async {
|
||||
await loadShieldTxs();
|
||||
final walletInfo = await WalletInfo.get(name, getType());
|
||||
if (walletInfo == null) {
|
||||
throw Exception('Wallet not found');
|
||||
}
|
||||
try {
|
||||
final wallet = await ZcashWalletBase.open(
|
||||
name: name,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
);
|
||||
await wallet.init();
|
||||
await saveBackup(name);
|
||||
return wallet;
|
||||
} catch (e) {
|
||||
await restoreWalletFilesFromBackup(name);
|
||||
final wallet = await ZcashWalletBase.open(
|
||||
name: name,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
);
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> remove(final String wallet) async {
|
||||
final path = await pathForWalletDir(name: wallet, type: getType());
|
||||
final file = Directory(path);
|
||||
final isExist = file.existsSync();
|
||||
|
||||
if (isExist) {
|
||||
await file.delete(recursive: true);
|
||||
}
|
||||
|
||||
final walletInfo = await WalletInfo.get(wallet, getType());
|
||||
if (walletInfo == null) {
|
||||
throw Exception('Wallet not found');
|
||||
}
|
||||
await WalletInfo.delete(walletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rename(final String currentName, final String password, final String newName) async {
|
||||
final currentWalletInfo = await WalletInfo.get(currentName, getType());
|
||||
if (currentWalletInfo == null) {
|
||||
throw Exception('Wallet not found');
|
||||
}
|
||||
final accountId = await ZcashWalletBase.getZcashAccountIdForName(currentName);
|
||||
if (accountId == null) {
|
||||
throw Exception('Wallet account not found for name: $currentName');
|
||||
}
|
||||
final currentWallet = ZcashWallet(
|
||||
currentWalletInfo,
|
||||
await currentWalletInfo.getDerivationInfo(),
|
||||
accountId: accountId,
|
||||
);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
|
||||
await newWalletInfo.save();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ZcashWallet> restoreFromKeys(
|
||||
final ZcashFromKeysWalletCredentials credentials, {
|
||||
final bool? isTestnet,
|
||||
}) async {
|
||||
return ZcashWalletBase.restoreKeys(credentials);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ZcashWallet> restoreFromSeed(
|
||||
final ZcashFromSeedWalletCredentials credentials, {
|
||||
final bool? isTestnet,
|
||||
}) async {
|
||||
if (credentials.seed == null || credentials.seed!.isEmpty) {
|
||||
throw ZcashMnemonicIsIncorrectException();
|
||||
}
|
||||
|
||||
if (!bip39.validateMnemonic(credentials.seed!)) {
|
||||
throw ZcashMnemonicIsIncorrectException();
|
||||
}
|
||||
|
||||
return ZcashWalletBase.restore(credentials);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ZcashWallet> restoreFromHardwareWallet(final ZcashNewWalletCredentials credentials) {
|
||||
throw UnimplementedError(
|
||||
"Restoring a Zcash wallet from a hardware wallet is not yet supported!",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
name: cw_zcash
|
||||
description: Zcash library for cake wallet
|
||||
version: 1.0.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.0
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
warp_api:
|
||||
path: ../scripts/zcash_lib/packages/warp_api_ffi
|
||||
cw_core:
|
||||
path: ../cw_core
|
||||
mobx: ^2.5.0
|
||||
bip39: ^1.0.6
|
||||
mutex: ^3.1.0
|
||||
|
||||
path: any
|
||||
flat_buffers: any
|
||||
zkool:
|
||||
git:
|
||||
url: https://github.com/cake-tech/zkool2
|
||||
ref: b1642f260da4fa00dd2f8d4dd689073d0b56960a
|
||||
|
||||
path_provider: any
|
||||
dependency_overrides:
|
||||
decimal: ^2.3.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.15
|
||||
build_resolvers: ^2.4.4
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^2.0.1
|
||||
ffigen: ^16.1.0
|
||||
+1
-1
@@ -24,7 +24,7 @@ IF NOT EXIST "%secrets_file_path%" (
|
||||
) ELSE (echo === Using previously/already generated secrets file: %secrets_file_path% ===)
|
||||
|
||||
echo === Generating mobx models ===
|
||||
for /d %%i in (cw_core cw_monero cw_bitcoin cw_evm cw_nano cw_bitcoin_cash cw_solana cw_tron cw_zcash.) do (
|
||||
for /d %%i in (cw_core cw_monero cw_bitcoin cw_evm cw_nano cw_bitcoin_cash cw_wownero cw_dogecoin) do (
|
||||
cd %%i
|
||||
call flutter pub get > nul
|
||||
call dart run build_runner build --delete-conflicting-outputs > nul
|
||||
|
||||
@@ -271,13 +271,10 @@ flutter:
|
||||
- assets/dogecoin_electrum_server_list.yml
|
||||
- assets/base_node_list.yml
|
||||
- assets/arbitrum_node_list.yml
|
||||
- assets/zcash_node_list.yml
|
||||
- assets/bsc_node_list.yml
|
||||
- assets/text/
|
||||
- assets/faq/
|
||||
- assets/animation/
|
||||
- scripts/zcash_lib/assets/sapling-spend.params
|
||||
- scripts/zcash_lib/assets/sapling-output.params
|
||||
- assets/new-ui/
|
||||
- assets/new-ui/icons/
|
||||
- assets/new-ui/hero/
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
../prepare_zcash.sh
|
||||
|
||||
pushd ../zcash_lib
|
||||
./build-scripts/build-android.sh
|
||||
popd
|
||||
@@ -5,7 +5,6 @@ ARG BITBOX_IMAGE
|
||||
ARG MONERO_IMAGE
|
||||
ARG DECRED_IMAGE
|
||||
ARG MWEBD_IMAGE
|
||||
ARG ZCASH_IMAGE
|
||||
|
||||
FROM ${TORCH_IMAGE} AS torch_src
|
||||
FROM ${REOWN_IMAGE} AS reown_src
|
||||
@@ -13,7 +12,6 @@ FROM ${BITBOX_IMAGE} AS bitbox_src
|
||||
FROM ${MONERO_IMAGE} AS monero_src
|
||||
FROM ${DECRED_IMAGE} AS decred_src
|
||||
FROM ${MWEBD_IMAGE} AS mwebd_src
|
||||
FROM ${ZCASH_IMAGE} AS zcash_src
|
||||
|
||||
FROM --platform=linux/amd64 alpine
|
||||
|
||||
@@ -23,4 +21,3 @@ COPY --from=bitbox_src /w /w.top
|
||||
COPY --from=monero_src /w /w.top
|
||||
COPY --from=decred_src /w /w.top
|
||||
COPY --from=mwebd_src /w /w.top
|
||||
COPY --from=zcash_src /w /w.top
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
ARG BASE_IMAGE
|
||||
FROM --platform=linux/amd64 ${BASE_IMAGE} AS build
|
||||
|
||||
RUN mkdir -p /w/scripts/android
|
||||
COPY scripts/prepare_zcash.sh /w/scripts/prepare_zcash.sh
|
||||
COPY scripts/android/build_zcash.sh /w/scripts/android/build_zcash.sh
|
||||
RUN /w/scripts/android/build_zcash.sh \
|
||||
&& rm -rf /w/scripts/zcash_lib/target
|
||||
|
||||
FROM --platform=linux/amd64 alpine
|
||||
COPY --from=build /w /w
|
||||
@@ -56,9 +56,8 @@ reown_ver=$(tinysha $SCRIPT_DIR/Dockerfile.reown $REPO_ROOT/scripts/prepare_reow
|
||||
bitbox_ver=$(tinysha $SCRIPT_DIR/Dockerfile.bitbox $REPO_ROOT/scripts/build_bitbox_flutter.sh)
|
||||
monero_ver=$(tinysha $SCRIPT_DIR/Dockerfile.monero $REPO_ROOT/scripts/prepare_moneroc.sh $REPO_ROOT/scripts/android/build_monero_all.sh)
|
||||
mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $(find $REPO_ROOT/cw_mweb/go -type f))
|
||||
zcash_ver=$(tinysha $SCRIPT_DIR/Dockerfile.zcash $REPO_ROOT/scripts/prepare_zcash.sh $REPO_ROOT/scripts/android/build_zcash.sh)
|
||||
decred_ver=$(tinysha $SCRIPT_DIR/Dockerfile.torch $SCRIPT_DIR/Dockerfile.decred $REPO_ROOT/scripts/android/build_decred.sh)
|
||||
echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver $decred_ver > /tmp/docker_build_versions
|
||||
echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $decred_ver > /tmp/docker_build_versions
|
||||
final_ver=$(tinysha /tmp/docker_build_versions)
|
||||
|
||||
docker create --name temp_extract $(img final $final_ver) \
|
||||
@@ -83,8 +82,6 @@ build reown "$reown_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
|
||||
|
||||
build monero "$monero_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
|
||||
|
||||
build zcash "$zcash_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
|
||||
|
||||
build torch "$torch_ver" \
|
||||
--build-arg BASE_IMAGE="$(img base "$base_ver")"
|
||||
|
||||
@@ -99,8 +96,7 @@ build final $final_ver \
|
||||
--build-arg BITBOX_IMAGE="$(img bitbox $bitbox_ver)" \
|
||||
--build-arg MONERO_IMAGE="$(img monero $monero_ver)" \
|
||||
--build-arg DECRED_IMAGE="$(img decred $decred_ver)" \
|
||||
--build-arg MWEBD_IMAGE="$(img mwebd $mwebd_ver)" \
|
||||
--build-arg ZCASH_IMAGE="$(img zcash $zcash_ver)"
|
||||
--build-arg MWEBD_IMAGE="$(img mwebd $mwebd_ver)"
|
||||
|
||||
echo "done: $(img final $final_ver)"
|
||||
echo $(img final $final_ver) > /tmp/cakewallet_docker
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
../prepare_zcash.sh
|
||||
|
||||
pushd ../zcash_lib
|
||||
./build-scripts/mac/build-mac.sh
|
||||
popd
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
../prepare_zcash.sh
|
||||
|
||||
pushd ../zcash_lib
|
||||
./build-scripts/build-linux.sh
|
||||
popd
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
../prepare_zcash.sh
|
||||
|
||||
pushd ../zcash_lib
|
||||
./build-scripts/mac/build-mac.sh
|
||||
popd
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -x -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
HASH=647231e2e6d93c1d6c16d4019cd3a11a3aaa9504
|
||||
|
||||
if [[ ! -d "zcash_lib/.git" ]];
|
||||
then
|
||||
rm -rf zcash_lib
|
||||
git clone https://github.com/MrCyjaneK/zwallet.git zcash_lib
|
||||
cd zcash_lib
|
||||
else
|
||||
cd zcash_lib
|
||||
git fetch -a
|
||||
fi
|
||||
|
||||
|
||||
git reset --hard
|
||||
git checkout $HASH
|
||||
git reset --hard
|
||||
git submodule update --init --force --recursive
|
||||
|
||||
# in go I could nicely replace => the heck out of it
|
||||
# sadly rust is not go
|
||||
find . -name Cargo.toml -exec sed -i.bak -E '
|
||||
s|rusqlite[[:space:]]*=[[:space:]]*\{[^}]*\}|rusqlite = { version = "0.29.0", features = ["bundled", "modern_sqlite", "backup"] }|g
|
||||
' {} +
|
||||
# find . -name Cargo.toml -exec sed -i.bak -E 's|r2d2_sqlite[[:space:]]*=[[:space:]]*([^\n]*)|r2d2_sqlite = "0.32.0"|g' {} +
|
||||
Reference in New Issue
Block a user