feat: derivationinfo to address records

This commit is contained in:
Rafael Saes 2024-10-30 12:13:59 -03:00
parent 64caf8479e
commit 433686bce3
16 changed files with 253 additions and 212 deletions

View file

@ -6,7 +6,7 @@ abstract class BaseBitcoinAddressRecord {
BaseBitcoinAddressRecord(
this.address, {
required this.index,
this.isChange = false,
bool isChange = false,
int txCount = 0,
int balance = 0,
String name = '',
@ -17,7 +17,8 @@ abstract class BaseBitcoinAddressRecord {
_balance = balance,
_name = name,
_isUsed = isUsed,
_isHidden = isHidden ?? isChange;
_isHidden = isHidden ?? isChange,
_isChange = isChange;
@override
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
@ -25,7 +26,8 @@ abstract class BaseBitcoinAddressRecord {
final String address;
final bool _isHidden;
bool get isHidden => _isHidden;
bool isChange;
final bool _isChange;
bool get isChange => _isChange;
final int index;
int _txCount;
int _balance;
@ -55,9 +57,12 @@ abstract class BaseBitcoinAddressRecord {
}
class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
final BitcoinDerivationInfo derivationInfo;
BitcoinAddressRecord(
super.address, {
required super.index,
required this.derivationInfo,
super.isHidden,
super.isChange = false,
super.txCount = 0,
@ -81,6 +86,9 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
return BitcoinAddressRecord(
decoded['address'] as String,
index: decoded['index'] as int,
derivationInfo: BitcoinDerivationInfo.fromJSON(
decoded['derivationInfo'] as Map<String, dynamic>,
),
isHidden: decoded['isHidden'] as bool? ?? false,
isChange: decoded['isChange'] as bool? ?? false,
isUsed: decoded['isUsed'] as bool? ?? false,
@ -101,6 +109,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
String toJSON() => json.encode({
'address': address,
'index': index,
'derivationInfo': derivationInfo.toJSON(),
'isHidden': isHidden,
'isChange': isChange,
'isUsed': isUsed,
@ -116,6 +125,8 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
int get labelIndex => index;
final String? labelHex;
static bool isChangeAddress(int labelIndex) => labelIndex == 0;
BitcoinSilentPaymentAddressRecord(
super.address, {
required int labelIndex,
@ -126,9 +137,9 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
super.type = SilentPaymentsAddresType.p2sp,
super.isHidden,
this.labelHex,
}) : super(index: labelIndex, isChange: labelIndex == 0) {
}) : super(index: labelIndex, isChange: isChangeAddress(labelIndex)) {
if (labelIndex != 1 && labelHex == null) {
throw ArgumentError('label must be provided for silent address index > 0');
throw ArgumentError('label must be provided for silent address index != 1');
}
}

View file

@ -24,9 +24,14 @@ class BitcoinHardwareWalletService {
final xpub = await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
final bip32 = Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
final fullPath = Bip32PathParser.parse(derivationPath).addElem(Bip32KeyIndex(0));
final address = ECPublic.fromBip32(bip32.derive(fullPath).publicKey)
.toP2wpkhAddress()
.toAddress(BitcoinNetwork.mainnet);
accounts.add(HardwareAccountData(
address: P2wpkhAddress.fromBip32(bip32: bip32, isChange: false, index: i)
.toAddress(BitcoinNetwork.mainnet),
address: address,
accountIndex: i,
derivationPath: derivationPath,
masterFingerprint: masterFp,

View file

@ -32,7 +32,10 @@ class BitcoinUnspent extends Unspent {
@override
bool operator ==(Object o) {
print('BitcoinUnspent operator ==');
if (identical(this, o)) return true;
return o is BitcoinUnspent && hash == o.hash && vout == o.vout;
}
@override
int get hashCode => Object.hash(hash, vout);
}

View file

@ -360,7 +360,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
updatedUnspentCoins.addAll(await fetchUnspent(address));
}));
unspentCoins = updatedUnspentCoins.toSet();
unspentCoins.addAll(updatedUnspentCoins);
if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
unspentCoins.forEach((coin) => addCoinInfo(coin));
@ -1033,3 +1033,58 @@ Future<void> delegatedScan(ScanData scanData) async {
// );
// }
}
class ScanNode {
final Uri uri;
final bool? useSSL;
ScanNode(this.uri, this.useSSL);
}
class ScanData {
final SendPort sendPort;
final SilentPaymentOwner silentAddress;
final int height;
final ScanNode? node;
final BasedUtxoNetwork network;
final int chainTip;
final List<String> transactionHistoryIds;
final Map<String, String> labels;
final List<int> labelIndexes;
final bool isSingleScan;
ScanData({
required this.sendPort,
required this.silentAddress,
required this.height,
required this.node,
required this.network,
required this.chainTip,
required this.transactionHistoryIds,
required this.labels,
required this.labelIndexes,
required this.isSingleScan,
});
factory ScanData.fromHeight(ScanData scanData, int newHeight) {
return ScanData(
sendPort: scanData.sendPort,
silentAddress: scanData.silentAddress,
height: newHeight,
node: scanData.node,
network: scanData.network,
chainTip: scanData.chainTip,
transactionHistoryIds: scanData.transactionHistoryIds,
labels: scanData.labels,
labelIndexes: scanData.labelIndexes,
isSingleScan: scanData.isSingleScan,
);
}
}
class SyncResponse {
final int height;
final SyncStatus syncStatus;
SyncResponse(this.height, this.syncStatus);
}

View file

@ -39,27 +39,44 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) {
switch (addressType) {
case P2pkhAddressType.p2pkh:
return P2pkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
case SegwitAddresType.p2tr:
return P2trAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
case SegwitAddresType.p2wsh:
return P2wshAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
case P2shAddressType.p2wpkhInP2sh:
return P2shAddress.fromBip32(
return P2pkhAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
);
case SegwitAddresType.p2tr:
return P2trAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
);
case SegwitAddresType.p2wsh:
return P2wshAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
);
case P2shAddressType.p2wpkhInP2sh:
return P2shAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
type: P2shAddressType.p2wpkhInP2sh,
);
case SegwitAddresType.p2wpkh:
return P2wpkhAddress.fromBip32(
return P2wpkhAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
isElectrum: false, // TODO:
);
default:
throw ArgumentError('Invalid address type');

View file

@ -4,11 +4,8 @@ import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/utils/file.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
part 'electrum_transaction_history.g.dart';

View file

@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -38,7 +37,6 @@ import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
import 'package:mobx/mobx.dart';
import 'package:hex/hex.dart';
import 'package:http/http.dart' as http;
part 'electrum_wallet.g.dart';
@ -69,7 +67,8 @@ abstract class ElectrumWalletBase
_password = password,
_isTransactionUpdating = false,
isEnabledAutoGenerateSubaddress = true,
unspentCoins = {},
// TODO: inital unspent coins
unspentCoins = ObservableSet(),
scripthashesListening = {},
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of(currency != null
? {
@ -221,8 +220,7 @@ abstract class ElectrumWalletBase
);
String _password;
@observable
Set<BitcoinUnspent> unspentCoins;
ObservableSet<BitcoinUnspent> unspentCoins;
@observable
TransactionPriorities? feeRates;
@ -404,7 +402,7 @@ abstract class ElectrumWalletBase
bool _isBelowDust(int amount) => amount <= _dustAmount && network != BitcoinNetwork.testnet;
UtxoDetails _createUTXOS({
TxCreateUtxoDetails _createUTXOS({
required bool sendAll,
required int credentialsAmount,
required bool paysToSilentPayment,
@ -484,13 +482,13 @@ abstract class ElectrumWalletBase
.toHex();
}
// TODO: isElectrum
final derivationPath = BitcoinAddressUtils.getDerivationPath(
type: utx.bitcoinAddressRecord.type,
account: utx.bitcoinAddressRecord.isChange ? 1 : 0,
index: utx.bitcoinAddressRecord.index,
);
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
if (utx.bitcoinAddressRecord is BitcoinAddressRecord) {
final derivationPath = (utx.bitcoinAddressRecord as BitcoinAddressRecord)
.derivationInfo
.derivationPath
.toString();
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
}
utxos.add(
UtxoWithAddress(
@ -521,7 +519,7 @@ abstract class ElectrumWalletBase
throw BitcoinTransactionNoInputsException();
}
return UtxoDetails(
return TxCreateUtxoDetails(
availableInputs: availableInputs,
unconfirmedCoins: unconfirmedCoins,
utxos: utxos,
@ -662,11 +660,7 @@ abstract class ElectrumWalletBase
isChange: true,
));
final changeDerivationPath = BitcoinAddressUtils.getDerivationPath(
type: changeAddress.type,
account: changeAddress.isChange ? 1 : 0,
index: changeAddress.index,
);
final changeDerivationPath = changeAddress.derivationInfo.derivationPath.toString();
utxoDetails.publicKeys[address.pubKeyHash()] =
PublicKeyWithDerivationPath('', changeDerivationPath);
@ -1176,7 +1170,7 @@ abstract class ElectrumWalletBase
updatedUnspentCoins.addAll(await fetchUnspent(address));
}));
unspentCoins = updatedUnspentCoins.toSet();
unspentCoins.addAll(updatedUnspentCoins);
if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
unspentCoins.forEach((coin) => addCoinInfo(coin));
@ -1220,17 +1214,7 @@ abstract class ElectrumWalletBase
final newUnspentCoins = (await fetchUnspent(addressRecord)).toSet();
await updateCoins(newUnspentCoins);
print([1, unspentCoins.containsAll(newUnspentCoins)]);
if (!unspentCoins.containsAll(newUnspentCoins)) {
newUnspentCoins.forEach((coin) {
print(unspentCoins.contains(coin));
print([coin.vout, coin.hash]);
print([unspentCoins.first.vout, unspentCoins.first.hash]);
if (!unspentCoins.contains(coin)) {
unspentCoins.add(coin);
}
});
}
unspentCoins.addAll(newUnspentCoins);
// if (unspentCoinsInfo.length != unspentCoins.length) {
// unspentCoins.forEach(addCoinInfo);
@ -1400,7 +1384,7 @@ abstract class ElectrumWalletBase
if (index + 1 <= script.length) {
try {
final opReturnData = script[index + 1].toString();
memo = utf8.decode(HEX.decode(opReturnData));
memo = StringUtils.decode(BytesUtils.fromHexString(opReturnData));
continue;
} catch (_) {
throw Exception('Cannot decode OP_RETURN data');
@ -1708,6 +1692,7 @@ abstract class ElectrumWalletBase
isChange: addressRecord.isChange,
gap: gapLimit,
type: addressRecord.type,
derivationInfo: BitcoinAddressUtils.getDerivationFromType(addressRecord.type),
);
}
}
@ -1805,21 +1790,17 @@ abstract class ElectrumWalletBase
@override
Future<String> signMessage(String message, {String? address = null}) async {
Bip32Slip10Secp256k1 HD = bip32;
final record = walletAddresses.getFromAddresses(address!);
final record = walletAddresses.allAddresses.firstWhere((element) => element.address == address);
final path = Bip32PathParser.parse(walletInfo.derivationInfo!.derivationPath!)
.addElem(
Bip32KeyIndex(BitcoinAddressUtils.getAccountFromChange(record.isChange)),
)
.addElem(Bip32KeyIndex(record.index));
if (record.isChange) {
HD = HD.childKey(Bip32KeyIndex(1));
} else {
HD = HD.childKey(Bip32KeyIndex(0));
}
final priv = ECPrivate.fromHex(bip32.derive(path).privateKey.toHex());
HD = HD.childKey(Bip32KeyIndex(record.index));
final priv = ECPrivate.fromHex(HD.privateKey.privKey.toHex());
String messagePrefix = '\x18Bitcoin Signed Message:\n';
final hexEncoded = priv.signMessage(utf8.encode(message), messagePrefix: messagePrefix);
final hexEncoded = priv.signMessage(StringUtils.encode(message));
final decodedSig = hex.decode(hexEncoded);
return base64Encode(decodedSig);
}
@ -1835,7 +1816,7 @@ abstract class ElectrumWalletBase
if (signature.endsWith('=')) {
sigDecodedBytes = base64.decode(signature);
} else {
sigDecodedBytes = hex.decode(signature);
sigDecodedBytes = BytesUtils.fromHexString(signature);
}
if (sigDecodedBytes.length != 64 && sigDecodedBytes.length != 65) {
@ -1845,7 +1826,7 @@ abstract class ElectrumWalletBase
String messagePrefix = '\x18Bitcoin Signed Message:\n';
final messageHash = QuickCrypto.sha256Hash(
BitcoinSignerUtils.magicMessage(utf8.encode(message), messagePrefix));
BitcoinSignerUtils.magicMessage(StringUtils.encode(message), messagePrefix));
List<int> correctSignature =
sigDecodedBytes.length == 65 ? sigDecodedBytes.sublist(1) : List.from(sigDecodedBytes);
@ -1911,14 +1892,14 @@ abstract class ElectrumWalletBase
break;
case ConnectionStatus.disconnected:
// if (syncStatus is! NotConnectedSyncStatus) {
// syncStatus = NotConnectedSyncStatus();
// }
if (syncStatus is! NotConnectedSyncStatus) {
syncStatus = NotConnectedSyncStatus();
}
break;
case ConnectionStatus.failed:
// if (syncStatus is! LostConnectionSyncStatus) {
// syncStatus = LostConnectionSyncStatus();
// }
if (syncStatus is! LostConnectionSyncStatus) {
syncStatus = LostConnectionSyncStatus();
}
break;
case ConnectionStatus.connecting:
if (syncStatus is! ConnectingSyncStatus) {
@ -1989,7 +1970,7 @@ abstract class ElectrumWalletBase
if (index + 1 <= script.length) {
try {
final opReturnData = script[index + 1].toString();
final decodedString = utf8.decode(HEX.decode(opReturnData));
final decodedString = StringUtils.decode(BytesUtils.fromHexString(opReturnData));
outputAddresses.add('OP_RETURN:$decodedString');
} catch (_) {
outputAddresses.add('OP_RETURN:');
@ -2005,61 +1986,6 @@ abstract class ElectrumWalletBase
}
}
class ScanNode {
final Uri uri;
final bool? useSSL;
ScanNode(this.uri, this.useSSL);
}
class ScanData {
final SendPort sendPort;
final SilentPaymentOwner silentAddress;
final int height;
final ScanNode? node;
final BasedUtxoNetwork network;
final int chainTip;
final List<String> transactionHistoryIds;
final Map<String, String> labels;
final List<int> labelIndexes;
final bool isSingleScan;
ScanData({
required this.sendPort,
required this.silentAddress,
required this.height,
required this.node,
required this.network,
required this.chainTip,
required this.transactionHistoryIds,
required this.labels,
required this.labelIndexes,
required this.isSingleScan,
});
factory ScanData.fromHeight(ScanData scanData, int newHeight) {
return ScanData(
sendPort: scanData.sendPort,
silentAddress: scanData.silentAddress,
height: newHeight,
node: scanData.node,
network: scanData.network,
chainTip: scanData.chainTip,
transactionHistoryIds: scanData.transactionHistoryIds,
labels: scanData.labels,
labelIndexes: scanData.labelIndexes,
isSingleScan: scanData.isSingleScan,
);
}
}
class SyncResponse {
final int height;
final SyncStatus syncStatus;
SyncResponse(this.height, this.syncStatus);
}
class EstimatedTxResult {
EstimatedTxResult({
required this.utxos,
@ -2095,7 +2021,7 @@ class PublicKeyWithDerivationPath {
final String publicKey;
}
class UtxoDetails {
class TxCreateUtxoDetails {
final List<BitcoinUnspent> availableInputs;
final List<BitcoinUnspent> unconfirmedCoins;
final List<UtxoWithAddress> utxos;
@ -2106,7 +2032,7 @@ class UtxoDetails {
final bool spendsSilentPayment;
final bool spendsUnconfirmedTX;
UtxoDetails({
TxCreateUtxoDetails({
required this.availableInputs,
required this.unconfirmedCoins,
required this.utxos,

View file

@ -43,7 +43,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
int initialSilentAddressIndex = 0,
List<BitcoinAddressRecord>? initialMwebAddresses,
BitcoinAddressType? initialAddressPageType,
}) : _allAddresses = (initialAddresses ?? []).toSet(),
}) : _allAddresses = ObservableSet.of(initialAddresses ?? []),
addressesByReceiveType =
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
receiveAddresses = ObservableList<BitcoinAddressRecord>.of(
@ -63,11 +63,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
mwebAddresses =
ObservableList<BitcoinAddressRecord>.of((initialMwebAddresses ?? []).toSet()),
super(walletInfo) {
silentAddress = SilentPaymentOwner.fromPrivateKeys(
b_scan: ECPrivate.fromHex(bip32.derive(SCAN_PATH).privateKey.toHex()),
b_spend: ECPrivate.fromHex(bip32.derive(SPEND_PATH).privateKey.toHex()),
network: network,
);
// TODO: initial silent address, not every time
silentAddress = SilentPaymentOwner.fromBip32(bip32);
if (silentAddresses.length == 0) {
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
silentAddress.toString(),
@ -91,8 +89,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
static const defaultChangeAddressesCount = 17;
static const gap = 20;
@observable
final Set<BitcoinAddressRecord> _allAddresses;
final ObservableSet<BitcoinAddressRecord> _allAddresses;
final ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
final ObservableList<BitcoinAddressRecord> receiveAddresses;
final ObservableList<BitcoinAddressRecord> changeAddresses;
@ -119,6 +116,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
@computed
List<BitcoinAddressRecord> get allAddresses => _allAddresses.toList();
BitcoinAddressRecord getFromAddresses(String address) {
return _allAddresses.firstWhere((element) => element.address == address);
}
@override
@computed
String get address {
@ -189,7 +190,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}
@override
String get primaryAddress => getAddress(isChange: false, index: 0, addressType: addressPageType);
String get primaryAddress => _allAddresses.first.address;
Map<String, int> currentReceiveAddressIndexByType;
@ -250,7 +251,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
updateAddressesByMatch();
updateReceiveAddresses();
updateChangeAddresses();
_validateAddresses();
await updateAddressesInBox();
if (currentReceiveAddressIndex >= receiveAddresses.length) {
@ -263,15 +263,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}
@action
Future<BitcoinAddressRecord> getChangeAddress(
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
Future<BitcoinAddressRecord> getChangeAddress({
List<BitcoinUnspent>? inputs,
List<BitcoinOutput>? outputs,
bool isPegIn = false,
}) async {
updateChangeAddresses();
if (changeAddresses.isEmpty) {
final newAddresses = await _createNewAddresses(gap, isChange: true);
addAddresses(newAddresses);
}
if (currentChangeAddressIndex >= changeAddresses.length) {
currentChangeAddressIndex = 0;
}
@ -326,13 +324,20 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
final newAddressIndex = addressesByReceiveType.fold(
0, (int acc, addressRecord) => addressRecord.isChange == false ? acc + 1 : acc);
final derivationInfo = BitcoinAddressUtils.getDerivationFromType(addressPageType);
final address = BitcoinAddressRecord(
getAddress(isChange: false, index: newAddressIndex, addressType: addressPageType),
getAddress(
isChange: false,
index: newAddressIndex,
addressType: addressPageType,
derivationInfo: derivationInfo,
),
index: newAddressIndex,
isChange: false,
name: label,
type: addressPageType,
network: network,
derivationInfo: BitcoinAddressUtils.getDerivationFromType(addressPageType),
);
_allAddresses.add(address);
Future.delayed(Duration.zero, () => updateAddressesByMatch());
@ -343,6 +348,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) {
throw UnimplementedError();
}
@ -351,17 +357,28 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) {
return generateAddress(isChange: isChange, index: index, addressType: addressType)
.toAddress(network);
return generateAddress(
isChange: isChange,
index: index,
addressType: addressType,
derivationInfo: derivationInfo,
).toAddress(network);
}
Future<String> getAddressAsync({
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) async =>
getAddress(isChange: isChange, index: index, addressType: addressType);
getAddress(
isChange: isChange,
index: index,
addressType: addressType,
derivationInfo: derivationInfo,
);
@action
void addBitcoinAddressTypes() {
@ -551,23 +568,41 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
required bool isChange,
required int gap,
required BitcoinAddressType type,
required BitcoinDerivationInfo derivationInfo,
}) async {
print("_allAddresses: ${_allAddresses.length}");
final newAddresses = await _createNewAddresses(gap, isChange: isChange, type: type);
final newAddresses = await _createNewAddresses(
gap,
isChange: isChange,
type: type,
derivationInfo: derivationInfo,
);
addAddresses(newAddresses);
print("_allAddresses: ${_allAddresses.length}");
return newAddresses;
}
@action
Future<void> generateInitialAddresses({required BitcoinAddressType type}) async {
await discoverAddresses(isChange: false, gap: defaultReceiveAddressesCount, type: type);
await discoverAddresses(isChange: true, gap: defaultChangeAddressesCount, type: type);
// TODO: try all other derivations
final derivationInfo = BitcoinAddressUtils.getDerivationFromType(type);
await discoverAddresses(
isChange: false,
gap: defaultReceiveAddressesCount,
type: type,
derivationInfo: derivationInfo,
);
await discoverAddresses(
isChange: true,
gap: defaultChangeAddressesCount,
type: type,
derivationInfo: derivationInfo,
);
}
@action
Future<List<BitcoinAddressRecord>> _createNewAddresses(
int count, {
required BitcoinDerivationInfo derivationInfo,
bool isChange = false,
BitcoinAddressType? type,
}) async {
@ -580,11 +615,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
isChange: isChange,
index: i,
addressType: type ?? addressPageType,
derivationInfo: derivationInfo,
),
index: i,
isChange: isChange,
type: type ?? addressPageType,
network: network,
derivationInfo: derivationInfo,
);
list.add(address);
}
@ -618,32 +655,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
updateAddressesByMatch();
}
void _validateAddresses() {
_allAddresses.forEach((element) async {
if (element.type == SegwitAddresType.mweb) {
// this would add a ton of startup lag for mweb addresses since we have 1000 of them
return;
}
if (!element.isChange &&
element.address !=
await getAddressAsync(
isChange: false,
index: element.index,
addressType: element.type,
)) {
element.isChange = true;
} else if (element.isChange &&
element.address !=
await getAddressAsync(
isChange: true,
index: element.index,
addressType: element.type,
)) {
element.isChange = false;
}
});
}
@action
Future<void> setAddressType(BitcoinAddressType type) async {
_addressPageType = type;

View file

@ -3,7 +3,6 @@ import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
@ -92,7 +91,7 @@ class ElectrumWalletSnapshot {
final derivationType = DerivationType
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
final derivationPath = data['derivationPath'] as String? ?? electrum_path;
final derivationPath = data['derivationPath'] as String? ?? ELECTRUM_PATH;
try {
regularAddressIndexByType = {

View file

@ -28,7 +28,12 @@ class LitecoinHardwareWalletService {
final bip32 =
Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion).childKey(Bip32KeyIndex(0));
final address = P2wpkhAddress.fromBip32(bip32: bip32, isChange: false, index: 0);
final address = P2wpkhAddress.fromDerivation(
bip32: bip32,
derivationInfo: BitcoinDerivationInfos.LITECOIN,
isChange: false,
index: 0,
);
accounts.add(HardwareAccountData(
address: address.toAddress(LitecoinNetwork.mainnet),

View file

@ -21,7 +21,6 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/pending_transaction.dart';
@ -243,7 +242,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
walletInfo.derivationInfo ??= DerivationInfo();
// set the default if not present:
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? ELECTRUM_PATH;
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
Uint8List? seedBytes = null;
@ -435,13 +434,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
@action
@override
Future<void> rescan({
required int height,
int? chainTip,
ScanData? scanData,
bool? doSingleScan,
bool? usingElectrs,
}) async {
Future<void> rescan({required int height}) async {
_syncTimer?.cancel();
await walletInfo.updateRestoreHeight(height);

View file

@ -103,6 +103,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
index: e.key,
type: SegwitAddresType.mweb,
network: network,
derivationInfo: BitcoinAddressUtils.getDerivationFromType(SegwitAddresType.p2wpkh),
))
.toList();
addMwebAddresses(addressRecords);
@ -121,12 +122,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) {
if (addressType == SegwitAddresType.mweb) {
return MwebAddress.fromAddress(address: mwebAddrs[0], network: network);
}
return P2wpkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
return P2wpkhAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
);
}
}
@ -135,12 +142,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) async {
if (addressType == SegwitAddresType.mweb) {
await ensureMwebAddressUpToIndexExists(index);
}
return getAddress(isChange: isChange, index: index, addressType: addressType);
return getAddress(
isChange: isChange,
index: index,
addressType: addressType,
derivationInfo: derivationInfo,
);
}
@action
@ -194,6 +207,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
index: 0,
type: SegwitAddresType.mweb,
network: network,
derivationInfo: BitcoinAddressUtils.getDerivationFromType(SegwitAddresType.p2wpkh),
);
}

View file

@ -411,10 +411,10 @@ packages:
dependency: transitive
description:
name: google_identity_services_web
sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6"
sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6"
url: "https://pub.dev"
source: hosted
version: "0.3.1+4"
version: "0.3.0+2"
googleapis_auth:
dependency: transitive
description:
@ -467,10 +467,10 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.2.0"
http2:
dependency: transitive
description:
@ -845,10 +845,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2"
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
@ -1041,18 +1041,18 @@ packages:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.4.2"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
url: "https://pub.dev"
source: hosted
version: "2.4.5"
version: "2.4.3"
xdg_directories:
dependency: transitive
description:

View file

@ -153,6 +153,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
isChange: addr.isChange,
type: P2pkhAddressType.p2pkh,
network: BitcoinCashNetwork.mainnet,
derivationInfo: BitcoinAddressUtils.getDerivationFromType(P2pkhAddressType.p2pkh),
);
} catch (_) {
return BitcoinAddressRecord(
@ -161,6 +162,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
isChange: addr.isChange,
type: P2pkhAddressType.p2pkh,
network: BitcoinCashNetwork.mainnet,
derivationInfo: BitcoinAddressUtils.getDerivationFromType(P2pkhAddressType.p2pkh),
);
}
}).toList(),

View file

@ -24,6 +24,12 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
required bool isChange,
required int index,
required BitcoinAddressType addressType,
required BitcoinDerivationInfo derivationInfo,
}) =>
P2pkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
P2pkhAddress.fromDerivation(
bip32: bip32,
derivationInfo: derivationInfo,
isChange: isChange,
index: index,
);
}

View file

@ -189,16 +189,13 @@ class WalletInfo extends HiveObject {
@HiveField(22)
String? parentAddress;
@HiveField(23)
List<String>? hiddenAddresses;
@HiveField(24)
List<String>? manualAddresses;
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
set yatLastUsedAddress(String address) {