mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 03:59:23 +00:00
Fix issues with Creating Electrum and Restoring Bip39
This commit is contained in:
parent
02d719431a
commit
2cc115e557
16 changed files with 92 additions and 62 deletions
|
@ -1,11 +1,11 @@
|
|||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
Map<DerivationType, List<DerivationInfo>> bitcoin_derivations = {
|
||||
DerivationType.electrum2: [
|
||||
DerivationType.electrum: [
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/0'/1",
|
||||
description: "Electrum 2",
|
||||
derivationType: DerivationType.electrum,
|
||||
derivationPath: "m/0'/0",
|
||||
description: "Electrum",
|
||||
script_type: "p2wpkh",
|
||||
),
|
||||
],
|
||||
|
|
|
@ -65,8 +65,7 @@ String bufferToBin(Uint8List data) {
|
|||
return q2;
|
||||
}
|
||||
|
||||
String encode(Uint8List originalData) {
|
||||
final data = Uint8List.fromList(originalData); // Create a modifiable copy
|
||||
String encode(Uint8List data) {
|
||||
final dataBitLen = data.length * 8;
|
||||
final wordBitLen = logBase(wordlist.length, 2).ceil();
|
||||
final wordCount = (dataBitLen / wordBitLen).floor();
|
||||
|
@ -98,9 +97,10 @@ Future<String> generateElectrumMnemonic({int strength = 264, String prefix = seg
|
|||
var result = '';
|
||||
|
||||
do {
|
||||
final originalBytes = await secRandom(byteCount);
|
||||
// create a modifiable copy, however I'm not sure why this is necessary
|
||||
final bytes = Uint8List.fromList(originalBytes);
|
||||
// final originalBytes = await secRandom(byteCount);
|
||||
// // create a modifiable copy, however I'm not sure why this is necessary
|
||||
// final bytes = Uint8List.fromList(originalBytes);
|
||||
final bytes = await secRandom(byteCount);
|
||||
maskBytes(bytes, strength);
|
||||
result = encode(bytes);
|
||||
} while (!prefixMatches(result, [prefix]).first);
|
||||
|
|
|
@ -89,7 +89,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
case DerivationType.bip39:
|
||||
seedBytes = await bip39.mnemonicToSeed(mnemonic);
|
||||
break;
|
||||
case DerivationType.electrum2:
|
||||
case DerivationType.electrum:
|
||||
default:
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
break;
|
||||
|
@ -121,7 +121,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network);
|
||||
|
||||
walletInfo.derivationInfo ??= DerivationInfo(
|
||||
derivationType: snp.derivationType ?? DerivationType.electrum2,
|
||||
derivationType: snp.derivationType ?? DerivationType.electrum,
|
||||
derivationPath: snp.derivationPath,
|
||||
);
|
||||
|
||||
|
@ -131,7 +131,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
late Uint8List seedBytes;
|
||||
|
||||
switch (walletInfo.derivationInfo!.derivationType) {
|
||||
case DerivationType.electrum2:
|
||||
case DerivationType.electrum:
|
||||
seedBytes = await mnemonicToSeedBytes(snp.mnemonic);
|
||||
break;
|
||||
case DerivationType.bip39:
|
||||
|
|
|
@ -10,10 +10,6 @@ class BitcoinNewWalletCredentials extends WalletCredentials {
|
|||
: super(
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
derivationInfo: DerivationInfo(
|
||||
derivationType: derivationType,
|
||||
derivationPath: derivationPath,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:cw_bitcoin/address_to_output_script.dart';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||
import 'package:cw_bitcoin/electrum.dart';
|
||||
import 'package:cw_bitcoin/script_hash.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
|
@ -19,10 +13,6 @@ import 'package:cw_core/wallet_info.dart';
|
|||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cw_bitcoin/bitcoin_derivations.dart';
|
||||
import 'package:bip32/bip32.dart' as bip32;
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
|
||||
class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
||||
|
@ -41,7 +31,7 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
|||
credentials.walletInfo?.network = network.value;
|
||||
|
||||
final wallet = await BitcoinWalletBase.create(
|
||||
mnemonic: await generateElectrumMnemonic(strength: 132),
|
||||
mnemonic: await generateElectrumMnemonic(),
|
||||
password: credentials.password!,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
|
@ -117,7 +107,7 @@ class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
|
|||
@override
|
||||
Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
if (!validateMnemonic(credentials.mnemonic)) {
|
||||
if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
|
||||
throw BitcoinMnemonicIsIncorrectException();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ abstract class ElectrumWalletBase
|
|||
CryptoCurrency? currency})
|
||||
: hd = currency == CryptoCurrency.bch
|
||||
? bitcoinCashHDWallet(seedBytes)
|
||||
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/0"),
|
||||
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
|
||||
.derivePath(walletInfo.derivationInfo?.derivationPath ?? "m/0'/0"),
|
||||
syncStatus = NotConnectedSyncStatus(),
|
||||
_password = password,
|
||||
_feeRates = <int>[],
|
||||
|
@ -592,6 +593,8 @@ abstract class ElectrumWalletBase
|
|||
? SegwitAddresType.p2wpkh.toString()
|
||||
: walletInfo.addressPageType.toString(),
|
||||
'balance': balance[currency]?.toJSON(),
|
||||
'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index,
|
||||
'derivationPath': walletInfo.derivationInfo?.derivationPath,
|
||||
});
|
||||
|
||||
int feeRate(TransactionPriority priority) {
|
||||
|
|
|
@ -51,8 +51,9 @@ class ElectrumWalletSnapshot {
|
|||
var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
||||
var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
|
||||
|
||||
final derivationType = data['derivationType'] as DerivationType? ?? DerivationType.bip39;
|
||||
final derivationPath = data['derivationPath'] as String? ?? "m/0'/1";
|
||||
final derivationType =
|
||||
DerivationType.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
||||
final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
|
||||
|
||||
try {
|
||||
regularAddressIndexByType = {
|
||||
|
|
|
@ -7,7 +7,7 @@ abstract class WalletCredentials {
|
|||
this.seedPhraseLength,
|
||||
this.walletInfo,
|
||||
this.password,
|
||||
DerivationInfo? derivationInfo,
|
||||
this.derivationInfo,
|
||||
}) {
|
||||
if (this.walletInfo != null && derivationInfo != null) {
|
||||
this.walletInfo!.derivationInfo = derivationInfo;
|
||||
|
@ -19,4 +19,5 @@ abstract class WalletCredentials {
|
|||
int? seedPhraseLength;
|
||||
String? password;
|
||||
WalletInfo? walletInfo;
|
||||
DerivationInfo? derivationInfo;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@ enum DerivationType {
|
|||
@HiveField(3)
|
||||
bip39,
|
||||
@HiveField(4)
|
||||
electrum1,
|
||||
@HiveField(5)
|
||||
electrum2,
|
||||
electrum,
|
||||
}
|
||||
@HiveType(typeId: DerivationInfo.typeId)
|
||||
class DerivationInfo extends HiveObject {
|
||||
|
@ -28,7 +26,7 @@ class DerivationInfo extends HiveObject {
|
|||
this.derivationPath,
|
||||
this.balance = "",
|
||||
this.address = "",
|
||||
this.height = 0,
|
||||
this.transactionsCount = 0,
|
||||
this.script_type,
|
||||
this.description,
|
||||
});
|
||||
|
@ -37,7 +35,7 @@ class DerivationInfo extends HiveObject {
|
|||
|
||||
String balance;
|
||||
String address;
|
||||
int height;
|
||||
int transactionsCount;
|
||||
DerivationType? derivationType;
|
||||
String? derivationPath;
|
||||
final String? script_type;
|
||||
|
|
|
@ -260,10 +260,10 @@ class CWBitcoin extends Bitcoin {
|
|||
Future<List<DerivationType>> compareDerivationMethods(
|
||||
{required String mnemonic, required Node node}) async {
|
||||
if (await checkIfMnemonicIsElectrum2(mnemonic)) {
|
||||
return [DerivationType.electrum2];
|
||||
return [DerivationType.electrum];
|
||||
}
|
||||
|
||||
return [DerivationType.bip39, DerivationType.electrum2];
|
||||
return [DerivationType.bip39, DerivationType.electrum];
|
||||
}
|
||||
|
||||
int _countOccurrences(String str, String charToCount) {
|
||||
|
@ -286,7 +286,7 @@ class CWBitcoin extends Bitcoin {
|
|||
|
||||
for (DerivationType dType in bitcoin_derivations.keys) {
|
||||
late Uint8List seedBytes;
|
||||
if (dType == DerivationType.electrum2) {
|
||||
if (dType == DerivationType.electrum) {
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
} else if (dType == DerivationType.bip39) {
|
||||
seedBytes = bip39.mnemonicToSeed(mnemonic);
|
||||
|
@ -300,7 +300,7 @@ class CWBitcoin extends Bitcoin {
|
|||
description: dInfo.description,
|
||||
script_type: dInfo.script_type,
|
||||
);
|
||||
var node = bip32.BIP32.fromSeed(seedBytes);
|
||||
var hd = bip32.BIP32.fromSeed(seedBytes);
|
||||
|
||||
String derivationPath = dInfoCopy.derivationPath!;
|
||||
int derivationDepth = _countOccurrences(derivationPath, "/");
|
||||
|
@ -308,29 +308,67 @@ class CWBitcoin extends Bitcoin {
|
|||
derivationPath += "/0/0";
|
||||
dInfoCopy.derivationPath = dInfoCopy.derivationPath! + "/0";
|
||||
}
|
||||
node = node.derivePath(derivationPath);
|
||||
hd = hd.derivePath(derivationPath);
|
||||
|
||||
// var hd = btc.HDWallet.fromSeed(
|
||||
// seedBytes,
|
||||
// network: node.type == WalletType.bitcoin ? btc.bitcoin : litecoinNetwork,
|
||||
// ).derivePath(dInfoCopy.derivationPath!);
|
||||
|
||||
// if (addressType == P2pkhAddressType.p2pkh)
|
||||
// return generateP2PKHAddress(hd: hd, index: index, network: network);
|
||||
//
|
||||
// if (addressType == SegwitAddresType.p2tr)
|
||||
// return generateP2TRAddress(hd: hd, index: index, network: network);
|
||||
//
|
||||
// if (addressType == SegwitAddresType.p2wsh)
|
||||
// return generateP2WSHAddress(hd: hd, index: index, network: network);
|
||||
//
|
||||
// if (addressType == P2shAddressType.p2wpkhInP2sh)
|
||||
// return generateP2SHAddress(hd: hd, index: index, network: network);
|
||||
|
||||
String? address;
|
||||
switch (dInfoCopy.script_type) {
|
||||
case "p2wpkh":
|
||||
// address = generateP2WPKHAddress(
|
||||
// hd: hd,
|
||||
// index: 0,
|
||||
// network: node.type == WalletType.bitcoin
|
||||
// ? BitcoinNetwork.mainnet
|
||||
// : LitecoinNetwork.mainnet);
|
||||
address = btc
|
||||
.P2WPKH(
|
||||
data: new btc.PaymentData(pubkey: node.publicKey),
|
||||
data: new btc.PaymentData(pubkey: hd.publicKey),
|
||||
network: btc.bitcoin,
|
||||
)
|
||||
.data
|
||||
.address;
|
||||
break;
|
||||
case "p2pkh":
|
||||
default:
|
||||
// address = generateP2PKHAddress(
|
||||
// hd: hd,
|
||||
// index: 0,
|
||||
// network: node.type == WalletType.bitcoin
|
||||
// ? BitcoinNetwork.mainnet
|
||||
// : LitecoinNetwork.mainnet);
|
||||
address = btc
|
||||
.P2PKH(
|
||||
data: new btc.PaymentData(pubkey: node.publicKey),
|
||||
network: btc.bitcoin,
|
||||
)
|
||||
data: new btc.PaymentData(pubkey: hd.publicKey),
|
||||
network: btc.bitcoin,
|
||||
)
|
||||
.data
|
||||
.address;
|
||||
break;
|
||||
// case "p2wpkh-p2sh":
|
||||
// address = generateP2SHAddress(
|
||||
// hd: hd,
|
||||
// index: 0,
|
||||
// network: node.type == WalletType.bitcoin
|
||||
// ? BitcoinNetwork.mainnet
|
||||
// : LitecoinNetwork.mainnet);
|
||||
// break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
final sh = scriptHash(address!, network: BitcoinNetwork.mainnet);
|
||||
|
@ -339,7 +377,7 @@ class CWBitcoin extends Bitcoin {
|
|||
final balance = await electrumClient.getBalance(sh);
|
||||
dInfoCopy.balance = balance.entries.first.value.toString();
|
||||
dInfoCopy.address = address;
|
||||
dInfoCopy.height = history.length;
|
||||
dInfoCopy.transactionsCount = history.length;
|
||||
|
||||
list.add(dInfoCopy);
|
||||
} catch (e) {
|
||||
|
@ -349,7 +387,7 @@ class CWBitcoin extends Bitcoin {
|
|||
}
|
||||
|
||||
// sort the list such that derivations with the most transactions are first:
|
||||
list.sort((a, b) => b.height.compareTo(a.height));
|
||||
list.sort((a, b) => b.transactionsCount.compareTo(a.transactionsCount));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
|
|
@ -767,7 +767,7 @@ Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
|
|||
derivationPath: walletInfo.derivationPath,
|
||||
derivationType: walletInfo.derivationType,
|
||||
address: walletInfo.address,
|
||||
height: walletInfo.restoreHeight,
|
||||
transactionsCount: walletInfo.restoreHeight,
|
||||
);
|
||||
await walletInfo.save();
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ class WalletRestoreChooseDerivationPage extends BasePage {
|
|||
),
|
||||
),
|
||||
Text(
|
||||
"${S.current.transactions}: ${derivation.height}",
|
||||
"${S.current.transactions}: ${derivation.transactionsCount}",
|
||||
style: Theme.of(context).primaryTextTheme.labelMedium!.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
|
|
@ -360,7 +360,7 @@ class WalletRestorePage extends BasePage {
|
|||
int derivationsWithHistory = 0;
|
||||
int derivationWithHistoryIndex = 0;
|
||||
for (int i = 0; i < derivations.length; i++) {
|
||||
if (derivations[i].height > 0) {
|
||||
if (derivations[i].transactionsCount > 0) {
|
||||
derivationsWithHistory++;
|
||||
derivationWithHistoryIndex = i;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
|||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
derivationType: derivationInfo.derivationType!,
|
||||
derivationType: derivationInfo!.derivationType!,
|
||||
derivationPath: derivationInfo.derivationPath!,
|
||||
);
|
||||
case WalletType.bitcoinCash:
|
||||
|
@ -115,7 +115,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
|||
name: name,
|
||||
mnemonic: restoreWallet.mnemonicSeed ?? '',
|
||||
password: password,
|
||||
derivationType: derivationInfo.derivationType!);
|
||||
derivationType: derivationInfo!.derivationType!);
|
||||
case WalletType.polygon:
|
||||
return polygon!.createPolygonRestoreWalletFromSeedCredentials(
|
||||
name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password);
|
||||
|
|
|
@ -71,7 +71,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
dirPath: dirPath,
|
||||
address: '',
|
||||
showIntroCakePayCard: (!walletCreationService.typeExists(type)) && type != WalletType.haven,
|
||||
derivationInfo: getDefaultDerivation(),
|
||||
derivationInfo: credentials.derivationInfo ?? getDefaultDerivation(),
|
||||
);
|
||||
|
||||
credentials.walletInfo = walletInfo;
|
||||
|
@ -89,7 +89,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
DerivationInfo getDefaultDerivation() {
|
||||
DerivationInfo? getDefaultDerivation() {
|
||||
switch (this.type) {
|
||||
case WalletType.nano:
|
||||
return DerivationInfo(
|
||||
|
@ -97,11 +97,12 @@ abstract class WalletCreationVMBase with Store {
|
|||
);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
default:
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.electrum2,
|
||||
derivationPath: "m/0'/1",
|
||||
derivationType: DerivationType.electrum,
|
||||
derivationPath: "m/0'/0",
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -204,6 +204,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
|
||||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
String? mnemonic = credentials['seed'] as String?;
|
||||
return bitcoin!.getDerivationsFromMnemonic(mnemonic: mnemonic!, node: node);
|
||||
case WalletType.nano:
|
||||
|
@ -226,7 +227,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
derivationType: DerivationType.nano,
|
||||
balance: nanoUtil!.getRawAsUsableString(standardInfo!.balance, nanoUtil!.rawPerNano),
|
||||
address: standardInfo.address!,
|
||||
height: standardInfo.confirmationHeight,
|
||||
transactionsCount: standardInfo.confirmationHeight,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -235,7 +236,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
derivationType: DerivationType.bip39,
|
||||
balance: nanoUtil!.getRawAsUsableString(bip39Info!.balance, nanoUtil!.rawPerNano),
|
||||
address: bip39Info.address!,
|
||||
height: bip39Info.confirmationHeight,
|
||||
transactionsCount: bip39Info.confirmationHeight,
|
||||
));
|
||||
}
|
||||
break;
|
||||
|
@ -254,6 +255,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.compareDerivationMethods(mnemonic: mnemonic!, node: node);
|
||||
case WalletType.nano:
|
||||
return nanoUtil!.compareDerivationMethods(
|
||||
|
|
Loading…
Reference in a new issue