mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-29 04:49:51 +00:00
feat: fix missing addrs
This commit is contained in:
parent
4015d32e97
commit
da37e11cfb
10 changed files with 336 additions and 173 deletions
|
@ -16,6 +16,7 @@ abstract class BaseBitcoinAddressRecord {
|
|||
String name = '',
|
||||
bool isUsed = false,
|
||||
required this.type,
|
||||
this.seedBytesType,
|
||||
bool? isHidden,
|
||||
}) : _txCount = txCount,
|
||||
_balance = balance,
|
||||
|
@ -62,6 +63,10 @@ abstract class BaseBitcoinAddressRecord {
|
|||
|
||||
BitcoinAddressType type;
|
||||
|
||||
final SeedBytesType? seedBytesType;
|
||||
|
||||
String get derivationPath => '';
|
||||
|
||||
String toJSON() => json.encode({
|
||||
'address': address,
|
||||
'index': index,
|
||||
|
@ -73,6 +78,8 @@ abstract class BaseBitcoinAddressRecord {
|
|||
'balance': balance,
|
||||
'type': type.toString(),
|
||||
'runtimeType': runtimeType.toString(),
|
||||
'seedBytesType': seedBytesType?.value,
|
||||
'derivationPath': derivationPath,
|
||||
});
|
||||
|
||||
static BaseBitcoinAddressRecord fromJSON(
|
||||
|
@ -98,15 +105,19 @@ abstract class BaseBitcoinAddressRecord {
|
|||
|
||||
class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||
final BitcoinDerivationInfo derivationInfo;
|
||||
final SeedBytesType seedBytesType;
|
||||
|
||||
String _derivationPath = '';
|
||||
|
||||
@override
|
||||
String get derivationPath => _derivationPath;
|
||||
|
||||
BitcoinAddressRecord(
|
||||
super.address, {
|
||||
required super.index,
|
||||
required this.derivationInfo,
|
||||
required this.seedBytesType,
|
||||
super.seedBytesType,
|
||||
super.isHidden,
|
||||
super.isChange = false,
|
||||
required super.isChange,
|
||||
super.txCount = 0,
|
||||
super.balance = 0,
|
||||
super.name = '',
|
||||
|
@ -114,6 +125,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
required super.type,
|
||||
String? scriptHash,
|
||||
BasedUtxoNetwork? network,
|
||||
String? derivationPath,
|
||||
}) {
|
||||
if (scriptHash != null) {
|
||||
this.scriptHash = scriptHash;
|
||||
|
@ -122,6 +134,14 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
} else {
|
||||
throw ArgumentError('either scriptHash or network must be provided');
|
||||
}
|
||||
|
||||
if (derivationPath == null)
|
||||
_derivationPath = derivationInfo.derivationPath
|
||||
.addElem(Bip32KeyIndex(isChange ? 1 : 0))
|
||||
.addElem(Bip32KeyIndex(index))
|
||||
.toString();
|
||||
else
|
||||
_derivationPath = derivationPath;
|
||||
}
|
||||
|
||||
factory BitcoinAddressRecord.fromJSON(
|
||||
|
@ -131,18 +151,18 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
]) {
|
||||
final decoded = json.decode(jsonSource) as Map;
|
||||
final derivationInfoSnp = decoded['derivationInfo'] as Map<String, dynamic>?;
|
||||
final derivationTypeSnp = decoded['derivationType'] as int?;
|
||||
final cwDerivationType = derivationTypeSnp != null
|
||||
? SeedBytesType.values[derivationTypeSnp]
|
||||
: derivationInfo!.derivationType == DerivationType.bip39
|
||||
final seedBytesTypeSnp = decoded['seedBytesType'] as String?;
|
||||
final seedBytesType = seedBytesTypeSnp == null
|
||||
? derivationInfo!.derivationType == DerivationType.bip39
|
||||
? SeedBytesType.old_bip39
|
||||
: SeedBytesType.old_electrum;
|
||||
: SeedBytesType.old_electrum
|
||||
: SeedBytesType.fromValue(seedBytesTypeSnp.toString());
|
||||
|
||||
return BitcoinAddressRecord(
|
||||
decoded['address'] as String,
|
||||
index: decoded['index'] as int,
|
||||
derivationInfo: derivationInfoSnp == null
|
||||
? [SeedBytesType.bip39, SeedBytesType.old_bip39].contains(cwDerivationType)
|
||||
? !seedBytesType.isElectrum
|
||||
? BitcoinDerivationInfo.fromDerivationAndAddress(
|
||||
BitcoinDerivationType.bip39,
|
||||
decoded['address'] as String,
|
||||
|
@ -150,7 +170,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
)
|
||||
: BitcoinDerivationInfos.ELECTRUM
|
||||
: BitcoinDerivationInfo.fromJSON(derivationInfoSnp),
|
||||
seedBytesType: cwDerivationType,
|
||||
seedBytesType: seedBytesType,
|
||||
isHidden: decoded['isHidden'] as bool? ?? false,
|
||||
isChange: decoded['isChange'] as bool? ?? false,
|
||||
isUsed: decoded['isUsed'] as bool? ?? false,
|
||||
|
@ -171,7 +191,6 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
String toJSON() {
|
||||
final m = json.decode(super.toJSON()) as Map<String, dynamic>;
|
||||
m['derivationInfo'] = derivationInfo.toJSON();
|
||||
m['derivationType'] = seedBytesType.index;
|
||||
m['scriptHash'] = scriptHash;
|
||||
return json.encode(m);
|
||||
}
|
||||
|
@ -202,6 +221,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
||||
String _derivationPath;
|
||||
|
||||
@override
|
||||
String get derivationPath => _derivationPath;
|
||||
|
||||
int get labelIndex => index;
|
||||
|
@ -219,6 +239,7 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
|||
super.isUsed = false,
|
||||
super.type = SilentPaymentsAddresType.p2sp,
|
||||
required super.isChange,
|
||||
super.seedBytesType,
|
||||
super.isHidden,
|
||||
this.labelHex,
|
||||
}) : _derivationPath = derivationPath,
|
||||
|
@ -247,13 +268,13 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
|||
labelHex: decoded['labelHex'] as String?,
|
||||
isChange: decoded['isChange'] as bool? ?? false,
|
||||
isHidden: decoded['isHidden'] as bool?,
|
||||
seedBytesType: SeedBytesType.fromValue(decoded['seedBytesType'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toJSON() {
|
||||
final m = json.decode(super.toJSON()) as Map<String, dynamic>;
|
||||
m['derivationPath'] = _derivationPath;
|
||||
m['index'] = labelIndex;
|
||||
m['labelHex'] = labelHex;
|
||||
return json.encode(m);
|
||||
|
@ -264,6 +285,9 @@ class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord {
|
|||
final String tweak;
|
||||
final String spAddress;
|
||||
|
||||
@override
|
||||
String get derivationPath => '';
|
||||
|
||||
BitcoinReceivedSPAddressRecord(
|
||||
super.address, {
|
||||
required super.labelIndex,
|
||||
|
@ -274,6 +298,7 @@ class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord {
|
|||
required this.tweak,
|
||||
required this.spAddress,
|
||||
required super.isChange,
|
||||
super.seedBytesType,
|
||||
super.labelHex,
|
||||
}) : super(isHidden: true, type: SegwitAddressType.p2tr);
|
||||
|
||||
|
@ -310,6 +335,9 @@ class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord {
|
|||
tweak: decoded['tweak'] as String? ?? decoded['silent_payment_tweak'] as String? ?? '',
|
||||
isChange: decoded['isChange'] as bool? ?? false,
|
||||
spAddress: decoded['spAddress'] as String? ?? '',
|
||||
seedBytesType: (decoded['seedBytesType'] as String?) == null
|
||||
? null
|
||||
: SeedBytesType.fromValue(decoded['seedBytesType'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -323,9 +351,15 @@ class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord {
|
|||
}
|
||||
|
||||
class LitecoinMWEBAddressRecord extends BaseBitcoinAddressRecord {
|
||||
String _derivationPath = '';
|
||||
|
||||
@override
|
||||
String get derivationPath => _derivationPath;
|
||||
|
||||
LitecoinMWEBAddressRecord(
|
||||
super.address, {
|
||||
required super.index,
|
||||
super.seedBytesType,
|
||||
super.isHidden,
|
||||
super.isChange = false,
|
||||
super.txCount = 0,
|
||||
|
@ -333,7 +367,11 @@ class LitecoinMWEBAddressRecord extends BaseBitcoinAddressRecord {
|
|||
super.name = '',
|
||||
super.isUsed = false,
|
||||
BasedUtxoNetwork? network,
|
||||
}) : super(type: SegwitAddressType.mweb);
|
||||
}) : super(type: SegwitAddressType.mweb) {
|
||||
var mwebPath = BitcoinDerivationInfos.LITECOIN_MWEB.derivationPath;
|
||||
|
||||
_derivationPath = mwebPath.addElem(Bip32KeyIndex(index)).toString();
|
||||
}
|
||||
|
||||
factory LitecoinMWEBAddressRecord.fromJSON(String jsonSource) {
|
||||
final decoded = json.decode(jsonSource) as Map;
|
||||
|
@ -347,6 +385,9 @@ class LitecoinMWEBAddressRecord extends BaseBitcoinAddressRecord {
|
|||
txCount: decoded['txCount'] as int? ?? 0,
|
||||
name: decoded['name'] as String? ?? '',
|
||||
balance: decoded['balance'] as int? ?? 0,
|
||||
seedBytesType: (decoded['seedBytesType'] as String?) == null
|
||||
? null
|
||||
: SeedBytesType.fromValue(decoded['seedBytesType'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,17 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
|||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
class BitcoinUnspent extends Unspent {
|
||||
BitcoinUnspent(BaseBitcoinAddressRecord addressRecord, String hash, int value, int vout)
|
||||
: bitcoinAddressRecord = addressRecord,
|
||||
super(addressRecord.address, hash, value, vout, null);
|
||||
BitcoinUnspent(
|
||||
BaseBitcoinAddressRecord addressRecord,
|
||||
String hash,
|
||||
int value,
|
||||
int vout,
|
||||
int? height,
|
||||
) : bitcoinAddressRecord = addressRecord,
|
||||
super(addressRecord.address, hash, value, vout, null, height: height);
|
||||
|
||||
factory BitcoinUnspent.fromUTXO(BaseBitcoinAddressRecord address, ElectrumUtxo utxo) =>
|
||||
BitcoinUnspent(address, utxo.txId, utxo.value.toInt(), utxo.vout);
|
||||
BitcoinUnspent(address, utxo.txId, utxo.value.toInt(), utxo.vout, utxo.height);
|
||||
|
||||
factory BitcoinUnspent.fromJSON(
|
||||
BaseBitcoinAddressRecord? address,
|
||||
|
@ -27,6 +32,7 @@ class BitcoinUnspent extends Unspent {
|
|||
json['tx_hash'] as String,
|
||||
int.parse(json['value'].toString()),
|
||||
int.parse(json['tx_pos'].toString()),
|
||||
json['height'] as int?,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -36,6 +42,7 @@ class BitcoinUnspent extends Unspent {
|
|||
'tx_hash': hash,
|
||||
'value': value,
|
||||
'tx_pos': vout,
|
||||
'height': height,
|
||||
};
|
||||
return json;
|
||||
}
|
||||
|
|
|
@ -302,58 +302,6 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
super.address = addr;
|
||||
}
|
||||
|
||||
@override
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required SeedBytesType seedBytesType,
|
||||
required bool isChange,
|
||||
required int index,
|
||||
required BitcoinAddressType addressType,
|
||||
required BitcoinDerivationInfo derivationInfo,
|
||||
}) {
|
||||
final hdWallet = hdWallets[seedBytesType]!;
|
||||
|
||||
switch (addressType) {
|
||||
case P2pkhAddressType.p2pkh:
|
||||
return P2pkhAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
case SegwitAddressType.p2tr:
|
||||
return P2trAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
case SegwitAddressType.p2wsh:
|
||||
return P2wshAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
case P2shAddressType.p2wpkhInP2sh:
|
||||
return P2shAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
type: P2shAddressType.p2wpkhInP2sh,
|
||||
);
|
||||
case SegwitAddressType.p2wpkh:
|
||||
return P2wpkhAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
default:
|
||||
throw ArgumentError('Invalid address type');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@action
|
||||
BaseBitcoinAddressRecord generateNewAddress({String label = ''}) {
|
||||
|
|
|
@ -25,7 +25,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}) : _allAddresses = ObservableList.of(initialAddresses ?? []),
|
||||
currentReceiveAddressIndexByType = initialRegularAddressIndex ?? {},
|
||||
currentChangeAddressIndexByType = initialChangeAddressIndex ?? {},
|
||||
_addressPageType = initialAddressPageType ??
|
||||
addressPageType = initialAddressPageType ??
|
||||
(walletInfo.addressPageType != null
|
||||
? BitcoinAddressType.fromValue(walletInfo.addressPageType!)
|
||||
: SegwitAddressType.p2wpkh),
|
||||
|
@ -48,11 +48,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
final Map<SeedBytesType, Bip32Slip10Secp256k1> hdWallets;
|
||||
Bip32Slip10Secp256k1 get hdWallet =>
|
||||
hdWallets[SeedBytesType.bip39] ?? hdWallets[SeedBytesType.electrum]!;
|
||||
bool get seedTypeIsElectrum =>
|
||||
hdWallets[SeedBytesType.bip39] == null && hdWallets[SeedBytesType.electrum] != null;
|
||||
|
||||
final bool isHardwareWallet;
|
||||
|
||||
@observable
|
||||
late BitcoinAddressType _addressPageType;
|
||||
BitcoinAddressType addressPageType;
|
||||
|
||||
@computed
|
||||
List<BitcoinAddressRecord> get allChangeAddresses =>
|
||||
|
@ -72,9 +74,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
]) =>
|
||||
(isChange ? changeAddressesByType[type] : receiveAddressesByType[type]) ?? [];
|
||||
|
||||
@computed
|
||||
BitcoinAddressType get addressPageType => _addressPageType;
|
||||
|
||||
@computed
|
||||
List<BitcoinAddressRecord> get allAddresses => _allAddresses.toList();
|
||||
|
||||
|
@ -176,18 +175,18 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
Map<String, int> currentReceiveAddressIndexByType;
|
||||
|
||||
int get currentReceiveAddressIndex =>
|
||||
currentReceiveAddressIndexByType[_addressPageType.toString()] ?? 0;
|
||||
currentReceiveAddressIndexByType[addressPageType.toString()] ?? 0;
|
||||
|
||||
void set currentReceiveAddressIndex(int index) =>
|
||||
currentReceiveAddressIndexByType[_addressPageType.toString()] = index;
|
||||
currentReceiveAddressIndexByType[addressPageType.toString()] = index;
|
||||
|
||||
Map<String, int> currentChangeAddressIndexByType;
|
||||
|
||||
int get currentChangeAddressIndex =>
|
||||
currentChangeAddressIndexByType[_addressPageType.toString()] ?? 0;
|
||||
currentChangeAddressIndexByType[addressPageType.toString()] ?? 0;
|
||||
|
||||
void set currentChangeAddressIndex(int index) =>
|
||||
currentChangeAddressIndexByType[_addressPageType.toString()] = index;
|
||||
currentChangeAddressIndexByType[addressPageType.toString()] = index;
|
||||
|
||||
SeedBytesType getHDWalletType() {
|
||||
if (hdWallets.containsKey(SeedBytesType.bip39)) {
|
||||
|
@ -246,7 +245,48 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
required BitcoinAddressType addressType,
|
||||
required BitcoinDerivationInfo derivationInfo,
|
||||
}) {
|
||||
throw UnimplementedError();
|
||||
final hdWallet = hdWallets[seedBytesType]!;
|
||||
|
||||
switch (addressType) {
|
||||
case P2pkhAddressType.p2pkh:
|
||||
return P2pkhAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
case SegwitAddressType.p2tr:
|
||||
return P2trAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
case SegwitAddressType.p2wsh:
|
||||
return P2wshAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
case P2shAddressType.p2wpkhInP2sh:
|
||||
return P2shAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
type: P2shAddressType.p2wpkhInP2sh,
|
||||
);
|
||||
case SegwitAddressType.p2wpkh:
|
||||
return P2wpkhAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
default:
|
||||
throw ArgumentError('Invalid address type');
|
||||
}
|
||||
}
|
||||
|
||||
String getAddress({
|
||||
|
@ -342,11 +382,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
final newAddresses = <BitcoinAddressRecord>[];
|
||||
|
||||
final isHidden = seedBytesType.isElectrum
|
||||
? derivationInfo.derivationPath.toString() !=
|
||||
BitcoinDerivationInfos.ELECTRUM.derivationPath.toString()
|
||||
: derivationInfo.derivationPath.toString() !=
|
||||
BitcoinDerivationInfos.BIP84.derivationPath.toString();
|
||||
final isHidden = getShouldHideAddress(derivationInfo.derivationPath);
|
||||
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final address = BitcoinAddressRecord(
|
||||
|
@ -445,15 +481,15 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
@action
|
||||
void updateHiddenAddresses() {
|
||||
this.hiddenAddresses.clear();
|
||||
this.hiddenAddresses.addAll(_allAddresses
|
||||
hiddenAddresses.clear();
|
||||
hiddenAddresses.addAll(_allAddresses
|
||||
.where((addressRecord) => !getIsReceive(addressRecord))
|
||||
.map((addressRecord) => addressRecord.address));
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> setAddressType(BitcoinAddressType type) async {
|
||||
_addressPageType = type;
|
||||
addressPageType = type;
|
||||
updateAddressesByType();
|
||||
walletInfo.addressPageType = addressPageType.toString();
|
||||
await walletInfo.save();
|
||||
|
@ -549,7 +585,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
for (final usedAddress in usedAddresses) {
|
||||
final isChange = usedAddress.isChange;
|
||||
|
||||
final alreadyDiscoveredSeedType = discoveredAddresses[usedAddress.seedBytesType];
|
||||
final alreadyDiscoveredSeedType = discoveredAddresses[usedAddress.seedBytesType!];
|
||||
final alreadyDiscoveredAddressType = alreadyDiscoveredSeedType?[usedAddress.type];
|
||||
final alreadyDiscoveredDerivationType =
|
||||
alreadyDiscoveredAddressType?[usedAddress.derivationInfo.derivationType];
|
||||
|
@ -561,7 +597,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
final matchingAddressList = allAddresses.where(
|
||||
(addr) =>
|
||||
addr.seedBytesType == usedAddress.seedBytesType &&
|
||||
addr.seedBytesType! == usedAddress.seedBytesType! &&
|
||||
addr.type == usedAddress.type &&
|
||||
addr.derivationInfo.derivationType == usedAddress.derivationInfo.derivationType &&
|
||||
addr.isChange == isChange,
|
||||
|
@ -573,17 +609,17 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
final isAddressUsedAboveGap = usedAddress.index >= totalMatchingAddresses - matchingGapLimit;
|
||||
|
||||
if (isAddressUsedAboveGap) {
|
||||
discoveredAddresses.putIfAbsent(usedAddress.seedBytesType, () => {});
|
||||
discoveredAddresses[usedAddress.seedBytesType]!.putIfAbsent(usedAddress.type, () => {});
|
||||
discoveredAddresses[usedAddress.seedBytesType]![usedAddress.type]!
|
||||
discoveredAddresses.putIfAbsent(usedAddress.seedBytesType!, () => {});
|
||||
discoveredAddresses[usedAddress.seedBytesType!]!.putIfAbsent(usedAddress.type, () => {});
|
||||
discoveredAddresses[usedAddress.seedBytesType!]![usedAddress.type]!
|
||||
.putIfAbsent(usedAddress.derivationInfo.derivationType, () => []);
|
||||
discoveredAddresses[usedAddress.seedBytesType]![usedAddress.type]![
|
||||
discoveredAddresses[usedAddress.seedBytesType!]![usedAddress.type]![
|
||||
usedAddress.derivationInfo.derivationType]!
|
||||
.add(isChange);
|
||||
|
||||
final theseAddresses = await discoverNewAddresses(
|
||||
isChange: isChange,
|
||||
seedBytesType: usedAddress.seedBytesType,
|
||||
seedBytesType: usedAddress.seedBytesType!,
|
||||
addressType: usedAddress.type,
|
||||
derivationInfo: usedAddress.derivationInfo,
|
||||
);
|
||||
|
@ -591,7 +627,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
final newMatchingAddressList = allAddresses.where(
|
||||
(addr) =>
|
||||
addr.seedBytesType == usedAddress.seedBytesType &&
|
||||
addr.seedBytesType == usedAddress.seedBytesType! &&
|
||||
addr.type == usedAddress.type &&
|
||||
addr.derivationInfo.derivationType == usedAddress.derivationInfo.derivationType &&
|
||||
addr.isChange == isChange,
|
||||
|
@ -599,7 +635,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
printV(
|
||||
"discovered ${theseAddresses.length} new ${isChange ? "change" : "receive"} addresses");
|
||||
printV(
|
||||
"Of type ${usedAddress.type} and derivation type ${usedAddress.seedBytesType}, new total: ${newMatchingAddressList.length}");
|
||||
"Of type ${usedAddress.type} and derivation type ${usedAddress.seedBytesType!}, new total: ${newMatchingAddressList.length}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,4 +644,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
return newAddresses;
|
||||
}
|
||||
|
||||
bool getShouldHideAddress(Bip32Path path) {
|
||||
if (seedTypeIsElectrum) {
|
||||
return path.toString() != BitcoinDerivationInfos.ELECTRUM.derivationPath.toString();
|
||||
}
|
||||
|
||||
return path.toString() != BitcoinDerivationInfos.BIP84.derivationPath.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1581,7 +1581,13 @@ class ElectrumWorker {
|
|||
spAddress: matchingSPWallet.toAddress(scanData.network),
|
||||
);
|
||||
|
||||
final unspent = BitcoinUnspent(receivedAddressRecord, txid, amount, pos);
|
||||
final unspent = BitcoinUnspent(
|
||||
receivedAddressRecord,
|
||||
txid,
|
||||
amount,
|
||||
pos,
|
||||
tweakHeight,
|
||||
);
|
||||
|
||||
unspents.add(unspent);
|
||||
txInfo.amount += unspent.value;
|
||||
|
|
|
@ -783,6 +783,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
outputId,
|
||||
utxo.value.toInt(),
|
||||
mwebAddrs.indexOf(utxo.address),
|
||||
utxo.height,
|
||||
);
|
||||
if (unspent.vout == 0) {
|
||||
unspent.isChange = true;
|
||||
|
@ -1460,6 +1461,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
return tx;
|
||||
}
|
||||
|
||||
final status = await CwMweb.status(StatusRequest());
|
||||
|
||||
// check if any of the inputs of this transaction are hog-ex:
|
||||
// this list is only non-mweb inputs:
|
||||
tx2.inputs.forEach((txInput) {
|
||||
|
@ -1475,6 +1478,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
|
||||
int confirmations = utxo.confirmations ?? 0;
|
||||
if (confirmations == 0 && utxo.height != null) {
|
||||
confirmations = status.mwebUtxosHeight - utxo.height!;
|
||||
}
|
||||
|
||||
if (confirmations < 6) {
|
||||
throw Exception(
|
||||
"A transaction input has less than 6 confirmations, please try again later.");
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:io' show Platform;
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
|
@ -52,6 +53,12 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
List<String> mwebAddrs = [];
|
||||
bool generating = false;
|
||||
|
||||
@observable
|
||||
int mwebIndex = 0;
|
||||
|
||||
@observable
|
||||
LitecoinMWEBAddressRecord? activeMwebAddress;
|
||||
|
||||
List<int> get scanSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
|
||||
List<int> get spendPubkey =>
|
||||
mwebHd!.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed;
|
||||
|
@ -60,16 +67,19 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
Future<void> init() async {
|
||||
if (!super.isHardwareWallet) await initMwebAddresses();
|
||||
|
||||
for (final derivationType in hdWallets.keys) {
|
||||
for (final seedBytesType in hdWallets.keys) {
|
||||
await generateInitialAddresses(
|
||||
addressType: P2pkhAddressType.p2pkh,
|
||||
seedBytesType: derivationType,
|
||||
addressType: SegwitAddressType.p2wpkh,
|
||||
seedBytesType: seedBytesType,
|
||||
bitcoinDerivationInfo: seedBytesType.isElectrum
|
||||
? BitcoinDerivationInfos.ELECTRUM
|
||||
: BitcoinDerivationInfos.LITECOIN,
|
||||
);
|
||||
|
||||
if ((Platform.isAndroid || Platform.isIOS) && !isHardwareWallet) {
|
||||
await generateInitialAddresses(
|
||||
await generateInitialMWEBAddresses(
|
||||
addressType: SegwitAddressType.mweb,
|
||||
seedBytesType: derivationType,
|
||||
seedBytesType: seedBytesType,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +87,50 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
await super.init();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> generateInitialMWEBAddresses({
|
||||
required BitcoinAddressType addressType,
|
||||
required SeedBytesType seedBytesType,
|
||||
}) async {
|
||||
final existingAddresses = mwebAddresses
|
||||
.where((addr) => addr.type == addressType && addr.seedBytesType == seedBytesType)
|
||||
.toList();
|
||||
|
||||
if (existingAddresses.length < ElectrumWalletAddressesBase.defaultReceiveAddressesCount) {
|
||||
await discoverNewMWEBAddresses(
|
||||
seedBytesType: seedBytesType,
|
||||
isChange: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<List<LitecoinMWEBAddressRecord>> discoverNewMWEBAddresses({
|
||||
required SeedBytesType seedBytesType,
|
||||
required bool isChange,
|
||||
}) async {
|
||||
final count = isChange
|
||||
? ElectrumWalletAddressesBase.defaultChangeAddressesCount
|
||||
: ElectrumWalletAddressesBase.defaultReceiveAddressesCount;
|
||||
|
||||
final startIndex = this.mwebAddresses.length;
|
||||
|
||||
final mwebAddresses = <LitecoinMWEBAddressRecord>[];
|
||||
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final address = LitecoinMWEBAddressRecord(
|
||||
(await generateMWEBAddress(index: i)).toAddress(network),
|
||||
index: i,
|
||||
seedBytesType: seedBytesType,
|
||||
);
|
||||
mwebAddresses.add(address);
|
||||
}
|
||||
|
||||
addMwebAddresses(mwebAddresses);
|
||||
return mwebAddresses;
|
||||
}
|
||||
|
||||
@override
|
||||
@action
|
||||
Future<List<BitcoinAddressRecord>> discoverNewAddresses({
|
||||
required SeedBytesType seedBytesType,
|
||||
|
@ -84,52 +138,40 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
required BitcoinAddressType addressType,
|
||||
required BitcoinDerivationInfo derivationInfo,
|
||||
}) async {
|
||||
final count = isChange
|
||||
? ElectrumWalletAddressesBase.defaultChangeAddressesCount
|
||||
: ElectrumWalletAddressesBase.defaultReceiveAddressesCount;
|
||||
if (addressType == SegwitAddressType.mweb) {
|
||||
final count = isChange
|
||||
? ElectrumWalletAddressesBase.defaultChangeAddressesCount
|
||||
: ElectrumWalletAddressesBase.defaultReceiveAddressesCount;
|
||||
|
||||
final startIndex = getAddressesByType(addressType, isChange)
|
||||
.where((addr) => (addr as BitcoinAddressRecord).seedBytesType == seedBytesType)
|
||||
.length;
|
||||
final startIndex = this.mwebAddresses.length;
|
||||
|
||||
final mwebAddresses = <LitecoinMWEBAddressRecord>[];
|
||||
final newAddresses = <BitcoinAddressRecord>[];
|
||||
final mwebAddresses = <LitecoinMWEBAddressRecord>[];
|
||||
|
||||
final isHidden = seedBytesType.isElectrum
|
||||
? derivationInfo.derivationPath != BitcoinDerivationInfos.ELECTRUM.derivationPath
|
||||
: derivationInfo.derivationPath != BitcoinDerivationInfos.BIP84.derivationPath;
|
||||
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final addressString = await getAddressAsync(
|
||||
derivationType: seedBytesType,
|
||||
isChange: isChange,
|
||||
index: i,
|
||||
addressType: addressType,
|
||||
derivationInfo: derivationInfo,
|
||||
);
|
||||
|
||||
if (addressType == SegwitAddressType.mweb) {
|
||||
final address = LitecoinMWEBAddressRecord(addressString, index: i);
|
||||
mwebAddresses.add(address);
|
||||
} else {
|
||||
final address = BitcoinAddressRecord(
|
||||
addressString,
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final address = LitecoinMWEBAddressRecord(
|
||||
await getAddressAsync(
|
||||
derivationType: seedBytesType,
|
||||
isChange: isChange,
|
||||
index: i,
|
||||
addressType: addressType,
|
||||
derivationInfo: derivationInfo,
|
||||
),
|
||||
index: i,
|
||||
isChange: isChange,
|
||||
isHidden: isHidden || isChange,
|
||||
type: addressType,
|
||||
network: network,
|
||||
derivationInfo: derivationInfo,
|
||||
seedBytesType: seedBytesType,
|
||||
);
|
||||
|
||||
newAddresses.add(address);
|
||||
mwebAddresses.add(address);
|
||||
}
|
||||
|
||||
addMwebAddresses(mwebAddresses);
|
||||
// TODO:
|
||||
return [];
|
||||
}
|
||||
|
||||
addAddresses(newAddresses);
|
||||
addMwebAddresses(mwebAddresses);
|
||||
return newAddresses;
|
||||
return super.discoverNewAddresses(
|
||||
seedBytesType: seedBytesType,
|
||||
isChange: isChange,
|
||||
addressType: addressType,
|
||||
derivationInfo: derivationInfo,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> ensureMwebAddressUpToIndexExists(int index) async {
|
||||
|
@ -189,6 +231,11 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
}
|
||||
}
|
||||
|
||||
Future<BitcoinBaseAddress> generateMWEBAddress({required int index}) async {
|
||||
await ensureMwebAddressUpToIndexExists(index);
|
||||
return MwebAddress.fromAddress(address: mwebAddrs[index]);
|
||||
}
|
||||
|
||||
@override
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required SeedBytesType seedBytesType,
|
||||
|
@ -285,11 +332,46 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
}
|
||||
|
||||
@override
|
||||
@computed
|
||||
String get address {
|
||||
if (addressPageType == SegwitAddressType.mweb) {
|
||||
if (activeMwebAddress != null) {
|
||||
return activeMwebAddress!.address;
|
||||
}
|
||||
|
||||
return mwebAddresses[0].address;
|
||||
}
|
||||
|
||||
return super.address;
|
||||
}
|
||||
|
||||
@override
|
||||
set address(String addr) {
|
||||
if (addressPageType == SegwitAddressType.mweb) {
|
||||
final selected =
|
||||
mwebAddresses.firstWhereOrNull((addressRecord) => addressRecord.address == addr) ??
|
||||
mwebAddresses[0];
|
||||
|
||||
activeMwebAddress = selected;
|
||||
|
||||
if (!selected.isChange) {
|
||||
mwebIndex = selected.index;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
super.address = addr;
|
||||
}
|
||||
|
||||
@override
|
||||
@computed
|
||||
String get addressForExchange {
|
||||
// don't use mweb addresses for exchange refund address:
|
||||
final addresses = selectedReceiveAddresses
|
||||
.where((element) => element.type == SegwitAddressType.p2wpkh && !element.isUsed);
|
||||
return addresses.first.address;
|
||||
final addresses = allAddresses.firstWhere(
|
||||
(element) => element.type == SegwitAddressType.p2wpkh && getIsUsed(element),
|
||||
);
|
||||
return addresses.address;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -344,10 +426,15 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
|
||||
@action
|
||||
void addMwebAddresses(Iterable<LitecoinMWEBAddressRecord> addresses) {
|
||||
final addressesSet = this.mwebAddresses.toSet();
|
||||
addressesSet.addAll(addresses);
|
||||
this.mwebAddresses.clear();
|
||||
this.mwebAddresses.addAll(addressesSet);
|
||||
final newMwebAddresses = <LitecoinMWEBAddressRecord>[];
|
||||
for (final address in addresses) {
|
||||
if (mwebAddresses.any((existing) => existing.address == address.address)) {
|
||||
continue;
|
||||
}
|
||||
newMwebAddresses.add(address);
|
||||
}
|
||||
|
||||
this.mwebAddresses.addAll(newMwebAddresses);
|
||||
updateAddressesByType();
|
||||
}
|
||||
|
||||
|
@ -408,4 +495,20 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
mwebEnabled: true, // TODO
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@action
|
||||
void updateAddressesByType() {
|
||||
receiveAddressesByType[SegwitAddressType.mweb] = mwebAddresses.toList();
|
||||
super.updateAddressesByType();
|
||||
}
|
||||
|
||||
@override
|
||||
bool getShouldHideAddress(Bip32Path path) {
|
||||
if (seedTypeIsElectrum) {
|
||||
return path.toString() != BitcoinDerivationInfos.ELECTRUM.derivationPath.toString();
|
||||
}
|
||||
|
||||
return path.toString() != BitcoinDerivationInfos.LITECOIN.derivationPath.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,32 +26,30 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
|||
|
||||
static const BITCOIN_CASH_ADDRESS_TYPES = [P2pkhAddressType.p2pkh];
|
||||
|
||||
@override
|
||||
@observable
|
||||
BitcoinAddressType changeAddressType = P2pkhAddressType.p2pkh;
|
||||
|
||||
@override
|
||||
BitcoinAddressType get addressPageType => P2pkhAddressType.p2pkh;
|
||||
|
||||
@override
|
||||
Future<void> init() async {
|
||||
for (final seedBytesType in hdWallets.keys) {
|
||||
await generateInitialAddresses(
|
||||
addressType: P2pkhAddressType.p2pkh,
|
||||
seedBytesType: seedBytesType,
|
||||
bitcoinDerivationInfo: BitcoinDerivationInfo(
|
||||
derivationType: BitcoinDerivationType.bip39,
|
||||
derivationPath: "m/44'/145'/0'",
|
||||
description: "Default Bitcoin Cash",
|
||||
scriptType: P2pkhAddressType.p2pkh,
|
||||
),
|
||||
);
|
||||
}
|
||||
await super.init();
|
||||
}
|
||||
|
||||
@override
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required SeedBytesType seedBytesType,
|
||||
required bool isChange,
|
||||
required int index,
|
||||
required BitcoinAddressType addressType,
|
||||
required BitcoinDerivationInfo derivationInfo,
|
||||
}) =>
|
||||
P2pkhAddress.fromDerivation(
|
||||
bip32: hdWallet,
|
||||
derivationInfo: derivationInfo,
|
||||
isChange: isChange,
|
||||
index: index,
|
||||
);
|
||||
|
||||
static BitcoinCashWalletAddressesBase fromJson(
|
||||
Map<String, dynamic> json,
|
||||
WalletInfo walletInfo, {
|
||||
|
@ -93,4 +91,13 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
|||
initialAddresses: initialAddresses,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool getShouldHideAddress(Bip32Path path) {
|
||||
if (seedTypeIsElectrum) {
|
||||
return path.toString() != BitcoinDerivationInfos.ELECTRUM.derivationPath.toString();
|
||||
}
|
||||
|
||||
return path.toString() != "m/44'/145'/0'";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import 'package:cw_core/unspent_comparable_mixin.dart';
|
||||
|
||||
class Unspent with UnspentComparable {
|
||||
Unspent(this.address, this.hash, this.value, this.vout, this.keyImage)
|
||||
: isSending = true,
|
||||
Unspent(
|
||||
this.address,
|
||||
this.hash,
|
||||
this.value,
|
||||
this.vout,
|
||||
this.keyImage, {
|
||||
this.height,
|
||||
}) : isSending = true,
|
||||
isFrozen = false,
|
||||
isChange = false,
|
||||
note = '';
|
||||
|
@ -16,6 +22,7 @@ class Unspent with UnspentComparable {
|
|||
bool isChange;
|
||||
bool isSending;
|
||||
bool isFrozen;
|
||||
int? height;
|
||||
int? confirmations;
|
||||
String note;
|
||||
|
||||
|
|
|
@ -162,14 +162,7 @@ class CWBitcoin extends Bitcoin {
|
|||
id: addr.index,
|
||||
name: addr.name,
|
||||
address: addr.address,
|
||||
derivationPath: (addr as BitcoinAddressRecord)
|
||||
.derivationInfo
|
||||
.derivationPath
|
||||
.addElem(
|
||||
Bip32KeyIndex(addr.isChange ? 1 : 0),
|
||||
)
|
||||
.addElem(Bip32KeyIndex(addr.index))
|
||||
.toString(),
|
||||
derivationPath: addr.derivationPath,
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isChange,
|
||||
|
@ -560,7 +553,7 @@ class CWBitcoin extends Bitcoin {
|
|||
id: addr.index,
|
||||
name: addr.name,
|
||||
address: addr.address,
|
||||
derivationPath: "",
|
||||
derivationPath: addr.derivationPath,
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isChange,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue