restore fix

This commit is contained in:
fosse 2023-08-25 11:12:07 -04:00
parent fe05f5a53d
commit e72f196c23
11 changed files with 272 additions and 223 deletions

View file

@ -7,9 +7,20 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
}
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
BitcoinRestoreWalletFromSeedCredentials(
{required String name, required String password, required this.mnemonic, WalletInfo? walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
BitcoinRestoreWalletFromSeedCredentials({
required String name,
required String password,
required this.mnemonic,
DerivationType? derivationType,
String? derivationPath,
WalletInfo? walletInfo,
}) : super(
name: name,
password: password,
walletInfo: walletInfo,
derivationType: derivationType,
derivationPath: derivationPath,
);
final String mnemonic;
}

View file

@ -107,14 +107,25 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save();
await wallet.init();
return wallet;
}
static Future<List<DerivationType>> compareDerivationMethods(
{required mnemonic, required Node node}) async {
return [DerivationType.unknown];
{required String mnemonic, required Node node}) async {
// if the mnemonic is 12 words, then it could be electrum 1.0,
// if the mnemonic is 24 words, then it could be electrum 2.0
// bip39 is possible with any number of words
int wordCount = mnemonic.split(" ").length;
if (wordCount == 24) {
return [DerivationType.bip39, DerivationType.electrum1];
} else if (wordCount == 12) {
return [DerivationType.bip39, DerivationType.electrum2];
} else {
return [DerivationType.bip39];
}
}
static Future<List<DerivationInfo>> getDerivationsFromMnemonic(

View file

@ -47,8 +47,8 @@ class ElectrumWallletSnapshot {
var regularAddressIndex = 0;
var changeAddressIndex = 0;
final derivationType = data['derivationType'] as DerivationType;
final derivationPath = data['derivationPath'] as String?;
final derivationType = data['derivationType'] as DerivationType? ?? DerivationType.bip39;
final derivationPath = data['derivationPath'] as String? ?? "m/0'/1";
try {
regularAddressIndex = int.parse(data['account_index'] as String? ?? '0');

View file

@ -5,10 +5,15 @@ abstract class WalletCredentials {
required this.name,
this.height,
this.walletInfo,
this.password});
this.password,
this.derivationType,
this.derivationPath,
});
final String name;
final int? height;
String? password;
DerivationType? derivationType;
String? derivationPath;
WalletInfo? walletInfo;
}

View file

@ -15,6 +15,10 @@ enum DerivationType {
nano,
@HiveField(3)
bip39,
@HiveField(4)
electrum1,
@HiveField(5)
electrum2,
}
class DerivationInfo {

View file

@ -22,16 +22,20 @@ class NanoNewWalletCredentials extends WalletCredentials {
}
class NanoRestoreWalletFromSeedCredentials extends WalletCredentials {
NanoRestoreWalletFromSeedCredentials(
{required String name,
required this.mnemonic,
this.derivationType,
int height = 0,
String? password})
: super(name: name, password: password, height: height);
NanoRestoreWalletFromSeedCredentials({
required String name,
required this.mnemonic,
int height = 0,
String? password,
DerivationType? derivationType,
}) : super(
name: name,
password: password,
height: height,
derivationType: derivationType,
);
final String mnemonic;
final DerivationType? derivationType;
}
class NanoWalletLoadingException implements Exception {

View file

@ -1,163 +1,164 @@
part of 'bitcoin.dart';
class CWBitcoin extends Bitcoin {
@override
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
@override
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({
required String name,
required String mnemonic,
required String password})
=> BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
@override
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({
required String name,
required String password,
required String wif,
WalletInfo? walletInfo})
=> BitcoinRestoreWalletFromWIFCredentials(name: name, password: password, wif: wif, walletInfo: walletInfo);
@override
WalletCredentials createBitcoinNewWalletCredentials({
required String name,
WalletInfo? walletInfo})
=> BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
@override
List<String> getWordList() => wordlist;
@override
Map<String, String> getWalletKeys(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
final keys = bitcoinWallet.keys;
return <String, String>{
'wif': keys.wif,
'privateKey': keys.privateKey,
'publicKey': keys.publicKey
};
}
@override
List<TransactionPriority> getTransactionPriorities()
=> BitcoinTransactionPriority.all;
List<TransactionPriority> getLitecoinTransactionPriorities()
=> LitecoinTransactionPriority.all;
@override
TransactionPriority deserializeBitcoinTransactionPriority(int raw)
=> BitcoinTransactionPriority.deserialize(raw: raw);
@override
TransactionPriority deserializeLitecoinTransactionPriority(int raw)
=> LitecoinTransactionPriority.deserialize(raw: raw);
@override
int getFeeRate(Object wallet, TransactionPriority priority) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeRate(priority);
}
@override
Future<void> generateNewAddress(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.walletAddresses.generateNewAddress();
}
@override
Object createBitcoinTransactionCredentials(List<Output> outputs, {required TransactionPriority priority, int? feeRate})
=> BitcoinTransactionCredentials(
outputs.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount))
.toList(),
priority: priority as BitcoinTransactionPriority,
feeRate: feeRate);
@override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, {TransactionPriority? priority, required int feeRate})
=> BitcoinTransactionCredentials(
outputs,
priority: priority != null ? priority as BitcoinTransactionPriority : null,
feeRate: feeRate);
@override
List<String> getAddresses(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => addr.address)
.toList();
}
@override
String getAddress(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.address;
}
@override
String formatterBitcoinAmountToString({required int amount})
=> bitcoinAmountToString(amount: amount);
@override
double formatterBitcoinAmountToDouble({required int amount})
=> bitcoinAmountToDouble(amount: amount);
@override
int formatterStringDoubleToBitcoinAmount(String amount)
=> stringDoubleToBitcoinAmount(amount);
@override
TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
@override
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate)
=> (priority as BitcoinTransactionPriority).labelWithRate(rate);
@override
List<Unspent> getUnspents(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.unspentCoins
.map((BitcoinUnspent bitcoinUnspent) => Unspent(
bitcoinUnspent.address.address,
bitcoinUnspent.hash,
bitcoinUnspent.value,
bitcoinUnspent.vout))
.toList();
}
void updateUnspents(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.updateUnspent();
}
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return BitcoinWalletService(walletInfoSource, unspentCoinSource);
}
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource);
}
@override
TransactionPriority getBitcoinTransactionPriorityMedium()
=> BitcoinTransactionPriority.medium;
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials(
{required String name,
required String mnemonic,
required String password,
DerivationType? derivationType,
String? derivationPath}) =>
BitcoinRestoreWalletFromSeedCredentials(
name: name,
mnemonic: mnemonic,
password: password,
derivationType: derivationType,
derivationPath: derivationPath);
@override
TransactionPriority getLitecoinTransactionPriorityMedium()
=> LitecoinTransactionPriority.medium;
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials(
{required String name,
required String password,
required String wif,
WalletInfo? walletInfo}) =>
BitcoinRestoreWalletFromWIFCredentials(
name: name, password: password, wif: wif, walletInfo: walletInfo);
@override
TransactionPriority getBitcoinTransactionPrioritySlow()
=> BitcoinTransactionPriority.slow;
WalletCredentials createBitcoinNewWalletCredentials(
{required String name, WalletInfo? walletInfo}) =>
BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
@override
TransactionPriority getLitecoinTransactionPrioritySlow()
=> LitecoinTransactionPriority.slow;
}
List<String> getWordList() => wordlist;
@override
Map<String, String> getWalletKeys(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
final keys = bitcoinWallet.keys;
return <String, String>{
'wif': keys.wif,
'privateKey': keys.privateKey,
'publicKey': keys.publicKey
};
}
@override
List<TransactionPriority> getTransactionPriorities() => BitcoinTransactionPriority.all;
List<TransactionPriority> getLitecoinTransactionPriorities() => LitecoinTransactionPriority.all;
@override
TransactionPriority deserializeBitcoinTransactionPriority(int raw) =>
BitcoinTransactionPriority.deserialize(raw: raw);
@override
TransactionPriority deserializeLitecoinTransactionPriority(int raw) =>
LitecoinTransactionPriority.deserialize(raw: raw);
@override
int getFeeRate(Object wallet, TransactionPriority priority) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeRate(priority);
}
@override
Future<void> generateNewAddress(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.walletAddresses.generateNewAddress();
}
@override
Object createBitcoinTransactionCredentials(List<Output> outputs,
{required TransactionPriority priority, int? feeRate}) =>
BitcoinTransactionCredentials(
outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount))
.toList(),
priority: priority as BitcoinTransactionPriority,
feeRate: feeRate);
@override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
{TransactionPriority? priority, required int feeRate}) =>
BitcoinTransactionCredentials(outputs,
priority: priority != null ? priority as BitcoinTransactionPriority : null,
feeRate: feeRate);
@override
List<String> getAddresses(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.addresses
.map((BitcoinAddressRecord addr) => addr.address)
.toList();
}
@override
String getAddress(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.walletAddresses.address;
}
@override
String formatterBitcoinAmountToString({required int amount}) =>
bitcoinAmountToString(amount: amount);
@override
double formatterBitcoinAmountToDouble({required int amount}) =>
bitcoinAmountToDouble(amount: amount);
@override
int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount);
@override
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate) =>
(priority as BitcoinTransactionPriority).labelWithRate(rate);
@override
List<Unspent> getUnspents(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.unspentCoins
.map((BitcoinUnspent bitcoinUnspent) => Unspent(bitcoinUnspent.address.address,
bitcoinUnspent.hash, bitcoinUnspent.value, bitcoinUnspent.vout))
.toList();
}
void updateUnspents(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
await bitcoinWallet.updateUnspent();
}
WalletService createBitcoinWalletService(
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return BitcoinWalletService(walletInfoSource, unspentCoinSource);
}
WalletService createLitecoinWalletService(
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource);
}
@override
TransactionPriority getBitcoinTransactionPriorityMedium() => BitcoinTransactionPriority.medium;
@override
TransactionPriority getLitecoinTransactionPriorityMedium() => LitecoinTransactionPriority.medium;
@override
TransactionPriority getBitcoinTransactionPrioritySlow() => BitcoinTransactionPriority.slow;
@override
TransactionPriority getLitecoinTransactionPrioritySlow() => LitecoinTransactionPriority.slow;
}

View file

@ -317,7 +317,7 @@ class WalletRestorePage extends BasePage {
walletRestoreViewModel.state = IsExecutingState();
List<DerivationType> derivationTypes =
await walletRestoreViewModel.getDerivationType(_credentials());
await walletRestoreViewModel.getDerivationTypes(_credentials());
if (derivationTypes[0] == DerivationType.unknown || derivationTypes.length > 1) {
// push screen to choose the derivation type:

View file

@ -35,37 +35,40 @@ abstract class WalletCreationVMBase with Store {
final Box<WalletInfo> _walletInfoSource;
final AppStore _appStore;
bool nameExists(String name)
=> walletCreationService.exists(name);
bool nameExists(String name) => walletCreationService.exists(name);
bool typeExists(WalletType type)
=> walletCreationService.typeExists(type);
bool typeExists(WalletType type) => walletCreationService.typeExists(type);
Future<void> create({dynamic options, RestoredWallet? restoreWallet}) async {
final type = restoreWallet?.type ?? this.type;
try {
state = IsExecutingState();
if (name.isEmpty) {
name = await generateName();
name = await generateName();
}
walletCreationService.checkIfExists(name);
final dirPath = await pathForWalletDir(name: name, type: type);
final path = await pathForWallet(name: name, type: type);
print("options: $options");
final credentials = restoreWallet != null
? getCredentialsFromRestoredWallet(options, restoreWallet)
: getCredentials(options);
final walletInfo = WalletInfo.external(
id: WalletBase.idFor(name, type),
name: name,
type: type,
isRecovery: isRecovery,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
path: path,
dirPath: dirPath,
address: '',
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven);
id: WalletBase.idFor(name, type),
name: name,
type: type,
isRecovery: isRecovery,
restoreHeight: credentials.height ?? 0,
date: DateTime.now(),
path: path,
dirPath: dirPath,
address: '',
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven,
derivationPath: credentials.derivationPath,
derivationType: credentials.derivationType,
);
credentials.walletInfo = walletInfo;
final wallet = restoreWallet != null
? await processFromRestoredWallet(credentials, restoreWallet)
@ -80,15 +83,16 @@ abstract class WalletCreationVMBase with Store {
state = FailureState(e.toString());
}
}
WalletCredentials getCredentials(dynamic options) =>
WalletCredentials getCredentials(dynamic options) => throw UnimplementedError();
Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError();
WalletCredentials getCredentialsFromRestoredWallet(
dynamic options, RestoredWallet restoreWallet) =>
throw UnimplementedError();
Future<WalletBase> process(WalletCredentials credentials) =>
throw UnimplementedError();
WalletCredentials getCredentialsFromRestoredWallet(dynamic options, RestoredWallet restoreWallet) =>
throw UnimplementedError();
Future<WalletBase> processFromRestoredWallet(WalletCredentials credentials, RestoredWallet restoreWallet) =>
Future<WalletBase> processFromRestoredWallet(
WalletCredentials credentials, RestoredWallet restoreWallet) =>
throw UnimplementedError();
}

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cw_bitcoin/bitcoin_wallet_service.dart';
import 'package:cw_core/node.dart';
import 'package:cw_nano/nano_wallet.dart';
import 'package:cw_nano/nano_wallet_service.dart';
import 'package:hive/hive.dart';
@ -64,6 +65,8 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
final password = generateWalletPassword();
final height = options['height'] as int? ?? 0;
name = options['name'] as String;
DerivationType? derivationType = options["derivationType"] as DerivationType?;
String? derivationPath = options["derivationPath"] as String?;
if (mode == WalletRestoreMode.seed) {
final seed = options['seed'] as String;
@ -73,7 +76,12 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
name: name, height: height, mnemonic: seed, password: password);
case WalletType.bitcoin:
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
name: name, mnemonic: seed, password: password);
name: name,
mnemonic: seed,
password: password,
derivationType: derivationType,
derivationPath: derivationPath,
);
case WalletType.litecoin:
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
name: name, mnemonic: seed, password: password);
@ -88,7 +96,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
name: name,
mnemonic: seed,
password: password,
derivationType: options["derivationType"] as DerivationType,
derivationType: derivationType,
);
default:
break;
@ -100,60 +108,61 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
final spendKey = options['spendKey'] as String?;
final address = options['address'] as String?;
if (type == WalletType.monero) {
return monero!.createMoneroRestoreWalletFromKeysCredentials(
switch (type) {
case WalletType.monero:
return monero!.createMoneroRestoreWalletFromKeysCredentials(
name: name,
height: height,
spendKey: spendKey!,
viewKey: viewKey!,
address: address!,
password: password,
language: 'English');
}
language: 'English',
);
if (type == WalletType.haven) {
return haven!.createHavenRestoreWalletFromKeysCredentials(
case WalletType.haven:
return haven!.createHavenRestoreWalletFromKeysCredentials(
name: name,
height: height,
spendKey: spendKey!,
viewKey: viewKey!,
address: address!,
password: password,
language: 'English');
}
language: 'English',
);
if (type == WalletType.ethereum) {
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
name: name,
privateKey: options['private_key'] as String,
password: password,
);
}
case WalletType.ethereum:
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
name: name,
privateKey: options['private_key'] as String,
password: password,
);
if (type == WalletType.nano) {
return nano!.createNanoRestoreWalletFromKeysCredentials(
name: name,
password: password,
seedKey: options['private_key'] as String,
derivationType: options["derivationType"] as DerivationType,
);
case WalletType.nano:
return nano!.createNanoRestoreWalletFromKeysCredentials(
name: name,
password: password,
seedKey: options['private_key'] as String,
derivationType: options["derivationType"] as DerivationType,
);
default:
break;
}
}
throw Exception('Unexpected type: ${type.toString()}');
}
@override
Future<List<DerivationType>> getDerivationType(dynamic options) async {
Future<List<DerivationType>> getDerivationTypes(dynamic options) async {
final seedKey = options['private_key'] as String?;
final mnemonic = options['seed'] as String?;
WalletType walletType = options['walletType'] as WalletType;
var appStore = getIt.get<AppStore>();
var node = appStore.settingsStore.getCurrentNode(walletType);
var node = appStore.settingsStore.getCurrentNode(walletType) as Node;
switch (type) {
case WalletType.bitcoin:
return BitcoinWalletService.compareDerivationMethods(mnemonic: mnemonic, node: node);
return BitcoinWalletService.compareDerivationMethods(mnemonic: mnemonic!, node: node);
// case WalletType.litecoin:
// return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
// name: name, mnemonic: seed, password: password);

View file

@ -90,7 +90,7 @@ class Unspent {
abstract class Bitcoin {
TransactionPriority getMediumTransactionPriority();
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password});
WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({required String name, required String mnemonic, required String password, DerivationType? derivationType, String? derivationPath});
WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo});
WalletCredentials createBitcoinNewWalletCredentials({required String name, WalletInfo? walletInfo});
List<String> getWordList();