centralized and cleaned up bip32 utils, and added mnemonic password functionality

This commit is contained in:
julian 2023-02-03 16:34:06 -06:00
parent b0c00d8ec7
commit 5b5ee30e41
52 changed files with 4388 additions and 3958 deletions

View file

@ -125,6 +125,7 @@ class StackRestoringUIState extends ChangeNotifier {
Manager? manager, Manager? manager,
String? address, String? address,
String? mnemonic, String? mnemonic,
String? mnemonicPassphrase,
int? height, int? height,
}) { }) {
_walletStates[walletId]!.restoringState = restoringStatus; _walletStates[walletId]!.restoringState = restoringStatus;
@ -134,6 +135,8 @@ class StackRestoringUIState extends ChangeNotifier {
address ?? _walletStates[walletId]!.address; address ?? _walletStates[walletId]!.address;
_walletStates[walletId]!.mnemonic = _walletStates[walletId]!.mnemonic =
mnemonic ?? _walletStates[walletId]!.mnemonic; mnemonic ?? _walletStates[walletId]!.mnemonic;
_walletStates[walletId]!.mnemonicPassphrase =
mnemonicPassphrase ?? _walletStates[walletId]!.mnemonicPassphrase;
_walletStates[walletId]!.height = height ?? _walletStates[walletId]!.height; _walletStates[walletId]!.height = height ?? _walletStates[walletId]!.height;
notifyListeners(); notifyListeners();
} }

View file

@ -11,6 +11,7 @@ class WalletRestoreState extends ChangeNotifier {
Manager? manager; Manager? manager;
String? address; String? address;
String? mnemonic; String? mnemonic;
String? mnemonicPassphrase;
int? height; int? height;
StackRestoringStatus get restoringState => _restoringStatus; StackRestoringStatus get restoringState => _restoringStatus;
@ -27,6 +28,7 @@ class WalletRestoreState extends ChangeNotifier {
this.manager, this.manager,
this.address, this.address,
this.mnemonic, this.mnemonic,
this.mnemonicPassphrase,
this.height, this.height,
}) { }) {
_restoringStatus = restoringStatus; _restoringStatus = restoringStatus;
@ -45,6 +47,7 @@ class WalletRestoreState extends ChangeNotifier {
manager: manager, manager: manager,
address: this.address, address: this.address,
mnemonic: mnemonic, mnemonic: mnemonic,
mnemonicPassphrase: mnemonicPassphrase,
height: this.height, height: this.height,
); );
} }

View file

@ -290,6 +290,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
// without using them // without using them
await manager.recoverFromMnemonic( await manager.recoverFromMnemonic(
mnemonic: mnemonic, mnemonic: mnemonic,
mnemonicPassphrase: "", // TODO add ui for certain coins
maxUnusedAddressGap: widget.coin == Coin.firo ? 50 : 20, maxUnusedAddressGap: widget.coin == Coin.firo ? 50 : 20,
maxNumberOfIndexesToCheck: 1000, maxNumberOfIndexesToCheck: 1000,
height: height, height: height,

View file

@ -357,7 +357,9 @@ abstract class SWB {
List<String> mnemonicList = (walletbackup['mnemonic'] as List<dynamic>) List<String> mnemonicList = (walletbackup['mnemonic'] as List<dynamic>)
.map<String>((e) => e as String) .map<String>((e) => e as String)
.toList(); .toList();
String mnemonic = mnemonicList.join(" ").trim(); final String mnemonic = mnemonicList.join(" ").trim();
final String mnemonicPassphrase =
walletbackup['mnemonicPassphrase'] as String? ?? "";
uiState?.update( uiState?.update(
walletId: manager.walletId, walletId: manager.walletId,
@ -403,6 +405,7 @@ abstract class SWB {
// without using them // without using them
await manager.recoverFromMnemonic( await manager.recoverFromMnemonic(
mnemonic: mnemonic, mnemonic: mnemonic,
mnemonicPassphrase: mnemonicPassphrase,
maxUnusedAddressGap: manager.coin == Coin.firo ? 50 : 20, maxUnusedAddressGap: manager.coin == Coin.firo ? 50 : 20,
maxNumberOfIndexesToCheck: 1000, maxNumberOfIndexesToCheck: 1000,
height: restoreHeight, height: restoreHeight,

View file

@ -109,6 +109,8 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> {
if (mnemonicList.isEmpty) { if (mnemonicList.isEmpty) {
await manager.recoverFromMnemonic( await manager.recoverFromMnemonic(
mnemonic: ref.read(provider).mnemonic!, mnemonic: ref.read(provider).mnemonic!,
mnemonicPassphrase:
ref.read(provider).mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
height: ref.read(provider).height ?? 0, height: ref.read(provider).height ?? 0,
@ -250,6 +252,8 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> {
if (mnemonicList.isEmpty) { if (mnemonicList.isEmpty) {
await manager.recoverFromMnemonic( await manager.recoverFromMnemonic(
mnemonic: ref.read(provider).mnemonic!, mnemonic: ref.read(provider).mnemonic!,
mnemonicPassphrase:
ref.read(provider).mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck:
maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck,

View file

@ -33,6 +33,7 @@ import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -55,40 +56,15 @@ const String GENESIS_HASH_MAINNET =
const String GENESIS_HASH_TESTNET = const String GENESIS_HASH_TESTNET =
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"; "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943";
bip32.BIP32 getBip32Node( String constructDerivePath({
int chain, required DerivePathType derivePathType,
int index, required int networkWIF,
String mnemonic, int account = 0,
NetworkType network, required int chain,
DerivePathType derivePathType, required int index,
) { }) {
final root = getBip32Root(mnemonic, network);
final node = getBip32NodeFromRoot(chain, index, root, derivePathType);
return node;
}
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple5<int, int, String, NetworkType, DerivePathType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
args.item5,
);
}
bip32.BIP32 getBip32NodeFromRoot(
int chain,
int index,
bip32.BIP32 root,
DerivePathType derivePathType,
) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0x80: // btc mainnet wif case 0x80: // btc mainnet wif
coinType = "0"; // btc mainnet coinType = "0"; // btc mainnet
break; break;
@ -96,49 +72,25 @@ bip32.BIP32 getBip32NodeFromRoot(
coinType = "1"; // btc testnet coinType = "1"; // btc testnet
break; break;
default: default:
throw Exception("Invalid Bitcoin network type used!"); throw Exception("Invalid Bitcoin network wif used!");
} }
int purpose;
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); purpose = 44;
break;
case DerivePathType.bip49: case DerivePathType.bip49:
return root.derivePath("m/49'/$coinType'/0'/$chain/$index"); purpose = 49;
break;
case DerivePathType.bip84: case DerivePathType.bip84:
return root.derivePath("m/84'/$coinType'/0'/$chain/$index"); purpose = 84;
break;
default: default:
throw Exception("DerivePathType $derivePathType not supported"); throw Exception("DerivePathType $derivePathType not supported");
} }
}
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple4<int, int, bip32.BIP32, DerivePathType> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final networkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
class BitcoinWallet extends CoinServiceAPI class BitcoinWallet extends CoinServiceAPI
@ -261,6 +213,15 @@ class BitcoinWallet extends CoinServiceAPI
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
@ -325,6 +286,7 @@ class BitcoinWallet extends CoinServiceAPI
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -355,14 +317,21 @@ class BitcoinWallet extends CoinServiceAPI
} }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic.trim(), mnemonic: mnemonic.trim(),
mnemonicPassphrase: mnemonicPassphrase ?? "",
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
); );
@ -405,15 +374,14 @@ class BitcoinWallet extends CoinServiceAPI
final Map<String, dynamic> receivingNodes = {}; final Map<String, dynamic> receivingNodes = {};
for (int j = 0; j < txCountBatchSize; j++) { for (int j = 0; j < txCountBatchSize; j++) {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, derivePathType: type,
Tuple4( networkWIF: root.network.wif,
chain, chain: chain,
index + j, index: index + j,
root,
type,
),
); );
final node = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
String addressString; String addressString;
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -522,6 +490,7 @@ class BitcoinWallet extends CoinServiceAPI
Future<void> _recoverWalletFromBIP32SeedPhrase({ Future<void> _recoverWalletFromBIP32SeedPhrase({
required String mnemonic, required String mnemonic,
required String mnemonicPassphrase,
int maxUnusedAddressGap = 20, int maxUnusedAddressGap = 20,
int maxNumberOfIndexesToCheck = 1000, int maxNumberOfIndexesToCheck = 1000,
bool isRescan = false, bool isRescan = false,
@ -535,7 +504,11 @@ class BitcoinWallet extends CoinServiceAPI
Map<String, Map<String, String>> p2shChangeDerivations = {}; Map<String, Map<String, String>> p2shChangeDerivations = {};
Map<String, Map<String, String>> p2wpkhChangeDerivations = {}; Map<String, Map<String, String>> p2wpkhChangeDerivations = {};
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
List<isar_models.Address> p2pkhReceiveAddressArray = []; List<isar_models.Address> p2pkhReceiveAddressArray = [];
List<isar_models.Address> p2shReceiveAddressArray = []; List<isar_models.Address> p2shReceiveAddressArray = [];
@ -1350,7 +1323,8 @@ class BitcoinWallet extends CoinServiceAPI
db: db, db: db,
electrumXClient: electrumXClient, electrumXClient: electrumXClient,
secureStorage: secureStore, secureStorage: secureStore,
getMnemonic: () => mnemonic, getMnemonicString: () => mnemonicString,
getMnemonicPassphrase: () => mnemonicPassphrase,
getChainHeight: () => chainHeight, getChainHeight: () => chainHeight,
getCurrentChangeAddress: () => currentChangeAddressP2PKH, getCurrentChangeAddress: () => currentChangeAddressP2PKH,
estimateTxFee: estimateTxFee, estimateTxFee: estimateTxFee,
@ -1361,7 +1335,6 @@ class BitcoinWallet extends CoinServiceAPI
checkChangeAddressForTransactions: checkChangeAddressForTransactions:
_checkP2PKHChangeAddressForTransactions, _checkP2PKHChangeAddressForTransactions,
addDerivation: addDerivation, addDerivation: addDerivation,
addDerivations: addDerivations,
dustLimitP2PKH: DUST_LIMIT_P2PKH, dustLimitP2PKH: DUST_LIMIT_P2PKH,
minConfirms: MINIMUM_CONFIRMATIONS, minConfirms: MINIMUM_CONFIRMATIONS,
); );
@ -1397,12 +1370,11 @@ class BitcoinWallet extends CoinServiceAPI
} }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -1490,13 +1462,14 @@ class BitcoinWallet extends CoinServiceAPI
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: "");
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialAddresses = await Future.wait([ final initialAddresses = await Future.wait([
@ -1526,17 +1499,22 @@ class BitcoinWallet extends CoinServiceAPI
int index, int index,
DerivePathType derivePathType, DerivePathType derivePathType,
) async { ) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final node = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple5( final derivePath = constructDerivePath(
chain, derivePathType: derivePathType,
index, networkWIF: _network.wif,
mnemonic!, chain: chain,
_network, index: index,
derivePathType,
),
); );
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
String address; String address;
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -2925,9 +2903,12 @@ class BitcoinWallet extends CoinServiceAPI
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic!, mnemonic: _mnemonic!,
mnemonicPassphrase: _mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
isRescan: true, isRescan: true,

View file

@ -31,6 +31,7 @@ import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -51,31 +52,15 @@ const String GENESIS_HASH_MAINNET =
const String GENESIS_HASH_TESTNET = const String GENESIS_HASH_TESTNET =
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"; "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943";
bip32.BIP32 getBip32Node(int chain, int index, String mnemonic, String constructDerivePath({
NetworkType network, DerivePathType derivePathType) { required DerivePathType derivePathType,
final root = getBip32Root(mnemonic, network); required int networkWIF,
int account = 0,
final node = getBip32NodeFromRoot(chain, index, root, derivePathType); required int chain,
return node; required int index,
} }) {
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple5<int, int, String, NetworkType, DerivePathType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
args.item5,
);
}
bip32.BIP32 getBip32NodeFromRoot(
int chain, int index, bip32.BIP32 root, DerivePathType derivePathType) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0x80: // bch mainnet wif case 0x80: // bch mainnet wif
coinType = coinType =
derivePathType == DerivePathType.bch44 ? "145" : "0"; // bch mainnet derivePathType == DerivePathType.bch44 ? "145" : "0"; // bch mainnet
@ -84,48 +69,23 @@ bip32.BIP32 getBip32NodeFromRoot(
coinType = "1"; // bch testnet coinType = "1"; // bch testnet
break; break;
default: default:
throw Exception("Invalid Bitcoincash network type used!"); throw Exception("Invalid Bitcoincash network wif used!");
} }
int purpose;
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
case DerivePathType.bch44: case DerivePathType.bch44:
return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); purpose = 44;
case DerivePathType.bip49: break;
return root.derivePath("m/49'/$coinType'/0'/$chain/$index"); case DerivePathType.bip84:
purpose = 84;
break;
default: default:
throw Exception("DerivePathType must not be null."); throw Exception("DerivePathType $derivePathType not supported");
}
} }
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple4<int, int, bip32.BIP32, DerivePathType> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final networkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB { class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
@ -214,6 +174,15 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
@ -250,7 +219,9 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
throw ArgumentError('$address is not currently supported'); throw ArgumentError('$address is not currently supported');
} }
} }
} catch (e, s) {} } catch (_) {
// invalid cash addr format
}
try { try {
decodeBase58 = bs58check.decode(address); decodeBase58 = bs58check.decode(address);
} catch (err) { } catch (err) {
@ -291,6 +262,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -321,14 +293,21 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic.trim(), mnemonic: mnemonic.trim(),
mnemonicPassphrase: mnemonicPassphrase ?? "",
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
coin: coin, coin: coin,
@ -372,15 +351,14 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
final Map<String, dynamic> receivingNodes = {}; final Map<String, dynamic> receivingNodes = {};
for (int j = 0; j < txCountBatchSize; j++) { for (int j = 0; j < txCountBatchSize; j++) {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, derivePathType: type,
Tuple4( networkWIF: root.network.wif,
chain, chain: chain,
index + j, index: index + j,
root,
type,
),
); );
final node = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
String addressString; String addressString;
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -493,6 +471,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<void> _recoverWalletFromBIP32SeedPhrase({ Future<void> _recoverWalletFromBIP32SeedPhrase({
required String mnemonic, required String mnemonic,
required String mnemonicPassphrase,
int maxUnusedAddressGap = 20, int maxUnusedAddressGap = 20,
int maxNumberOfIndexesToCheck = 1000, int maxNumberOfIndexesToCheck = 1000,
bool isRescan = false, bool isRescan = false,
@ -507,7 +486,11 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
Map<String, Map<String, String>> bch44P2pkhChangeDerivations = {}; Map<String, Map<String, String>> bch44P2pkhChangeDerivations = {};
Map<String, Map<String, String>> p2shChangeDerivations = {}; Map<String, Map<String, String>> p2shChangeDerivations = {};
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
List<isar_models.Address> bip44P2pkhReceiveAddressArray = []; List<isar_models.Address> bip44P2pkhReceiveAddressArray = [];
List<isar_models.Address> bch44P2pkhReceiveAddressArray = []; List<isar_models.Address> bch44P2pkhReceiveAddressArray = [];
@ -531,7 +514,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
const txCountBatchSize = 12; const txCountBatchSize = 12;
try { try {
bool testnet = ((coin ?? null) == Coin.bitcoincashTestnet) ? true : false; bool testnet = ((coin) == Coin.bitcoincashTestnet) ? true : false;
// receiving addresses // receiving addresses
Logging.instance Logging.instance
.log("checking receiving addresses...", level: LogLevel.Info); .log("checking receiving addresses...", level: LogLevel.Info);
@ -1334,12 +1317,11 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -1440,13 +1422,14 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(key: '${_walletId}_mnemonicPassphrase', value: "");
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialAddresses = await Future.wait([ final initialAddresses = await Future.wait([
@ -1472,17 +1455,22 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
int index, int index,
DerivePathType derivePathType, DerivePathType derivePathType,
) async { ) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final node = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple5( final derivePath = constructDerivePath(
chain, derivePathType: derivePathType,
index, networkWIF: _network.wif,
mnemonic!, chain: chain,
_network, index: index,
derivePathType,
),
); );
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
String address; String address;
@ -2970,9 +2958,12 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic!, mnemonic: _mnemonic!,
mnemonicPassphrase: _mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
isRescan: true, isRescan: true,

View file

@ -263,11 +263,14 @@ abstract class CoinServiceAPI {
bool validateAddress(String address); bool validateAddress(String address);
Future<List<String>> get mnemonic; Future<List<String>> get mnemonic;
Future<String?> get mnemonicString;
Future<String?> get mnemonicPassphrase;
Future<bool> testNetworkConnection(); Future<bool> testNetworkConnection();
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,

View file

@ -32,6 +32,7 @@ import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -52,31 +53,15 @@ const String GENESIS_HASH_MAINNET =
const String GENESIS_HASH_TESTNET = const String GENESIS_HASH_TESTNET =
"bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e"; "bb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e";
bip32.BIP32 getBip32Node(int chain, int index, String mnemonic, String constructDerivePath({
NetworkType network, DerivePathType derivePathType) { required DerivePathType derivePathType,
final root = getBip32Root(mnemonic, network); required int networkWIF,
int account = 0,
final node = getBip32NodeFromRoot(chain, index, root, derivePathType); required int chain,
return node; required int index,
} }) {
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple5<int, int, String, NetworkType, DerivePathType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
args.item5,
);
}
bip32.BIP32 getBip32NodeFromRoot(
int chain, int index, bip32.BIP32 root, DerivePathType derivePathType) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0x9e: // doge mainnet wif case 0x9e: // doge mainnet wif
coinType = "3"; // doge mainnet coinType = "3"; // doge mainnet
break; break;
@ -84,46 +69,19 @@ bip32.BIP32 getBip32NodeFromRoot(
coinType = "1"; // doge testnet coinType = "1"; // doge testnet
break; break;
default: default:
throw Exception("Invalid Dogecoin network type used!"); throw Exception("Invalid Dogecoin network wif used!");
} }
int purpose;
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); purpose = 44;
break;
default: default:
throw Exception( throw Exception("DerivePathType $derivePathType not supported");
"DerivePathType null or unsupported (${DerivePathType.bip44})");
}
} }
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple4<int, int, bip32.BIP32, DerivePathType> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final networkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
class DogecoinWallet extends CoinServiceAPI class DogecoinWallet extends CoinServiceAPI
@ -222,6 +180,15 @@ class DogecoinWallet extends CoinServiceAPI
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
@ -281,6 +248,7 @@ class DogecoinWallet extends CoinServiceAPI
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -311,14 +279,20 @@ class DogecoinWallet extends CoinServiceAPI
} }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic.trim(), mnemonic: mnemonic.trim(),
mnemonicPassphrase: mnemonicPassphrase ?? "",
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
); );
@ -361,15 +335,14 @@ class DogecoinWallet extends CoinServiceAPI
final Map<String, dynamic> receivingNodes = {}; final Map<String, dynamic> receivingNodes = {};
for (int j = 0; j < txCountBatchSize; j++) { for (int j = 0; j < txCountBatchSize; j++) {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, derivePathType: type,
Tuple4( networkWIF: root.network.wif,
chain, chain: chain,
index + j, index: index + j,
root,
type,
),
); );
final node = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
isar_models.Address address; isar_models.Address address;
switch (type) { switch (type) {
case DerivePathType.bip44: case DerivePathType.bip44:
@ -463,6 +436,7 @@ class DogecoinWallet extends CoinServiceAPI
Future<void> _recoverWalletFromBIP32SeedPhrase({ Future<void> _recoverWalletFromBIP32SeedPhrase({
required String mnemonic, required String mnemonic,
required String mnemonicPassphrase,
int maxUnusedAddressGap = 20, int maxUnusedAddressGap = 20,
int maxNumberOfIndexesToCheck = 1000, int maxNumberOfIndexesToCheck = 1000,
bool isRescan = false, bool isRescan = false,
@ -472,7 +446,11 @@ class DogecoinWallet extends CoinServiceAPI
Map<String, Map<String, String>> p2pkhReceiveDerivations = {}; Map<String, Map<String, String>> p2pkhReceiveDerivations = {};
Map<String, Map<String, String>> p2pkhChangeDerivations = {}; Map<String, Map<String, String>> p2pkhChangeDerivations = {};
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, network)); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
network,
);
List<isar_models.Address> p2pkhReceiveAddressArray = []; List<isar_models.Address> p2pkhReceiveAddressArray = [];
int p2pkhReceiveIndex = -1; int p2pkhReceiveIndex = -1;
@ -1187,12 +1165,11 @@ class DogecoinWallet extends CoinServiceAPI
} }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -1280,13 +1257,17 @@ class DogecoinWallet extends CoinServiceAPI
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
// Generate and add addresses // Generate and add addresses
final initialReceivingAddressP2PKH = final initialReceivingAddressP2PKH =
@ -1310,17 +1291,22 @@ class DogecoinWallet extends CoinServiceAPI
int index, int index,
DerivePathType derivePathType, DerivePathType derivePathType,
) async { ) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final node = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple5( final derivePath = constructDerivePath(
chain, derivePathType: derivePathType,
index, networkWIF: network.wif,
mnemonic!, chain: chain,
network, index: index,
derivePathType,
),
); );
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
network,
derivePath,
);
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
String address; String address;
@ -2561,9 +2547,12 @@ class DogecoinWallet extends CoinServiceAPI
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic!, mnemonic: _mnemonic!,
mnemonicPassphrase: _mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
isRescan: true, isRescan: true,

View file

@ -1103,26 +1103,24 @@ class EpicCashWallet extends CoinServiceAPI
bool get isRefreshing => refreshMutex; bool get isRefreshing => refreshMutex;
@override @override
// TODO: implement maxFee // unused for epic
Future<int> get maxFee => throw UnimplementedError(); Future<int> get maxFee => throw UnimplementedError();
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { String? _mnemonicString = await mnemonicString;
final mnemonicString = if (_mnemonicString != null) {
await _secureStore.read(key: '${_walletId}_mnemonic'); final List<String> data = _mnemonicString.split(' ');
final List<String> data = mnemonicString!.split(' ');
return data; return data;
} else { } else {
String? mnemonicString;
await m.protect(() async { await m.protect(() async {
mnemonicString = await compute( _mnemonicString = await compute(
_walletMnemonicWrapper, _walletMnemonicWrapper,
0, 0,
); );
}); });
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonicString); key: '${_walletId}_mnemonic', value: _mnemonicString);
final List<String> data = mnemonicString!.split(' '); final List<String> data = _mnemonicString!.split(' ');
return data; return data;
} }
} }
@ -1130,6 +1128,15 @@ class EpicCashWallet extends CoinServiceAPI
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
@override @override
Future<Map<String, dynamic>> prepareSend( Future<Map<String, dynamic>> prepareSend(
{required String address, {required String address,
@ -1359,11 +1366,13 @@ class EpicCashWallet extends CoinServiceAPI
double highestPercent = 0; double highestPercent = 0;
@override @override
Future<void> recoverFromMnemonic( Future<void> recoverFromMnemonic({
{required String mnemonic, required String mnemonic,
required String mnemonicPassphrase, // unused in epic
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height}) async { required int height,
}) async {
try { try {
await _prefs.init(); await _prefs.init();
await updateNode(false); await updateNode(false);

View file

@ -4,7 +4,6 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'dart:math'; import 'dart:math';
import 'package:bip32/bip32.dart' as bip32;
import 'package:bip39/bip39.dart' as bip39; import 'package:bip39/bip39.dart' as bip39;
import 'package:bitcoindart/bitcoindart.dart'; import 'package:bitcoindart/bitcoindart.dart';
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
@ -25,6 +24,7 @@ import 'package:stackwallet/services/event_bus/events/global/refresh_percent_cha
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart'; import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart';
import 'package:stackwallet/services/mixins/firo_hive.dart';
import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_cache.dart';
import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart';
import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/node_service.dart';
@ -32,6 +32,7 @@ import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -43,8 +44,6 @@ import 'package:stackwallet/utilities/prefs.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import '../../mixins/firo_hive.dart';
const DUST_LIMIT = 1000; const DUST_LIMIT = 1000;
const MINIMUM_CONFIRMATIONS = 1; const MINIMUM_CONFIRMATIONS = 1;
const MINT_LIMIT = 100100000000; const MINT_LIMIT = 100100000000;
@ -102,6 +101,7 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
final address = arguments['address'] as String; final address = arguments['address'] as String;
final subtractFeeFromAmount = arguments['subtractFeeFromAmount'] as bool; final subtractFeeFromAmount = arguments['subtractFeeFromAmount'] as bool;
final mnemonic = arguments['mnemonic'] as String; final mnemonic = arguments['mnemonic'] as String;
final mnemonicPassphrase = arguments['mnemonicPassphrase'] as String;
final index = arguments['index'] as int; final index = arguments['index'] as int;
final lelantusEntries = final lelantusEntries =
arguments['lelantusEntries'] as List<DartLelantusEntry>; arguments['lelantusEntries'] as List<DartLelantusEntry>;
@ -115,6 +115,7 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
address, address,
subtractFeeFromAmount, subtractFeeFromAmount,
mnemonic, mnemonic,
mnemonicPassphrase,
index, index,
lelantusEntries, lelantusEntries,
locktime, locktime,
@ -143,11 +144,13 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
final setDataMap = arguments['setDataMap'] as Map; final setDataMap = arguments['setDataMap'] as Map;
final usedSerialNumbers = arguments['usedSerialNumbers'] as List?; final usedSerialNumbers = arguments['usedSerialNumbers'] as List?;
final mnemonic = arguments['mnemonic'] as String; final mnemonic = arguments['mnemonic'] as String;
final mnemonicPassphrase = arguments['mnemonicPassphrase'] as String;
final coin = arguments['coin'] as Coin; final coin = arguments['coin'] as Coin;
final network = arguments['network'] as NetworkType?; final network = arguments['network'] as NetworkType?;
if (!(usedSerialNumbers == null || network == null)) { if (!(usedSerialNumbers == null || network == null)) {
var restoreData = await isolateRestore( var restoreData = await isolateRestore(
mnemonic, mnemonic,
mnemonicPassphrase,
coin, coin,
latestSetId, latestSetId,
setDataMap, setDataMap,
@ -159,11 +162,13 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
} }
} else if (function == "isolateDerive") { } else if (function == "isolateDerive") {
final mnemonic = arguments['mnemonic'] as String; final mnemonic = arguments['mnemonic'] as String;
final mnemonicPassphrase = arguments['mnemonicPassphrase'] as String;
final from = arguments['from'] as int; final from = arguments['from'] as int;
final to = arguments['to'] as int; final to = arguments['to'] as int;
final network = arguments['network'] as NetworkType?; final network = arguments['network'] as NetworkType?;
if (!(network == null)) { if (!(network == null)) {
var derived = await isolateDerive(mnemonic, from, to, network); var derived = await isolateDerive(
mnemonic, mnemonicPassphrase, from, to, network);
sendPort.send(derived); sendPort.send(derived);
return; return;
} }
@ -192,13 +197,31 @@ void stop(ReceivePort port) {
} }
Future<Map<String, dynamic>> isolateDerive( Future<Map<String, dynamic>> isolateDerive(
String mnemonic, int from, int to, NetworkType _network) async { String mnemonic,
String mnemonicPassphrase,
int from,
int to,
NetworkType _network,
) async {
Map<String, dynamic> result = {}; Map<String, dynamic> result = {};
Map<String, dynamic> allReceive = {}; Map<String, dynamic> allReceive = {};
Map<String, dynamic> allChange = {}; Map<String, dynamic> allChange = {};
final root = getBip32Root(mnemonic, _network); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
for (int i = from; i < to; i++) { for (int i = from; i < to; i++) {
var currentNode = getBip32NodeFromRoot(0, i, root); final derivePathReceiving = constructDerivePath(
networkWIF: _network.wif,
chain: 0,
index: i,
);
var currentNode = await Bip32Utils.getBip32NodeFromRoot(
root,
derivePathReceiving,
);
var address = P2PKH( var address = P2PKH(
network: _network, data: PaymentData(pubkey: currentNode.publicKey)) network: _network, data: PaymentData(pubkey: currentNode.publicKey))
.data .data
@ -209,7 +232,15 @@ Future<Map<String, dynamic>> isolateDerive(
"address": address, "address": address,
}; };
currentNode = getBip32NodeFromRoot(1, i, root); final derivePathChange = constructDerivePath(
networkWIF: _network.wif,
chain: 0,
index: i,
);
currentNode = await Bip32Utils.getBip32NodeFromRoot(
root,
derivePathChange,
);
address = P2PKH( address = P2PKH(
network: _network, data: PaymentData(pubkey: currentNode.publicKey)) network: _network, data: PaymentData(pubkey: currentNode.publicKey))
.data .data
@ -230,6 +261,7 @@ Future<Map<String, dynamic>> isolateDerive(
Future<Map<String, dynamic>> isolateRestore( Future<Map<String, dynamic>> isolateRestore(
String mnemonic, String mnemonic,
String mnemonicPassphrase,
Coin coin, Coin coin,
int _latestSetId, int _latestSetId,
Map<dynamic, dynamic> _setDataMap, Map<dynamic, dynamic> _setDataMap,
@ -250,9 +282,19 @@ Future<Map<String, dynamic>> isolateRestore(
usedSerialNumbersSet.add(usedSerialNumbers[ind]); usedSerialNumbersSet.add(usedSerialNumbers[ind]);
} }
final root = getBip32Root(mnemonic, network); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
network,
);
while (currentIndex < lastFoundIndex + 50) { while (currentIndex < lastFoundIndex + 50) {
final mintKeyPair = getBip32NodeFromRoot(MINT_INDEX, currentIndex, root); final _derivePath = constructDerivePath(
networkWIF: network.wif,
chain: MINT_INDEX,
index: currentIndex,
);
final mintKeyPair =
await Bip32Utils.getBip32NodeFromRoot(root, _derivePath);
final mintTag = CreateTag( final mintTag = CreateTag(
Format.uint8listToString(mintKeyPair.privateKey!), Format.uint8listToString(mintKeyPair.privateKey!),
currentIndex, currentIndex,
@ -300,7 +342,14 @@ Future<Map<String, dynamic>> isolateRestore(
.log("amount $amount used $isUsed", level: LogLevel.Info); .log("amount $amount used $isUsed", level: LogLevel.Info);
} else { } else {
final keyPath = GetAesKeyPath(foundCoin[0] as String); final keyPath = GetAesKeyPath(foundCoin[0] as String);
final aesKeyPair = getBip32NodeFromRoot(JMINT_INDEX, keyPath, root); final derivePath = constructDerivePath(
networkWIF: network.wif,
chain: JMINT_INDEX,
index: keyPath,
);
final aesKeyPair =
await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
if (aesKeyPair.privateKey != null) { if (aesKeyPair.privateKey != null) {
final aesPrivateKey = final aesPrivateKey =
Format.uint8listToString(aesKeyPair.privateKey!); Format.uint8listToString(aesKeyPair.privateKey!);
@ -491,6 +540,7 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
String address, String address,
bool subtractFeeFromAmount, bool subtractFeeFromAmount,
String mnemonic, String mnemonic,
String mnemonicPassphrase,
int index, int index,
List<DartLelantusEntry> lelantusEntries, List<DartLelantusEntry> lelantusEntries,
int locktime, int locktime,
@ -521,8 +571,17 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
4294967295, 4294967295,
Uint8List(0), Uint8List(0),
); );
final derivePath = constructDerivePath(
final jmintKeyPair = getBip32Node(MINT_INDEX, index, mnemonic, _network); networkWIF: _network.wif,
chain: MINT_INDEX,
index: index,
);
final jmintKeyPair = await Bip32Utils.getBip32Node(
mnemonic,
mnemonicPassphrase,
_network,
derivePath,
);
final String jmintprivatekey = final String jmintprivatekey =
Format.uint8listToString(jmintKeyPair.privateKey!); Format.uint8listToString(jmintKeyPair.privateKey!);
@ -530,7 +589,17 @@ Future<dynamic> isolateCreateJoinSplitTransaction(
final keyPath = getMintKeyPath(changeToMint, jmintprivatekey, index, final keyPath = getMintKeyPath(changeToMint, jmintprivatekey, index,
isTestnet: coin == Coin.firoTestNet); isTestnet: coin == Coin.firoTestNet);
final aesKeyPair = getBip32Node(JMINT_INDEX, keyPath, mnemonic, _network); final _derivePath = constructDerivePath(
networkWIF: _network.wif,
chain: JMINT_INDEX,
index: keyPath,
);
final aesKeyPair = await Bip32Utils.getBip32Node(
mnemonic,
mnemonicPassphrase,
_network,
_derivePath,
);
final aesPrivateKey = Format.uint8listToString(aesKeyPair.privateKey!); final aesPrivateKey = Format.uint8listToString(aesKeyPair.privateKey!);
final jmintData = createJMintScript( final jmintData = createJMintScript(
@ -659,29 +728,15 @@ Future<int> getBlockHead(ElectrumX client) async {
} }
// end of isolates // end of isolates
bip32.BIP32 getBip32Node( String constructDerivePath({
int chain, int index, String mnemonic, NetworkType network) { // required DerivePathType derivePathType,
final root = getBip32Root(mnemonic, network); required int networkWIF,
int account = 0,
final node = getBip32NodeFromRoot(chain, index, root); required int chain,
return node; required int index,
} }) {
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple4<int, int, String, NetworkType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32NodeFromRoot(int chain, int index, bip32.BIP32 root) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0xd2: // firo mainnet wif case 0xd2: // firo mainnet wif
coinType = "136"; // firo mainnet coinType = "136"; // firo mainnet
break; break;
@ -689,41 +744,19 @@ bip32.BIP32 getBip32NodeFromRoot(int chain, int index, bip32.BIP32 root) {
coinType = "1"; // firo testnet coinType = "1"; // firo testnet
break; break;
default: default:
throw Exception("Invalid Bitcoin network type used!"); throw Exception("Invalid Firo network wif used!");
} }
final node = root.derivePath("m/44'/$coinType'/0'/$chain/$index"); int purpose;
return node; // switch (derivePathType) {
} // case DerivePathType.bip44:
purpose = 44;
// break;
// default:
// throw Exception("DerivePathType $derivePathType not supported");
// }
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple3<int, int, bip32.BIP32> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final firoNetworkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, firoNetworkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
Future<String> _getMintScriptWrapper( Future<String> _getMintScriptWrapper(
@ -795,6 +828,15 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
@override @override
bool validateAddress(String address) { bool validateAddress(String address) {
return Address.validateAddress(address, _network); return Address.validateAddress(address, _network);
@ -1178,12 +1220,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
// } // }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -2085,10 +2126,17 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
} }
// this should never fail as overwriting a mnemonic is big bad // this should never fail as overwriting a mnemonic is big bad
assert((await _secureStore.read(key: '${_walletId}_mnemonic')) == null); if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
longMutex = false;
throw Exception("Attempted to overwrite mnemonic on initialize new!");
}
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
await firoUpdateJIndex(<dynamic>[]); await firoUpdateJIndex(<dynamic>[]);
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
@ -2134,9 +2182,14 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
receiveDerivationsString == "{}") { receiveDerivationsString == "{}") {
GlobalEventBus.instance GlobalEventBus.instance
.fire(RefreshPercentChangedEvent(0.05, walletId)); .fire(RefreshPercentChangedEvent(0.05, walletId));
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final mnemonic = await mnemonicString;
await fillAddresses(mnemonic!, final mnemonicPassphrase =
numberOfThreads: Platform.numberOfProcessors - isolates.length - 1); await _secureStore.read(key: '${_walletId}_mnemonicPassphrase');
await fillAddresses(
mnemonic!,
mnemonicPassphrase!,
numberOfThreads: Platform.numberOfProcessors - isolates.length - 1,
);
} }
await checkReceivingAddressForTransactions(); await checkReceivingAddressForTransactions();
@ -2226,24 +2279,25 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
} }
Future<List<DartLelantusEntry>> _getLelantusEntry() async { Future<List<DartLelantusEntry>> _getLelantusEntry() async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
final List<LelantusCoin> lelantusCoins = await _getUnspentCoins(); final List<LelantusCoin> lelantusCoins = await _getUnspentCoins();
final root = await compute(
getBip32RootWrapper, final root = await Bip32Utils.getBip32Root(
Tuple2( _mnemonic!,
mnemonic!, _mnemonicPassphrase!,
_network, _network,
),
); );
final waitLelantusEntries = lelantusCoins.map((coin) async { final waitLelantusEntries = lelantusCoins.map((coin) async {
final keyPair = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, networkWIF: _network.wif,
Tuple3( chain: MINT_INDEX,
MINT_INDEX, index: coin.index,
coin.index,
root,
),
); );
final keyPair = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
if (keyPair.privateKey == null) { if (keyPair.privateKey == null) {
Logging.instance.log("error bad key", level: LogLevel.Error); Logging.instance.log("error bad key", level: LogLevel.Error);
return DartLelantusEntry(1, 0, 0, 0, 0, ''); return DartLelantusEntry(1, 0, 0, 0, 0, '');
@ -2887,16 +2941,21 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
} }
Future<String> _getMintHex(int amount, int index) async { Future<String> _getMintHex(int amount, int index) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final mintKeyPair = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple4( final derivePath = constructDerivePath(
MINT_INDEX, networkWIF: _network.wif,
index, chain: MINT_INDEX,
mnemonic!, index: index,
_network,
),
); );
final mintKeyPair = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
String keydata = Format.uint8listToString(mintKeyPair.privateKey!); String keydata = Format.uint8listToString(mintKeyPair.privateKey!);
String seedID = Format.uint8listToString(mintKeyPair.identifier); String seedID = Format.uint8listToString(mintKeyPair.identifier);
@ -3691,8 +3750,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
return address!.value; return address!.value;
} }
Future<void> fillAddresses(String suppliedMnemonic, Future<void> fillAddresses(
{int perBatch = 50, int numberOfThreads = 4}) async { String suppliedMnemonic,
String mnemonicPassphrase, {
int perBatch = 50,
int numberOfThreads = 4,
}) async {
if (numberOfThreads <= 0) { if (numberOfThreads <= 0) {
numberOfThreads = 1; numberOfThreads = 1;
} }
@ -3718,6 +3781,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
ReceivePort receivePort = await getIsolate({ ReceivePort receivePort = await getIsolate({
"function": "isolateDerive", "function": "isolateDerive",
"mnemonic": suppliedMnemonic, "mnemonic": suppliedMnemonic,
"mnemonicPassphrase": mnemonicPassphrase,
"from": start + i * perBatch, "from": start + i * perBatch,
"to": start + (i + 1) * perBatch, "to": start + (i + 1) * perBatch,
"network": _network, "network": _network,
@ -3757,8 +3821,8 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
/// [index] - This can be any integer >= 0 /// [index] - This can be any integer >= 0
Future<isar_models.Address> _generateAddressForChain( Future<isar_models.Address> _generateAddressForChain(
int chain, int index) async { int chain, int index) async {
// final wallet = await Hive.openBox(this._walletId); final _mnemonic = await mnemonicString;
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonicPassphrase = await mnemonicPassphrase;
Map<String, dynamic>? derivations; Map<String, dynamic>? derivations;
if (chain == 0) { if (chain == 0) {
final receiveDerivationsString = final receiveDerivationsString =
@ -3774,8 +3838,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
if (derivations!.isNotEmpty) { if (derivations!.isNotEmpty) {
if (derivations["$index"] == null) { if (derivations["$index"] == null) {
await fillAddresses(mnemonic!, await fillAddresses(
numberOfThreads: Platform.numberOfProcessors - isolates.length - 1); _mnemonic!,
_mnemonicPassphrase!,
numberOfThreads: Platform.numberOfProcessors - isolates.length - 1,
);
Logging.instance.log("calling _generateAddressForChain recursively", Logging.instance.log("calling _generateAddressForChain recursively",
level: LogLevel.Info); level: LogLevel.Info);
return _generateAddressForChain(chain, index); return _generateAddressForChain(chain, index);
@ -3792,8 +3859,18 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
: isar_models.AddressSubType.change, : isar_models.AddressSubType.change,
); );
} else { } else {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeWrapper, Tuple4(chain, index, mnemonic!, _network)); networkWIF: _network.wif,
chain: chain,
index: index,
);
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
final address = final address =
P2PKH(network: _network, data: PaymentData(pubkey: node.publicKey)) P2PKH(network: _network, data: PaymentData(pubkey: node.publicKey))
.data .data
@ -3882,8 +3959,13 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
await _recoverWalletFromBIP32SeedPhrase(mnemonic!, maxUnusedAddressGap); final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase(
_mnemonic!,
_mnemonicPassphrase!,
maxUnusedAddressGap,
);
longMutex = false; longMutex = false;
await refresh(); await refresh();
@ -4069,6 +4151,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -4109,13 +4192,22 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
// } // }
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic.trim(), maxUnusedAddressGap); mnemonic.trim(),
mnemonicPassphrase ?? "",
maxUnusedAddressGap,
);
await compute( await compute(
_setTestnetWrapper, _setTestnetWrapper,
@ -4151,6 +4243,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
Future<void> _makeDerivations( Future<void> _makeDerivations(
String suppliedMnemonic, String suppliedMnemonic,
String mnemonicPassphrase,
int maxUnusedAddressGap, int maxUnusedAddressGap,
) async { ) async {
List<isar_models.Address> receivingAddressArray = []; List<isar_models.Address> receivingAddressArray = [];
@ -4163,7 +4256,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
int receivingGapCounter = 0; int receivingGapCounter = 0;
int changeGapCounter = 0; int changeGapCounter = 0;
await fillAddresses(suppliedMnemonic, await fillAddresses(suppliedMnemonic, mnemonicPassphrase,
numberOfThreads: Platform.numberOfProcessors - isolates.length - 1); numberOfThreads: Platform.numberOfProcessors - isolates.length - 1);
final receiveDerivationsString = final receiveDerivationsString =
@ -4276,7 +4369,10 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
/// Recovers wallet from [suppliedMnemonic]. Expects a valid mnemonic. /// Recovers wallet from [suppliedMnemonic]. Expects a valid mnemonic.
Future<void> _recoverWalletFromBIP32SeedPhrase( Future<void> _recoverWalletFromBIP32SeedPhrase(
String suppliedMnemonic, int maxUnusedAddressGap) async { String suppliedMnemonic,
String mnemonicPassphrase,
int maxUnusedAddressGap,
) async {
longMutex = true; longMutex = true;
Logging.instance Logging.instance
.log("PROCESSORS ${Platform.numberOfProcessors}", level: LogLevel.Info); .log("PROCESSORS ${Platform.numberOfProcessors}", level: LogLevel.Info);
@ -4284,8 +4380,8 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
final latestSetId = await getLatestSetId(); final latestSetId = await getLatestSetId();
final setDataMap = getSetDataMap(latestSetId); final setDataMap = getSetDataMap(latestSetId);
final usedSerialNumbers = getUsedCoinSerials(); final usedSerialNumbers = getUsedCoinSerials();
final makeDerivations = final makeDerivations = _makeDerivations(
_makeDerivations(suppliedMnemonic, maxUnusedAddressGap); suppliedMnemonic, mnemonicPassphrase, maxUnusedAddressGap);
await Future.wait([ await Future.wait([
updateCachedId(walletId), updateCachedId(walletId),
@ -4307,12 +4403,15 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
Future<void> _restore(int latestSetId, Map<dynamic, dynamic> setDataMap, Future<void> _restore(int latestSetId, Map<dynamic, dynamic> setDataMap,
dynamic usedSerialNumbers) async { dynamic usedSerialNumbers) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
final dataFuture = _refreshTransactions(); final dataFuture = _refreshTransactions();
ReceivePort receivePort = await getIsolate({ ReceivePort receivePort = await getIsolate({
"function": "restore", "function": "restore",
"mnemonic": mnemonic, "mnemonic": _mnemonic,
"mnemonicPassphrase": _mnemonicPassphrase,
"coin": coin, "coin": coin,
"latestSetId": latestSetId, "latestSetId": latestSetId,
"setDataMap": setDataMap, "setDataMap": setDataMap,
@ -4422,8 +4521,8 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
Future<dynamic> _createJoinSplitTransaction( Future<dynamic> _createJoinSplitTransaction(
int spendAmount, String address, bool subtractFeeFromAmount) async { int spendAmount, String address, bool subtractFeeFromAmount) async {
// final price = await firoPrice; final _mnemonic = await mnemonicString;
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonicPassphrase = await mnemonicPassphrase;
final index = firoGetMintIndex(); final index = firoGetMintIndex();
final lelantusEntry = await _getLelantusEntry(); final lelantusEntry = await _getLelantusEntry();
final anonymitySets = await fetchAnonymitySets(); final anonymitySets = await fetchAnonymitySets();
@ -4436,7 +4535,8 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
"spendAmount": spendAmount, "spendAmount": spendAmount,
"address": address, "address": address,
"subtractFeeFromAmount": subtractFeeFromAmount, "subtractFeeFromAmount": subtractFeeFromAmount,
"mnemonic": mnemonic, "mnemonic": _mnemonic,
"mnemonicPassphrase": _mnemonicPassphrase,
"index": index, "index": index,
// "price": price, // "price": price,
"lelantusEntries": lelantusEntry, "lelantusEntries": lelantusEntry,

View file

@ -30,6 +30,7 @@ import 'package:stackwallet/services/node_service.dart';
import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -51,40 +52,15 @@ const String GENESIS_HASH_MAINNET =
const String GENESIS_HASH_TESTNET = const String GENESIS_HASH_TESTNET =
"4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0"; "4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0";
bip32.BIP32 getBip32Node( String constructDerivePath({
int chain, required DerivePathType derivePathType,
int index, required int networkWIF,
String mnemonic, int account = 0,
NetworkType network, required int chain,
DerivePathType derivePathType, required int index,
) { }) {
final root = getBip32Root(mnemonic, network);
final node = getBip32NodeFromRoot(chain, index, root, derivePathType);
return node;
}
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple5<int, int, String, NetworkType, DerivePathType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
args.item5,
);
}
bip32.BIP32 getBip32NodeFromRoot(
int chain,
int index,
bip32.BIP32 root,
DerivePathType derivePathType,
) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0xb0: // ltc mainnet wif case 0xb0: // ltc mainnet wif
coinType = "2"; // ltc mainnet coinType = "2"; // ltc mainnet
break; break;
@ -92,49 +68,25 @@ bip32.BIP32 getBip32NodeFromRoot(
coinType = "1"; // ltc testnet coinType = "1"; // ltc testnet
break; break;
default: default:
throw Exception("Invalid Litecoin network type used!"); throw Exception("Invalid Litecoin network wif used!");
} }
int purpose;
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); purpose = 44;
break;
case DerivePathType.bip49: case DerivePathType.bip49:
return root.derivePath("m/49'/$coinType'/0'/$chain/$index"); purpose = 49;
break;
case DerivePathType.bip84: case DerivePathType.bip84:
return root.derivePath("m/84'/$coinType'/0'/$chain/$index"); purpose = 84;
break;
default: default:
throw Exception("DerivePathType unsupported"); throw Exception("DerivePathType $derivePathType not supported");
}
} }
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple4<int, int, bip32.BIP32, DerivePathType> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final networkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
class LitecoinWallet extends CoinServiceAPI class LitecoinWallet extends CoinServiceAPI
@ -236,6 +188,15 @@ class LitecoinWallet extends CoinServiceAPI
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
@ -300,6 +261,7 @@ class LitecoinWallet extends CoinServiceAPI
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -339,14 +301,20 @@ class LitecoinWallet extends CoinServiceAPI
} }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic.trim(), mnemonic: mnemonic.trim(),
mnemonicPassphrase: mnemonicPassphrase ?? "",
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
); );
@ -389,15 +357,14 @@ class LitecoinWallet extends CoinServiceAPI
final Map<String, dynamic> receivingNodes = {}; final Map<String, dynamic> receivingNodes = {};
for (int j = 0; j < txCountBatchSize; j++) { for (int j = 0; j < txCountBatchSize; j++) {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, derivePathType: type,
Tuple4( networkWIF: root.network.wif,
chain, chain: chain,
index + j, index: index + j,
root,
type,
),
); );
final node = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
String addressString; String addressString;
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -515,6 +482,7 @@ class LitecoinWallet extends CoinServiceAPI
Future<void> _recoverWalletFromBIP32SeedPhrase({ Future<void> _recoverWalletFromBIP32SeedPhrase({
required String mnemonic, required String mnemonic,
required String mnemonicPassphrase,
int maxUnusedAddressGap = 20, int maxUnusedAddressGap = 20,
int maxNumberOfIndexesToCheck = 1000, int maxNumberOfIndexesToCheck = 1000,
bool isRescan = false, bool isRescan = false,
@ -528,7 +496,11 @@ class LitecoinWallet extends CoinServiceAPI
Map<String, Map<String, String>> p2shChangeDerivations = {}; Map<String, Map<String, String>> p2shChangeDerivations = {};
Map<String, Map<String, String>> p2wpkhChangeDerivations = {}; Map<String, Map<String, String>> p2wpkhChangeDerivations = {};
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
List<isar_models.Address> p2pkhReceiveAddressArray = []; List<isar_models.Address> p2pkhReceiveAddressArray = [];
List<isar_models.Address> p2shReceiveAddressArray = []; List<isar_models.Address> p2shReceiveAddressArray = [];
@ -1321,12 +1293,11 @@ class LitecoinWallet extends CoinServiceAPI
} }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -1463,13 +1434,17 @@ class LitecoinWallet extends CoinServiceAPI
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialAddresses = await Future.wait([ final initialAddresses = await Future.wait([
@ -1499,17 +1474,22 @@ class LitecoinWallet extends CoinServiceAPI
int index, int index,
DerivePathType derivePathType, DerivePathType derivePathType,
) async { ) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final node = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple5( final derivePath = constructDerivePath(
chain, derivePathType: derivePathType,
index, networkWIF: _network.wif,
mnemonic!, chain: chain,
_network, index: index,
derivePathType,
),
); );
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
String address; String address;
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -2888,9 +2868,12 @@ class LitecoinWallet extends CoinServiceAPI
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic!, mnemonic: _mnemonic!,
mnemonicPassphrase: _mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
isRescan: true, isRescan: true,

View file

@ -160,6 +160,7 @@ class Manager with ChangeNotifier {
_currentWallet.validateAddress(address); _currentWallet.validateAddress(address);
Future<List<String>> get mnemonic => _currentWallet.mnemonic; Future<List<String>> get mnemonic => _currentWallet.mnemonic;
Future<String?> get mnemonicPassphrase => _currentWallet.mnemonicPassphrase;
Future<bool> testNetworkConnection() => Future<bool> testNetworkConnection() =>
_currentWallet.testNetworkConnection(); _currentWallet.testNetworkConnection();
@ -168,6 +169,7 @@ class Manager with ChangeNotifier {
Future<void> initializeExisting() => _currentWallet.initializeExisting(); Future<void> initializeExisting() => _currentWallet.initializeExisting();
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -175,6 +177,7 @@ class Manager with ChangeNotifier {
try { try {
await _currentWallet.recoverFromMnemonic( await _currentWallet.recoverFromMnemonic(
mnemonic: mnemonic, mnemonic: mnemonic,
mnemonicPassphrase: mnemonicPassphrase,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
height: height, height: height,

View file

@ -314,7 +314,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _prefs.init(); await _prefs.init();
// this should never fail // this should never fail
if ((await _secureStorage.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
@ -365,6 +365,10 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _secureStorage.write( await _secureStorage.write(
key: '${_walletId}_mnemonic', value: wallet?.seed.trim()); key: '${_walletId}_mnemonic', value: wallet?.seed.trim());
await _secureStorage.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
walletInfo.address = wallet?.walletAddresses.address; walletInfo.address = wallet?.walletAddresses.address;
await DB.instance await DB.instance
.add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo); .add<WalletInfo>(boxName: WalletInfo.boxName, value: walletInfo);
@ -419,15 +423,23 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<List<String>> get mnemonic async { Future<List<String>> get mnemonic async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStorage.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@override
Future<String?> get mnemonicString =>
_secureStorage.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStorage.read(
key: '${_walletId}_mnemonicPassphrase',
);
@override @override
Future<Map<String, dynamic>> prepareSend({ Future<Map<String, dynamic>> prepareSend({
required String address, required String address,
@ -519,6 +531,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase, // not used at the moment
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -543,12 +556,17 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
// } // }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStorage.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStorage.write( await _secureStorage.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStorage.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await DB.instance await DB.instance
.put<dynamic>(boxName: walletId, key: "restoreHeight", value: height); .put<dynamic>(boxName: walletId, key: "restoreHeight", value: height);

View file

@ -30,6 +30,7 @@ import 'package:stackwallet/services/node_service.dart';
import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -51,87 +52,38 @@ const String GENESIS_HASH_MAINNET =
const String GENESIS_HASH_TESTNET = const String GENESIS_HASH_TESTNET =
"00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"; "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008";
bip32.BIP32 getBip32Node( String constructDerivePath({
int chain, required DerivePathType derivePathType,
int index, required int networkWIF,
String mnemonic, int account = 0,
NetworkType network, required int chain,
DerivePathType derivePathType, required int index,
) { }) {
final root = getBip32Root(mnemonic, network);
final node = getBip32NodeFromRoot(chain, index, root, derivePathType);
return node;
}
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple5<int, int, String, NetworkType, DerivePathType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
args.item5,
);
}
bip32.BIP32 getBip32NodeFromRoot(
int chain,
int index,
bip32.BIP32 root,
DerivePathType derivePathType,
) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0xb4: // nmc mainnet wif case 0xb4: // nmc mainnet wif
coinType = "7"; // nmc mainnet coinType = "7"; // nmc mainnet
break; break;
default: default:
throw Exception("Invalid Namecoin network type used!"); throw Exception("Invalid Namecoin network wif used!");
} }
int purpose;
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); purpose = 44;
break;
case DerivePathType.bip49: case DerivePathType.bip49:
return root.derivePath("m/49'/$coinType'/0'/$chain/$index"); purpose = 49;
break;
case DerivePathType.bip84: case DerivePathType.bip84:
return root.derivePath("m/84'/$coinType'/0'/$chain/$index"); purpose = 84;
break;
default: default:
throw Exception("DerivePathType must not be null."); throw Exception("DerivePathType $derivePathType not supported");
}
} }
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple4<int, int, bip32.BIP32, DerivePathType> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final networkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
class NamecoinWallet extends CoinServiceAPI class NamecoinWallet extends CoinServiceAPI
@ -231,6 +183,15 @@ class NamecoinWallet extends CoinServiceAPI
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
@ -295,6 +256,7 @@ class NamecoinWallet extends CoinServiceAPI
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -326,14 +288,21 @@ class NamecoinWallet extends CoinServiceAPI
} }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic.trim(), mnemonic: mnemonic.trim(),
mnemonicPassphrase: mnemonicPassphrase ?? "",
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
); );
@ -376,15 +345,14 @@ class NamecoinWallet extends CoinServiceAPI
final Map<String, dynamic> receivingNodes = {}; final Map<String, dynamic> receivingNodes = {};
for (int j = 0; j < txCountBatchSize; j++) { for (int j = 0; j < txCountBatchSize; j++) {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, derivePathType: type,
Tuple4( networkWIF: root.network.wif,
chain, chain: chain,
index + j, index: index + j,
root,
type,
),
); );
final node = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
String addressString; String addressString;
isar_models.AddressType addrType; isar_models.AddressType addrType;
switch (type) { switch (type) {
@ -505,6 +473,7 @@ class NamecoinWallet extends CoinServiceAPI
Future<void> _recoverWalletFromBIP32SeedPhrase({ Future<void> _recoverWalletFromBIP32SeedPhrase({
required String mnemonic, required String mnemonic,
required String mnemonicPassphrase,
int maxUnusedAddressGap = 20, int maxUnusedAddressGap = 20,
int maxNumberOfIndexesToCheck = 1000, int maxNumberOfIndexesToCheck = 1000,
bool isRescan = false, bool isRescan = false,
@ -518,7 +487,11 @@ class NamecoinWallet extends CoinServiceAPI
Map<String, Map<String, String>> p2shChangeDerivations = {}; Map<String, Map<String, String>> p2shChangeDerivations = {};
Map<String, Map<String, String>> p2wpkhChangeDerivations = {}; Map<String, Map<String, String>> p2wpkhChangeDerivations = {};
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
List<isar_models.Address> p2pkhReceiveAddressArray = []; List<isar_models.Address> p2pkhReceiveAddressArray = [];
List<isar_models.Address> p2shReceiveAddressArray = []; List<isar_models.Address> p2shReceiveAddressArray = [];
@ -1310,12 +1283,11 @@ class NamecoinWallet extends CoinServiceAPI
} }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -1444,13 +1416,17 @@ class NamecoinWallet extends CoinServiceAPI
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialAddresses = await Future.wait([ final initialAddresses = await Future.wait([
@ -1480,17 +1456,22 @@ class NamecoinWallet extends CoinServiceAPI
int index, int index,
DerivePathType derivePathType, DerivePathType derivePathType,
) async { ) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final node = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple5( final derivePath = constructDerivePath(
chain, derivePathType: derivePathType,
index, networkWIF: _network.wif,
mnemonic!, chain: chain,
_network, index: index,
derivePathType,
),
); );
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
String address; String address;
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -2602,6 +2583,8 @@ class NamecoinWallet extends CoinServiceAPI
case DerivePathType.bip84: case DerivePathType.bip84:
addressesP2WPKH.add(address); addressesP2WPKH.add(address);
break; break;
default:
throw Exception("DerivePathType unsupported");
} }
} }
} }
@ -2881,9 +2864,11 @@ class NamecoinWallet extends CoinServiceAPI
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic!, mnemonic: _mnemonic!,
mnemonicPassphrase: _mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
isRescan: true, isRescan: true,

View file

@ -29,6 +29,7 @@ import 'package:stackwallet/services/node_service.dart';
import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -49,85 +50,35 @@ const String GENESIS_HASH_MAINNET =
const String GENESIS_HASH_TESTNET = const String GENESIS_HASH_TESTNET =
"0000594ada5310b367443ee0afd4fa3d0bbd5850ea4e33cdc7d6a904a7ec7c90"; "0000594ada5310b367443ee0afd4fa3d0bbd5850ea4e33cdc7d6a904a7ec7c90";
bip32.BIP32 getBip32Node( String constructDerivePath({
int chain, required DerivePathType derivePathType,
int index, required int networkWIF,
String mnemonic, int account = 0,
NetworkType network, required int chain,
DerivePathType derivePathType, required int index,
) { }) {
final root = getBip32Root(mnemonic, network);
final node = getBip32NodeFromRoot(chain, index, root, derivePathType);
return node;
}
/// wrapper for compute()
bip32.BIP32 getBip32NodeWrapper(
Tuple5<int, int, String, NetworkType, DerivePathType> args,
) {
return getBip32Node(
args.item1,
args.item2,
args.item3,
args.item4,
args.item5,
);
}
bip32.BIP32 getBip32NodeFromRoot(
int chain,
int index,
bip32.BIP32 root,
DerivePathType derivePathType,
) {
String coinType; String coinType;
switch (root.network.wif) { switch (networkWIF) {
case 0x6c: // PART mainnet wif case 0x6c: // PART mainnet wif
coinType = "44"; // PART mainnet coinType = "44"; // PART mainnet
break; break;
default: default:
throw Exception("Invalid Particl network type used!"); throw Exception("Invalid Particl network wif used!");
} }
int purpose;
switch (derivePathType) { switch (derivePathType) {
case DerivePathType.bip44: case DerivePathType.bip44:
return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); purpose = 44;
break;
case DerivePathType.bip84: case DerivePathType.bip84:
return root.derivePath("m/84'/$coinType'/0'/$chain/$index"); purpose = 84;
break;
default: default:
throw Exception("DerivePathType $derivePathType not supported"); throw Exception("DerivePathType $derivePathType not supported");
} }
}
/// wrapper for compute() return "m/$purpose'/$coinType'/$account'/$chain/$index";
bip32.BIP32 getBip32NodeFromRootWrapper(
Tuple4<int, int, bip32.BIP32, DerivePathType> args,
) {
return getBip32NodeFromRoot(
args.item1,
args.item2,
args.item3,
args.item4,
);
}
bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) {
final seed = bip39.mnemonicToSeed(mnemonic);
final networkType = bip32.NetworkType(
wif: network.wif,
bip32: bip32.Bip32Type(
public: network.bip32.public,
private: network.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
/// wrapper for compute()
bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
return getBip32Root(args.item1, args.item2);
} }
class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB { class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
@ -226,6 +177,15 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<List<String>> get mnemonic => _getMnemonicList(); Future<List<String>> get mnemonic => _getMnemonicList();
@override
Future<String?> get mnemonicString =>
_secureStore.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStore.read(
key: '${_walletId}_mnemonicPassphrase',
);
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
@ -288,6 +248,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase,
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -322,14 +283,21 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic.trim(), mnemonic: mnemonic.trim(),
mnemonicPassphrase: mnemonicPassphrase ?? "",
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
); );
@ -372,15 +340,14 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
final Map<String, dynamic> receivingNodes = {}; final Map<String, dynamic> receivingNodes = {};
for (int j = 0; j < txCountBatchSize; j++) { for (int j = 0; j < txCountBatchSize; j++) {
final node = await compute( final derivePath = constructDerivePath(
getBip32NodeFromRootWrapper, derivePathType: type,
Tuple4( networkWIF: root.network.wif,
chain, chain: chain,
index + j, index: index + j,
root,
type,
),
); );
final node = await Bip32Utils.getBip32NodeFromRoot(root, derivePath);
String addressString; String addressString;
isar_models.AddressType addrType; isar_models.AddressType addrType;
switch (type) { switch (type) {
@ -487,6 +454,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<void> _recoverWalletFromBIP32SeedPhrase({ Future<void> _recoverWalletFromBIP32SeedPhrase({
required String mnemonic, required String mnemonic,
required String mnemonicPassphrase,
int maxUnusedAddressGap = 20, int maxUnusedAddressGap = 20,
int maxNumberOfIndexesToCheck = 1000, int maxNumberOfIndexesToCheck = 1000,
bool isRescan = false, bool isRescan = false,
@ -498,7 +466,11 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
Map<String, Map<String, String>> p2pkhChangeDerivations = {}; Map<String, Map<String, String>> p2pkhChangeDerivations = {};
Map<String, Map<String, String>> p2wpkhChangeDerivations = {}; Map<String, Map<String, String>> p2wpkhChangeDerivations = {};
final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
List<isar_models.Address> p2pkhReceiveAddressArray = []; List<isar_models.Address> p2pkhReceiveAddressArray = [];
List<isar_models.Address> p2wpkhReceiveAddressArray = []; List<isar_models.Address> p2wpkhReceiveAddressArray = [];
@ -1238,12 +1210,11 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
Future<List<String>> _getMnemonicList() async { Future<List<String>> _getMnemonicList() async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStore.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@ -1359,13 +1330,17 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
// this should never fail // this should never fail
if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
await _secureStore.write( await _secureStore.write(
key: '${_walletId}_mnemonic', key: '${_walletId}_mnemonic',
value: bip39.generateMnemonic(strength: 256)); value: bip39.generateMnemonic(strength: 256));
await _secureStore.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialAddresses = await Future.wait([ final initialAddresses = await Future.wait([
@ -1391,17 +1366,22 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
int index, int index,
DerivePathType derivePathType, DerivePathType derivePathType,
) async { ) async {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final node = await compute( final _mnemonicPassphrase = await mnemonicPassphrase;
getBip32NodeWrapper,
Tuple5( final derivePath = constructDerivePath(
chain, derivePathType: derivePathType,
index, networkWIF: _network.wif,
mnemonic!, chain: chain,
_network, index: index,
derivePathType,
),
); );
final node = await Bip32Utils.getBip32Node(
_mnemonic!,
_mnemonicPassphrase!,
_network,
derivePath,
);
final data = PaymentData(pubkey: node.publicKey); final data = PaymentData(pubkey: node.publicKey);
String address; String address;
isar_models.AddressType addrType; isar_models.AddressType addrType;
@ -2976,9 +2956,12 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _deleteDerivations(); await _deleteDerivations();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final _mnemonic = await mnemonicString;
final _mnemonicPassphrase = await mnemonicPassphrase;
await _recoverWalletFromBIP32SeedPhrase( await _recoverWalletFromBIP32SeedPhrase(
mnemonic: mnemonic!, mnemonic: _mnemonic!,
mnemonicPassphrase: _mnemonicPassphrase!,
maxUnusedAddressGap: maxUnusedAddressGap, maxUnusedAddressGap: maxUnusedAddressGap,
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
isRescan: true, isRescan: true,

View file

@ -319,7 +319,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _prefs.init(); await _prefs.init();
// this should never fail // this should never fail
if ((await _secureStorage.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null || (await mnemonicPassphrase) != null) {
throw Exception( throw Exception(
"Attempted to overwrite mnemonic on generate new wallet!"); "Attempted to overwrite mnemonic on generate new wallet!");
} }
@ -377,6 +377,10 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _secureStorage.write( await _secureStorage.write(
key: '${_walletId}_mnemonic', value: wallet?.seed.trim()); key: '${_walletId}_mnemonic', value: wallet?.seed.trim());
await _secureStorage.write(
key: '${_walletId}_mnemonicPassphrase',
value: "",
);
walletInfo.address = wallet?.walletAddresses.address; walletInfo.address = wallet?.walletAddresses.address;
await DB.instance await DB.instance
@ -427,15 +431,23 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<List<String>> get mnemonic async { Future<List<String>> get mnemonic async {
final mnemonicString = final _mnemonicString = await mnemonicString;
await _secureStorage.read(key: '${_walletId}_mnemonic'); if (_mnemonicString == null) {
if (mnemonicString == null) {
return []; return [];
} }
final List<String> data = mnemonicString.split(' '); final List<String> data = _mnemonicString.split(' ');
return data; return data;
} }
@override
Future<String?> get mnemonicString =>
_secureStorage.read(key: '${_walletId}_mnemonic');
@override
Future<String?> get mnemonicPassphrase => _secureStorage.read(
key: '${_walletId}_mnemonicPassphrase',
);
@override @override
Future<Map<String, dynamic>> prepareSend({ Future<Map<String, dynamic>> prepareSend({
required String address, required String address,
@ -528,6 +540,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
Future<void> recoverFromMnemonic({ Future<void> recoverFromMnemonic({
required String mnemonic, required String mnemonic,
String? mnemonicPassphrase, // not used at the moment
required int maxUnusedAddressGap, required int maxUnusedAddressGap,
required int maxNumberOfIndexesToCheck, required int maxNumberOfIndexesToCheck,
required int height, required int height,
@ -543,12 +556,17 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
try { try {
// check to make sure we aren't overwriting a mnemonic // check to make sure we aren't overwriting a mnemonic
// this should never fail // this should never fail
if ((await _secureStorage.read(key: '${_walletId}_mnemonic')) != null) { if ((await mnemonicString) != null ||
(await this.mnemonicPassphrase) != null) {
longMutex = false; longMutex = false;
throw Exception("Attempted to overwrite mnemonic on restore!"); throw Exception("Attempted to overwrite mnemonic on restore!");
} }
await _secureStorage.write( await _secureStorage.write(
key: '${_walletId}_mnemonic', value: mnemonic.trim()); key: '${_walletId}_mnemonic', value: mnemonic.trim());
await _secureStorage.write(
key: '${_walletId}_mnemonicPassphrase',
value: mnemonicPassphrase ?? "",
);
// extract seed height from 14 word seed // extract seed height from 14 word seed
if (seedLength == 14) { if (seedLength == 14) {

View file

@ -39,7 +39,8 @@ mixin PaynymWalletInterface {
late final int _minConfirms; late final int _minConfirms;
// passed in wallet functions // passed in wallet functions
late final Future<List<String>> Function() _getMnemonic; late final Future<String?> Function() _getMnemonicString;
late final Future<String?> Function() _getMnemonicPassphrase;
late final Future<int> Function() _getChainHeight; late final Future<int> Function() _getChainHeight;
late final Future<String> Function() _getCurrentChangeAddress; late final Future<String> Function() _getCurrentChangeAddress;
late final int Function({ late final int Function({
@ -66,11 +67,6 @@ mixin PaynymWalletInterface {
required String wif, required String wif,
required DerivePathType derivePathType, required DerivePathType derivePathType,
}) _addDerivation; }) _addDerivation;
late final Future<void> Function({
required int chain,
required DerivePathType derivePathType,
required Map<String, dynamic> derivationsToAdd,
}) _addDerivations;
// initializer // initializer
void initPaynymWalletInterface({ void initPaynymWalletInterface({
@ -83,7 +79,8 @@ mixin PaynymWalletInterface {
required SecureStorageInterface secureStorage, required SecureStorageInterface secureStorage,
required int dustLimitP2PKH, required int dustLimitP2PKH,
required int minConfirms, required int minConfirms,
required Future<List<String>> Function() getMnemonic, required Future<String?> Function() getMnemonicString,
required Future<String?> Function() getMnemonicPassphrase,
required Future<int> Function() getChainHeight, required Future<int> Function() getChainHeight,
required Future<String> Function() getCurrentChangeAddress, required Future<String> Function() getCurrentChangeAddress,
required int Function({ required int Function({
@ -115,12 +112,6 @@ mixin PaynymWalletInterface {
required DerivePathType derivePathType, required DerivePathType derivePathType,
}) })
addDerivation, addDerivation,
required Future<void> Function({
required int chain,
required DerivePathType derivePathType,
required Map<String, dynamic> derivationsToAdd,
})
addDerivations,
}) { }) {
_walletId = walletId; _walletId = walletId;
_walletName = walletName; _walletName = walletName;
@ -131,7 +122,8 @@ mixin PaynymWalletInterface {
_secureStorage = secureStorage; _secureStorage = secureStorage;
_dustLimitP2PKH = dustLimitP2PKH; _dustLimitP2PKH = dustLimitP2PKH;
_minConfirms = minConfirms; _minConfirms = minConfirms;
_getMnemonic = getMnemonic; _getMnemonicString = getMnemonicString;
_getMnemonicPassphrase = getMnemonicPassphrase;
_getChainHeight = getChainHeight; _getChainHeight = getChainHeight;
_getCurrentChangeAddress = getCurrentChangeAddress; _getCurrentChangeAddress = getCurrentChangeAddress;
_estimateTxFee = estimateTxFee; _estimateTxFee = estimateTxFee;
@ -141,7 +133,6 @@ mixin PaynymWalletInterface {
_refresh = refresh; _refresh = refresh;
_checkChangeAddressForTransactions = checkChangeAddressForTransactions; _checkChangeAddressForTransactions = checkChangeAddressForTransactions;
_addDerivation = addDerivation; _addDerivation = addDerivation;
_addDerivations = addDerivations;
} }
// convenience getter // convenience getter
@ -186,7 +177,8 @@ mixin PaynymWalletInterface {
int index, int index,
) async { ) async {
final myPrivateKey = await deriveReceivingPrivateKey( final myPrivateKey = await deriveReceivingPrivateKey(
mnemonic: await _getMnemonic(), mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
index: index, index: index,
); );
@ -244,26 +236,39 @@ mixin PaynymWalletInterface {
} }
// generate bip32 payment code root // generate bip32 payment code root
Future<bip32.BIP32> getRootNode({ Future<bip32.BIP32> _getRootNode({
required List<String> mnemonic, required String mnemonic,
required String mnemonicPassphrase,
}) async { }) async {
final root = await Bip32Utils.getBip32Root(mnemonic.join(" "), _network); final root = await Bip32Utils.getBip32Root(
mnemonic,
mnemonicPassphrase,
_network,
);
return root; return root;
} }
Future<Uint8List> deriveNotificationPrivateKey({ Future<Uint8List> deriveNotificationPrivateKey({
required List<String> mnemonic, required String mnemonic,
required String mnemonicPassphrase,
}) async { }) async {
final root = await getRootNode(mnemonic: mnemonic); final root = await _getRootNode(
mnemonic: mnemonic,
mnemonicPassphrase: mnemonicPassphrase,
);
final node = root.derivePath(kPaynymDerivePath).derive(0); final node = root.derivePath(kPaynymDerivePath).derive(0);
return node.privateKey!; return node.privateKey!;
} }
Future<Uint8List> deriveReceivingPrivateKey({ Future<Uint8List> deriveReceivingPrivateKey({
required List<String> mnemonic, required String mnemonic,
required String mnemonicPassphrase,
required int index, required int index,
}) async { }) async {
final root = await getRootNode(mnemonic: mnemonic); final root = await _getRootNode(
mnemonic: mnemonic,
mnemonicPassphrase: mnemonicPassphrase,
);
final node = root.derivePath(kPaynymDerivePath).derive(index); final node = root.derivePath(kPaynymDerivePath).derive(index);
return node.privateKey!; return node.privateKey!;
} }
@ -282,8 +287,10 @@ mixin PaynymWalletInterface {
} }
Future<Uint8List> signWithNotificationKey(Uint8List data) async { Future<Uint8List> signWithNotificationKey(Uint8List data) async {
final privateKey = final privateKey = await deriveNotificationPrivateKey(
await deriveNotificationPrivateKey(mnemonic: await _getMnemonic()); mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
);
final pair = btc_dart.ECPair.fromPrivateKey(privateKey, network: _network); final pair = btc_dart.ECPair.fromPrivateKey(privateKey, network: _network);
final signed = pair.sign(SHA256Digest().process(data)); final signed = pair.sign(SHA256Digest().process(data));
return signed; return signed;
@ -303,8 +310,10 @@ mixin PaynymWalletInterface {
throw PaynymSendException( throw PaynymSendException(
"No notification transaction sent to $paymentCode"); "No notification transaction sent to $paymentCode");
} else { } else {
final myPrivateKey = final myPrivateKey = await deriveNotificationPrivateKey(
await deriveNotificationPrivateKey(mnemonic: await _getMnemonic()); mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
);
final sendToAddress = await nextUnusedSendAddressFrom( final sendToAddress = await nextUnusedSendAddressFrom(
pCode: paymentCode, pCode: paymentCode,
privateKey: myPrivateKey, privateKey: myPrivateKey,
@ -749,8 +758,10 @@ mixin PaynymWalletInterface {
final pubKey = designatedInput.scriptSigAsm!.split(" ")[1].fromHex; final pubKey = designatedInput.scriptSigAsm!.split(" ")[1].fromHex;
final myPrivateKey = final myPrivateKey = await deriveNotificationPrivateKey(
await deriveNotificationPrivateKey(mnemonic: await _getMnemonic()); mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
);
final S = SecretPoint(myPrivateKey, pubKey); final S = SecretPoint(myPrivateKey, pubKey);
@ -888,12 +899,18 @@ mixin PaynymWalletInterface {
const maxCount = 2147483647; const maxCount = 2147483647;
assert(maxNumberOfIndexesToCheck < maxCount); assert(maxNumberOfIndexesToCheck < maxCount);
final mnemonic = await _getMnemonic(); final mnemonic = (await _getMnemonicString())!;
final mnemonicPassphrase = (await _getMnemonicPassphrase())!;
final mySendPrivateKey = final mySendPrivateKey = await deriveNotificationPrivateKey(
await deriveNotificationPrivateKey(mnemonic: mnemonic); mnemonic: mnemonic,
final receivingNode = mnemonicPassphrase: mnemonicPassphrase,
(await getRootNode(mnemonic: mnemonic)).derivePath(kPaynymDerivePath); );
final receivingNode = (await _getRootNode(
mnemonic: mnemonic,
mnemonicPassphrase: mnemonicPassphrase,
))
.derivePath(kPaynymDerivePath);
List<Address> addresses = []; List<Address> addresses = [];
int receivingGapCounter = 0; int receivingGapCounter = 0;
@ -1140,7 +1157,10 @@ mixin PaynymWalletInterface {
if (storedAddress != null) { if (storedAddress != null) {
return storedAddress; return storedAddress;
} else { } else {
final root = await getRootNode(mnemonic: await _getMnemonic()); final root = await _getRootNode(
mnemonic: (await _getMnemonicString())!,
mnemonicPassphrase: (await _getMnemonicPassphrase())!,
);
final node = root.derivePath(kPaynymDerivePath); final node = root.derivePath(kPaynymDerivePath);
final paymentCode = PaymentCode.initFromPubKey( final paymentCode = PaymentCode.initFromPubKey(
node.publicKey, node.publicKey,

View file

@ -5,28 +5,124 @@ import 'package:flutter/foundation.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
abstract class Bip32Utils { abstract class Bip32Utils {
static bip32.BIP32 getBip32RootSync(String mnemonic, NetworkType network) { // =============================== get root ==================================
final seed = bip39.mnemonicToSeed(mnemonic); static bip32.BIP32 getBip32RootSync(
final networkType = bip32.NetworkType( String mnemonic,
wif: network.wif, String mnemonicPassphrase,
NetworkType networkType,
) {
final seed = bip39.mnemonicToSeed(mnemonic, passphrase: mnemonicPassphrase);
final _networkType = bip32.NetworkType(
wif: networkType.wif,
bip32: bip32.Bip32Type( bip32: bip32.Bip32Type(
public: network.bip32.public, public: networkType.bip32.public,
private: network.bip32.private, private: networkType.bip32.private,
), ),
); );
final root = bip32.BIP32.fromSeed(seed, networkType); final root = bip32.BIP32.fromSeed(seed, _networkType);
return root; return root;
} }
static Future<bip32.BIP32> getBip32Root( static Future<bip32.BIP32> getBip32Root(
String mnemonic, NetworkType network) async { String mnemonic,
final root = await compute(_getBip32RootWrapper, Tuple2(mnemonic, network)); String mnemonicPassphrase,
NetworkType networkType,
) async {
final root = await compute(
_getBip32RootWrapper,
Tuple3(
mnemonic,
mnemonicPassphrase,
networkType,
),
);
return root; return root;
} }
/// wrapper for compute() /// wrapper for compute()
static bip32.BIP32 _getBip32RootWrapper(Tuple2<String, NetworkType> args) { static bip32.BIP32 _getBip32RootWrapper(
return getBip32RootSync(args.item1, args.item2); Tuple3<String, String, NetworkType> args,
) {
return getBip32RootSync(
args.item1,
args.item2,
args.item3,
);
}
// =========================== get node from root ============================
static bip32.BIP32 getBip32NodeFromRootSync(
bip32.BIP32 root,
String derivePath,
) {
return root.derivePath(derivePath);
}
static Future<bip32.BIP32> getBip32NodeFromRoot(
bip32.BIP32 root,
String derivePath,
) async {
final node = await compute(
_getBip32NodeFromRootWrapper,
Tuple2(
root,
derivePath,
),
);
return node;
}
/// wrapper for compute()
static bip32.BIP32 _getBip32NodeFromRootWrapper(
Tuple2<bip32.BIP32, String> args,
) {
return getBip32NodeFromRootSync(
args.item1,
args.item2,
);
}
// =============================== get node ==================================
static bip32.BIP32 getBip32NodeSync(
String mnemonic,
String mnemonicPassphrase,
NetworkType network,
String derivePath,
) {
final root = getBip32RootSync(mnemonic, mnemonicPassphrase, network);
final node = getBip32NodeFromRootSync(root, derivePath);
return node;
}
static Future<bip32.BIP32> getBip32Node(
String mnemonic,
String mnemonicPassphrase,
NetworkType networkType,
String derivePath,
) async {
final node = await compute(
_getBip32NodeWrapper,
Tuple4(
mnemonic,
mnemonicPassphrase,
networkType,
derivePath,
),
);
return node;
}
/// wrapper for compute()
static bip32.BIP32 _getBip32NodeWrapper(
Tuple4<String, String, NetworkType, String> args,
) {
return getBip32NodeSync(
args.item1,
args.item2,
args.item3,
args.item4,
);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -353,6 +353,11 @@ class MockManager extends _i1.Mock implements _i11.Manager {
returnValue: _i8.Future<List<String>>.value(<String>[]), returnValue: _i8.Future<List<String>>.value(<String>[]),
) as _i8.Future<List<String>>); ) as _i8.Future<List<String>>);
@override @override
_i8.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i8.Future<String?>.value(),
) as _i8.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -464,6 +469,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
@override @override
_i8.Future<void> recoverFromMnemonic({ _i8.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -474,6 +480,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -314,6 +314,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -425,6 +430,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -435,6 +441,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -312,6 +312,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -423,6 +428,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -433,6 +439,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -621,6 +621,11 @@ class MockManager extends _i1.Mock implements _i12.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -732,6 +737,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -742,6 +748,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -408,6 +408,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i6.Future<List<String>>.value(<String>[]), returnValue: _i6.Future<List<String>>.value(<String>[]),
) as _i6.Future<List<String>>); ) as _i6.Future<List<String>>);
@override @override
_i6.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i6.Future<String?>.value(),
) as _i6.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -519,6 +524,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i6.Future<void> recoverFromMnemonic({ _i6.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -529,6 +535,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -408,6 +408,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i6.Future<List<String>>.value(<String>[]), returnValue: _i6.Future<List<String>>.value(<String>[]),
) as _i6.Future<List<String>>); ) as _i6.Future<List<String>>);
@override @override
_i6.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i6.Future<String?>.value(),
) as _i6.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -519,6 +524,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i6.Future<void> recoverFromMnemonic({ _i6.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -529,6 +535,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -408,6 +408,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i6.Future<List<String>>.value(<String>[]), returnValue: _i6.Future<List<String>>.value(<String>[]),
) as _i6.Future<List<String>>); ) as _i6.Future<List<String>>);
@override @override
_i6.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i6.Future<String?>.value(),
) as _i6.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -519,6 +524,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i6.Future<void> recoverFromMnemonic({ _i6.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -529,6 +535,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -183,6 +183,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -294,6 +299,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -304,6 +310,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -406,6 +406,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i6.Future<List<String>>.value(<String>[]), returnValue: _i6.Future<List<String>>.value(<String>[]),
) as _i6.Future<List<String>>); ) as _i6.Future<List<String>>);
@override @override
_i6.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i6.Future<String?>.value(),
) as _i6.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -517,6 +522,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i6.Future<void> recoverFromMnemonic({ _i6.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -527,6 +533,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -621,6 +621,11 @@ class MockManager extends _i1.Mock implements _i12.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -732,6 +737,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -742,6 +748,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -462,6 +462,11 @@ class MockManager extends _i1.Mock implements _i12.Manager {
returnValue: _i8.Future<List<String>>.value(<String>[]), returnValue: _i8.Future<List<String>>.value(<String>[]),
) as _i8.Future<List<String>>); ) as _i8.Future<List<String>>);
@override @override
_i8.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i8.Future<String?>.value(),
) as _i8.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -573,6 +578,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
@override @override
_i8.Future<void> recoverFromMnemonic({ _i8.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -583,6 +589,7 @@ class MockManager extends _i1.Mock implements _i12.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -183,6 +183,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -294,6 +299,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -304,6 +310,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -183,6 +183,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -294,6 +299,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -304,6 +310,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -398,6 +398,11 @@ class MockManager extends _i1.Mock implements _i11.Manager {
returnValue: _i8.Future<List<String>>.value(<String>[]), returnValue: _i8.Future<List<String>>.value(<String>[]),
) as _i8.Future<List<String>>); ) as _i8.Future<List<String>>);
@override @override
_i8.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i8.Future<String?>.value(),
) as _i8.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -509,6 +514,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
@override @override
_i8.Future<void> recoverFromMnemonic({ _i8.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -519,6 +525,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -398,6 +398,11 @@ class MockManager extends _i1.Mock implements _i11.Manager {
returnValue: _i8.Future<List<String>>.value(<String>[]), returnValue: _i8.Future<List<String>>.value(<String>[]),
) as _i8.Future<List<String>>); ) as _i8.Future<List<String>>);
@override @override
_i8.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i8.Future<String?>.value(),
) as _i8.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -509,6 +514,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
@override @override
_i8.Future<void> recoverFromMnemonic({ _i8.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -519,6 +525,7 @@ class MockManager extends _i1.Mock implements _i11.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -183,6 +183,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -294,6 +299,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -304,6 +310,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -183,6 +183,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -294,6 +299,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -304,6 +310,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -406,6 +406,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i6.Future<List<String>>.value(<String>[]), returnValue: _i6.Future<List<String>>.value(<String>[]),
) as _i6.Future<List<String>>); ) as _i6.Future<List<String>>);
@override @override
_i6.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i6.Future<String?>.value(),
) as _i6.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -517,6 +522,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i6.Future<void> recoverFromMnemonic({ _i6.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -527,6 +533,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -663,6 +663,11 @@ class MockManager extends _i1.Mock implements _i15.Manager {
returnValue: _i8.Future<List<String>>.value(<String>[]), returnValue: _i8.Future<List<String>>.value(<String>[]),
) as _i8.Future<List<String>>); ) as _i8.Future<List<String>>);
@override @override
_i8.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i8.Future<String?>.value(),
) as _i8.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -774,6 +779,7 @@ class MockManager extends _i1.Mock implements _i15.Manager {
@override @override
_i8.Future<void> recoverFromMnemonic({ _i8.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -784,6 +790,7 @@ class MockManager extends _i1.Mock implements _i15.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -406,6 +406,11 @@ class MockManager extends _i1.Mock implements _i9.Manager {
returnValue: _i6.Future<List<String>>.value(<String>[]), returnValue: _i6.Future<List<String>>.value(<String>[]),
) as _i6.Future<List<String>>); ) as _i6.Future<List<String>>);
@override @override
_i6.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i6.Future<String?>.value(),
) as _i6.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -517,6 +522,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
@override @override
_i6.Future<void> recoverFromMnemonic({ _i6.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -527,6 +533,7 @@ class MockManager extends _i1.Mock implements _i9.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -185,6 +185,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -296,6 +301,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -306,6 +312,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -184,6 +184,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -295,6 +300,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -305,6 +311,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -183,6 +183,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -294,6 +299,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -304,6 +310,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -225,6 +225,11 @@ class MockManager extends _i1.Mock implements _i8.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -336,6 +341,7 @@ class MockManager extends _i1.Mock implements _i8.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -346,6 +352,7 @@ class MockManager extends _i1.Mock implements _i8.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -185,6 +185,11 @@ class MockManager extends _i1.Mock implements _i5.Manager {
returnValue: _i7.Future<List<String>>.value(<String>[]), returnValue: _i7.Future<List<String>>.value(<String>[]),
) as _i7.Future<List<String>>); ) as _i7.Future<List<String>>);
@override @override
_i7.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i7.Future<String?>.value(),
) as _i7.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -296,6 +301,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
@override @override
_i7.Future<void> recoverFromMnemonic({ _i7.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -306,6 +312,7 @@ class MockManager extends _i1.Mock implements _i5.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

View file

@ -211,6 +211,16 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
returnValue: _i10.Future<List<String>>.value(<String>[]), returnValue: _i10.Future<List<String>>.value(<String>[]),
) as _i10.Future<List<String>>); ) as _i10.Future<List<String>>);
@override @override
_i10.Future<String?> get mnemonicString => (super.noSuchMethod(
Invocation.getter(#mnemonicString),
returnValue: _i10.Future<String?>.value(),
) as _i10.Future<String?>);
@override
_i10.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i10.Future<String?>.value(),
) as _i10.Future<String?>);
@override
_i10.Future<int> get maxFee => (super.noSuchMethod( _i10.Future<int> get maxFee => (super.noSuchMethod(
Invocation.getter(#maxFee), Invocation.getter(#maxFee),
returnValue: _i10.Future<int>.value(0), returnValue: _i10.Future<int>.value(0),
@ -634,14 +644,18 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
) as _i10.Future<void>); ) as _i10.Future<void>);
@override @override
_i10.Future<void> fillAddresses( _i10.Future<void> fillAddresses(
String? suppliedMnemonic, { String? suppliedMnemonic,
String? mnemonicPassphrase, {
int? perBatch = 50, int? perBatch = 50,
int? numberOfThreads = 4, int? numberOfThreads = 4,
}) => }) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#fillAddresses, #fillAddresses,
[suppliedMnemonic], [
suppliedMnemonic,
mnemonicPassphrase,
],
{ {
#perBatch: perBatch, #perBatch: perBatch,
#numberOfThreads: numberOfThreads, #numberOfThreads: numberOfThreads,
@ -669,6 +683,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
@override @override
_i10.Future<void> recoverFromMnemonic({ _i10.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -679,6 +694,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -528,6 +528,11 @@ class MockManager extends _i1.Mock implements _i6.Manager {
returnValue: _i18.Future<List<String>>.value(<String>[]), returnValue: _i18.Future<List<String>>.value(<String>[]),
) as _i18.Future<List<String>>); ) as _i18.Future<List<String>>);
@override @override
_i18.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i18.Future<String?>.value(),
) as _i18.Future<String?>);
@override
bool get isConnected => (super.noSuchMethod( bool get isConnected => (super.noSuchMethod(
Invocation.getter(#isConnected), Invocation.getter(#isConnected),
returnValue: false, returnValue: false,
@ -639,6 +644,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
@override @override
_i18.Future<void> recoverFromMnemonic({ _i18.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -649,6 +655,7 @@ class MockManager extends _i1.Mock implements _i6.Manager {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,
@ -845,6 +852,16 @@ class MockCoinServiceAPI extends _i1.Mock implements _i7.CoinServiceAPI {
returnValue: _i18.Future<List<String>>.value(<String>[]), returnValue: _i18.Future<List<String>>.value(<String>[]),
) as _i18.Future<List<String>>); ) as _i18.Future<List<String>>);
@override @override
_i18.Future<String?> get mnemonicString => (super.noSuchMethod(
Invocation.getter(#mnemonicString),
returnValue: _i18.Future<String?>.value(),
) as _i18.Future<String?>);
@override
_i18.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i18.Future<String?>.value(),
) as _i18.Future<String?>);
@override
bool get hasCalledExit => (super.noSuchMethod( bool get hasCalledExit => (super.noSuchMethod(
Invocation.getter(#hasCalledExit), Invocation.getter(#hasCalledExit),
returnValue: false, returnValue: false,
@ -925,6 +942,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i7.CoinServiceAPI {
@override @override
_i18.Future<void> recoverFromMnemonic({ _i18.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -935,6 +953,7 @@ class MockCoinServiceAPI extends _i1.Mock implements _i7.CoinServiceAPI {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,
@ -1130,6 +1149,16 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
returnValue: _i18.Future<List<String>>.value(<String>[]), returnValue: _i18.Future<List<String>>.value(<String>[]),
) as _i18.Future<List<String>>); ) as _i18.Future<List<String>>);
@override @override
_i18.Future<String?> get mnemonicString => (super.noSuchMethod(
Invocation.getter(#mnemonicString),
returnValue: _i18.Future<String?>.value(),
) as _i18.Future<String?>);
@override
_i18.Future<String?> get mnemonicPassphrase => (super.noSuchMethod(
Invocation.getter(#mnemonicPassphrase),
returnValue: _i18.Future<String?>.value(),
) as _i18.Future<String?>);
@override
_i18.Future<int> get maxFee => (super.noSuchMethod( _i18.Future<int> get maxFee => (super.noSuchMethod(
Invocation.getter(#maxFee), Invocation.getter(#maxFee),
returnValue: _i18.Future<int>.value(0), returnValue: _i18.Future<int>.value(0),
@ -1553,14 +1582,18 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
) as _i18.Future<void>); ) as _i18.Future<void>);
@override @override
_i18.Future<void> fillAddresses( _i18.Future<void> fillAddresses(
String? suppliedMnemonic, { String? suppliedMnemonic,
String? mnemonicPassphrase, {
int? perBatch = 50, int? perBatch = 50,
int? numberOfThreads = 4, int? numberOfThreads = 4,
}) => }) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
#fillAddresses, #fillAddresses,
[suppliedMnemonic], [
suppliedMnemonic,
mnemonicPassphrase,
],
{ {
#perBatch: perBatch, #perBatch: perBatch,
#numberOfThreads: numberOfThreads, #numberOfThreads: numberOfThreads,
@ -1588,6 +1621,7 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
@override @override
_i18.Future<void> recoverFromMnemonic({ _i18.Future<void> recoverFromMnemonic({
required String? mnemonic, required String? mnemonic,
String? mnemonicPassphrase,
required int? maxUnusedAddressGap, required int? maxUnusedAddressGap,
required int? maxNumberOfIndexesToCheck, required int? maxNumberOfIndexesToCheck,
required int? height, required int? height,
@ -1598,6 +1632,7 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
[], [],
{ {
#mnemonic: mnemonic, #mnemonic: mnemonic,
#mnemonicPassphrase: mnemonicPassphrase,
#maxUnusedAddressGap: maxUnusedAddressGap, #maxUnusedAddressGap: maxUnusedAddressGap,
#maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, #maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
#height: height, #height: height,

File diff suppressed because it is too large Load diff