Bip39 minor enhancements (#1416)

* minor enhancements

* rename bitcoin_derivations -> electrum_derivations
This commit is contained in:
Matthew Fosse 2024-04-29 16:31:44 -07:00 committed by GitHub
parent a008c1f2dd
commit 59f339ba90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 80 additions and 58 deletions

View file

@ -1,6 +1,6 @@
import 'package:cw_core/wallet_info.dart';
Map<DerivationType, List<DerivationInfo>> bitcoin_derivations = {
Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
DerivationType.electrum: [
DerivationInfo(
derivationType: DerivationType.electrum,

View file

@ -287,6 +287,18 @@ class CWBitcoin extends Bitcoin {
}) async {
List<DerivationInfo> list = [];
List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node);
if (types.length == 1 && types.first == DerivationType.electrum) {
return [
DerivationInfo(
derivationType: DerivationType.electrum,
derivationPath: "m/0'/0",
description: "Electrum",
scriptType: "p2wpkh",
)
];
}
final electrumClient = ElectrumClient();
await electrumClient.connectToUri(node.uri);
@ -304,7 +316,7 @@ class CWBitcoin extends Bitcoin {
break;
}
for (DerivationType dType in bitcoin_derivations.keys) {
for (DerivationType dType in electrum_derivations.keys) {
late Uint8List seedBytes;
if (dType == DerivationType.electrum) {
seedBytes = await mnemonicToSeedBytes(mnemonic);
@ -312,7 +324,7 @@ class CWBitcoin extends Bitcoin {
seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? '');
}
for (DerivationInfo dInfo in bitcoin_derivations[dType]!) {
for (DerivationInfo dInfo in electrum_derivations[dType]!) {
try {
DerivationInfo dInfoCopy = DerivationInfo(
derivationType: dInfo.derivationType,
@ -325,7 +337,7 @@ class CWBitcoin extends Bitcoin {
int derivationDepth = _countOccurrences(derivationPath, "/");
// the correct derivation depth is dependant on the derivation type:
// the derivation paths defined in bitcoin_derivations are at the ROOT level, i.e.:
// the derivation paths defined in electrum_derivations are at the ROOT level, i.e.:
// electrum's format doesn't specify subaddresses, just subaccounts:
// for BIP44

View file

@ -106,7 +106,6 @@ class CWNano extends Nano {
required String mnemonic,
required DerivationType derivationType,
}) {
if (mnemonic.split(" ").length == 12 && derivationType != DerivationType.bip39) {
throw Exception("Invalid mnemonic for derivation type!");
}
@ -126,7 +125,6 @@ class CWNano extends Nano {
required String seedKey,
required DerivationType derivationType,
}) {
if (seedKey.length == 128 && derivationType != DerivationType.bip39) {
throw Exception("Invalid seed key length for derivation type!");
}
@ -192,7 +190,6 @@ class CWNano extends Nano {
}
class CWNanoUtil extends NanoUtil {
@override
bool isValidBip39Seed(String seed) {
return NanoDerivations.isValidBip39Seed(seed);
@ -346,4 +343,54 @@ class CWNanoUtil extends NanoUtil {
return [DerivationType.nano, DerivationType.bip39];
}
}
@override
Future<List<DerivationInfo>> getDerivationsFromMnemonic({
String? mnemonic,
String? seedKey,
required Node node,
}) async {
List<DerivationInfo> list = [];
List<DerivationType> possibleDerivationTypes = await compareDerivationMethods(
mnemonic: mnemonic,
privateKey: seedKey,
node: node,
);
if (possibleDerivationTypes.length == 1) {
return [DerivationInfo(derivationType: possibleDerivationTypes.first)];
}
AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic(
DerivationType.bip39,
mnemonic: mnemonic,
seedKey: seedKey,
node: node,
);
AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic(
DerivationType.nano,
mnemonic: mnemonic,
seedKey: seedKey,
node: node,
);
if (standardInfo?.confirmationHeight != null && standardInfo!.confirmationHeight > 0) {
list.add(DerivationInfo(
derivationType: DerivationType.nano,
balance: nanoUtil!.getRawAsUsableString(standardInfo.balance, nanoUtil!.rawPerNano),
address: standardInfo.address!,
transactionsCount: standardInfo.confirmationHeight,
));
}
if (bip39Info?.confirmationHeight != null && bip39Info!.confirmationHeight > 0) {
list.add(DerivationInfo(
derivationType: DerivationType.bip39,
balance: nanoUtil!.getRawAsUsableString(bip39Info.balance, nanoUtil!.rawPerNano),
address: bip39Info.address!,
transactionsCount: bip39Info.confirmationHeight,
));
}
return list;
}
}

View file

@ -113,13 +113,19 @@ abstract class WalletCreationVMBase with Store {
derivationType: DerivationType.nano,
);
case WalletType.bitcoin:
case WalletType.litecoin:
return DerivationInfo(
derivationType: DerivationType.bip39,
derivationPath: "m/84'/0'/0'/0",
description: "Standard BIP84 native segwit",
scriptType: "p2wpkh",
);
case WalletType.litecoin:
return DerivationInfo(
derivationType: DerivationType.bip39,
derivationPath: "m/84'/2'/0'/0",
description: "Standard BIP84 native segwit (litecoin)",
scriptType: "p2wpkh",
);
default:
return null;
}

View file

@ -212,65 +212,17 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
case WalletType.nano:
String? mnemonic = credentials['seed'] as String?;
String? seedKey = credentials['private_key'] as String?;
AccountInfoResponse? bip39Info = await nanoUtil!.getInfoFromSeedOrMnemonic(
DerivationType.bip39,
mnemonic: mnemonic,
seedKey: seedKey,
node: node);
AccountInfoResponse? standardInfo = await nanoUtil!.getInfoFromSeedOrMnemonic(
DerivationType.nano,
return nanoUtil!.getDerivationsFromMnemonic(
mnemonic: mnemonic,
seedKey: seedKey,
node: node,
);
if (standardInfo?.balance != null) {
list.add(DerivationInfo(
derivationType: DerivationType.nano,
balance: nanoUtil!.getRawAsUsableString(standardInfo!.balance, nanoUtil!.rawPerNano),
address: standardInfo.address!,
transactionsCount: standardInfo.confirmationHeight,
));
}
if (bip39Info?.balance != null) {
list.add(DerivationInfo(
derivationType: DerivationType.bip39,
balance: nanoUtil!.getRawAsUsableString(bip39Info!.balance, nanoUtil!.rawPerNano),
address: bip39Info.address!,
transactionsCount: bip39Info.confirmationHeight,
));
}
break;
default:
break;
}
return list;
}
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);
switch (type) {
case WalletType.bitcoin:
case WalletType.litecoin:
return bitcoin!.compareDerivationMethods(mnemonic: mnemonic!, node: node);
case WalletType.nano:
return nanoUtil!.compareDerivationMethods(
mnemonic: mnemonic,
privateKey: seedKey,
node: node,
);
default:
break;
}
return [DerivationType.def];
}
@override
Future<WalletBase> process(WalletCredentials credentials) async {
if (mode == WalletRestoreMode.keys) {

View file

@ -84,7 +84,7 @@ import 'package:hive/hive.dart';
const bitcoinCWHeaders = """
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/litecoin_network.dart';
import 'package:cw_bitcoin/bitcoin_derivations.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_bitcoin/bitcoin_receive_page_option.dart';
@ -914,6 +914,11 @@ abstract class NanoUtil {
String? privateKey,
required Node node,
});
Future<List<DerivationInfo>> getDerivationsFromMnemonic({
String? mnemonic,
String? seedKey,
required Node node,
});
}
""";