mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
electrum updates (#1449)
* hotfixes * copy over the rest of the fixes * use hardened derivation path everywhere * correct balance path for electrum * revert index nullability and correct balance path for all cases * only save wallet info if we changed it
This commit is contained in:
parent
fc2c9a2bcc
commit
591342ec6a
10 changed files with 66 additions and 46 deletions
|
@ -6,6 +6,7 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
import 'package:convert/convert.dart';
|
import 'package:convert/convert.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
|
@ -150,7 +151,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
);
|
);
|
||||||
|
|
||||||
// set the default if not present:
|
// set the default if not present:
|
||||||
walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/0";
|
walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? electrum_path;
|
||||||
walletInfo.derivationInfo!.derivationType = snp.derivationType ?? DerivationType.electrum;
|
walletInfo.derivationInfo!.derivationType = snp.derivationType ?? DerivationType.electrum;
|
||||||
|
|
||||||
Uint8List? seedBytes = null;
|
Uint8List? seedBytes = null;
|
||||||
|
|
|
@ -108,3 +108,6 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
String electrum_path = electrum_derivations[DerivationType.electrum]!.first.derivationPath!;
|
|
@ -17,6 +17,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
|
||||||
import 'package:cw_bitcoin/electrum.dart';
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_bitcoin/electrum_transaction_history.dart';
|
import 'package:cw_bitcoin/electrum_transaction_history.dart';
|
||||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
@ -133,7 +134,7 @@ abstract class ElectrumWalletBase
|
||||||
return currency == CryptoCurrency.bch
|
return currency == CryptoCurrency.bch
|
||||||
? bitcoinCashHDWallet(seedBytes)
|
? bitcoinCashHDWallet(seedBytes)
|
||||||
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
|
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
|
||||||
.derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? "m/0'"));
|
.derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitcoin.HDWallet.fromBase58(xpub!);
|
return bitcoin.HDWallet.fromBase58(xpub!);
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/utils/file.dart';
|
import 'package:cw_core/utils/file.dart';
|
||||||
|
@ -71,7 +72,7 @@ class ElectrumWalletSnapshot {
|
||||||
|
|
||||||
final derivationType = DerivationType
|
final derivationType = DerivationType
|
||||||
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
||||||
final derivationPath = data['derivationPath'] as String? ?? "m/0'/0";
|
final derivationPath = data['derivationPath'] as String? ?? electrum_path;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
regularAddressIndexByType = {
|
regularAddressIndexByType = {
|
||||||
|
|
|
@ -5,58 +5,64 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
||||||
import 'package:hex/hex.dart';
|
import 'package:hex/hex.dart';
|
||||||
|
|
||||||
bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, int? index}) {
|
bitcoin.PaymentData generatePaymentData({
|
||||||
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
required bitcoin.HDWallet hd,
|
||||||
|
required int index,
|
||||||
|
}) {
|
||||||
|
final pubKey = hd.derive(index).pubKey!;
|
||||||
return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
|
return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ECPrivate generateECPrivate(
|
ECPrivate generateECPrivate({
|
||||||
{required bitcoin.HDWallet hd, required BasedUtxoNetwork network, int? index}) {
|
required bitcoin.HDWallet hd,
|
||||||
final wif = index != null ? hd.derive(index).wif! : hd.wif!;
|
required BasedUtxoNetwork network,
|
||||||
|
required int index,
|
||||||
|
}) {
|
||||||
|
final wif = hd.derive(index).wif!;
|
||||||
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
|
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateP2WPKHAddress({
|
String generateP2WPKHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required bitcoin.HDWallet hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
int? index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
final pubKey = hd.derive(index).pubKey!;
|
||||||
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
|
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateP2SHAddress({
|
String generateP2SHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required bitcoin.HDWallet hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
int? index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
final pubKey = hd.derive(index).pubKey!;
|
||||||
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
|
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateP2WSHAddress({
|
String generateP2WSHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required bitcoin.HDWallet hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
int? index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
final pubKey = hd.derive(index).pubKey!;
|
||||||
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
|
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateP2PKHAddress({
|
String generateP2PKHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required bitcoin.HDWallet hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
int? index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
final pubKey = hd.derive(index).pubKey!;
|
||||||
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
|
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateP2TRAddress({
|
String generateP2TRAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required bitcoin.HDWallet hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
int? index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!;
|
final pubKey = hd.derive(index).pubKey!;
|
||||||
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
|
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,14 +295,7 @@ class CWBitcoin extends Bitcoin {
|
||||||
|
|
||||||
List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node);
|
List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node);
|
||||||
if (types.length == 1 && types.first == DerivationType.electrum) {
|
if (types.length == 1 && types.first == DerivationType.electrum) {
|
||||||
return [
|
return [getElectrumDerivations()[DerivationType.electrum]!.first];
|
||||||
DerivationInfo(
|
|
||||||
derivationType: DerivationType.electrum,
|
|
||||||
derivationPath: "m/0'",
|
|
||||||
description: "Electrum",
|
|
||||||
scriptType: "p2wpkh",
|
|
||||||
)
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final electrumClient = ElectrumClient();
|
final electrumClient = ElectrumClient();
|
||||||
|
@ -339,38 +332,34 @@ class CWBitcoin extends Bitcoin {
|
||||||
scriptType: dInfo.scriptType,
|
scriptType: dInfo.scriptType,
|
||||||
);
|
);
|
||||||
|
|
||||||
String derivationPath = dInfoCopy.derivationPath!;
|
String balancePath = dInfoCopy.derivationPath!;
|
||||||
int derivationDepth = _countOccurrences(derivationPath, "/");
|
int derivationDepth = _countOccurrences(balancePath, "/");
|
||||||
|
|
||||||
// the correct derivation depth is dependant on the derivation type:
|
|
||||||
// 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
|
// for BIP44
|
||||||
if (derivationDepth == 3) {
|
if (derivationDepth == 3 || derivationDepth == 1) {
|
||||||
// we add "/0/0" so that we generate account 0, index 0 and correctly get balance
|
// we add "/0" so that we generate account 0
|
||||||
derivationPath += "/0/0";
|
balancePath += "/0";
|
||||||
}
|
}
|
||||||
|
|
||||||
// var hd = bip32.BIP32.fromSeed(seedBytes).derivePath(derivationPath);
|
|
||||||
final hd = btc.HDWallet.fromSeed(
|
final hd = btc.HDWallet.fromSeed(
|
||||||
seedBytes,
|
seedBytes,
|
||||||
network: networkType,
|
network: networkType,
|
||||||
).derivePath(derivationPath);
|
).derivePath(balancePath);
|
||||||
|
|
||||||
|
// derive address at index 0:
|
||||||
String? address;
|
String? address;
|
||||||
switch (dInfoCopy.scriptType) {
|
switch (dInfoCopy.scriptType) {
|
||||||
case "p2wpkh":
|
case "p2wpkh":
|
||||||
address = generateP2WPKHAddress(hd: hd, network: network);
|
address = generateP2WPKHAddress(hd: hd, network: network, index: 0);
|
||||||
break;
|
break;
|
||||||
case "p2pkh":
|
case "p2pkh":
|
||||||
address = generateP2PKHAddress(hd: hd, network: network);
|
address = generateP2PKHAddress(hd: hd, network: network, index: 0);
|
||||||
break;
|
break;
|
||||||
case "p2wpkh-p2sh":
|
case "p2wpkh-p2sh":
|
||||||
address = generateP2SHAddress(hd: hd, network: network);
|
address = generateP2SHAddress(hd: hd, network: network, index: 0);
|
||||||
break;
|
break;
|
||||||
case "p2tr":
|
case "p2tr":
|
||||||
address = generateP2TRAddress(hd: hd, network: network);
|
address = generateP2TRAddress(hd: hd, network: network, index: 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
|
@ -396,6 +385,11 @@ class CWBitcoin extends Bitcoin {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<DerivationType, List<DerivationInfo>> getElectrumDerivations() {
|
||||||
|
return electrum_derivations;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool hasTaprootInput(PendingTransaction pendingTransaction) {
|
bool hasTaprootInput(PendingTransaction pendingTransaction) {
|
||||||
return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;
|
return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;
|
||||||
|
|
|
@ -233,6 +233,8 @@ Future<void> defaultSettingsMigration(
|
||||||
case 36:
|
case 36:
|
||||||
await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||||
break;
|
break;
|
||||||
|
case 37:
|
||||||
|
await fixBtcDerivationPaths(walletInfoSource);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -775,6 +777,19 @@ Future<void> changeDefaultMoneroNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> fixBtcDerivationPaths(Box<WalletInfo> walletsInfoSource) async {
|
||||||
|
for (WalletInfo walletInfo in walletsInfoSource.values) {
|
||||||
|
if (walletInfo.type == WalletType.bitcoin ||
|
||||||
|
walletInfo.type == WalletType.bitcoinCash ||
|
||||||
|
walletInfo.type == WalletType.litecoin) {
|
||||||
|
if (walletInfo.derivationInfo?.derivationPath == "m/0'/0") {
|
||||||
|
walletInfo.derivationInfo!.derivationPath = "m/0'";
|
||||||
|
await walletInfo.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
|
Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
|
||||||
for (WalletInfo walletInfo in walletsInfoSource.values) {
|
for (WalletInfo walletInfo in walletsInfoSource.values) {
|
||||||
if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {
|
if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {
|
||||||
|
|
|
@ -202,7 +202,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
transactionDescriptions: transactionDescriptions,
|
transactionDescriptions: transactionDescriptions,
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
initialMigrationVersion: 36,
|
initialMigrationVersion: 37,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||||
|
@ -98,10 +99,7 @@ abstract class WalletCreationVMBase with Store {
|
||||||
);
|
);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return DerivationInfo(
|
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||||
derivationType: DerivationType.electrum,
|
|
||||||
derivationPath: "m/0'",
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,7 @@ abstract class Bitcoin {
|
||||||
{required String mnemonic, required Node node});
|
{required String mnemonic, required Node node});
|
||||||
Future<List<DerivationInfo>> getDerivationsFromMnemonic(
|
Future<List<DerivationInfo>> getDerivationsFromMnemonic(
|
||||||
{required String mnemonic, required Node node, String? passphrase});
|
{required String mnemonic, required Node node, String? passphrase});
|
||||||
|
Map<DerivationType, List<DerivationInfo>> getElectrumDerivations();
|
||||||
Future<void> setAddressType(Object wallet, dynamic option);
|
Future<void> setAddressType(Object wallet, dynamic option);
|
||||||
ReceivePageOption getSelectedAddressType(Object wallet);
|
ReceivePageOption getSelectedAddressType(Object wallet);
|
||||||
List<ReceivePageOption> getBitcoinReceivePageOptions();
|
List<ReceivePageOption> getBitcoinReceivePageOptions();
|
||||||
|
|
Loading…
Reference in a new issue