mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-12 09:32:33 +00:00
refactor: misc
This commit is contained in:
parent
d4b0165141
commit
3950f6cd17
21 changed files with 585 additions and 361 deletions
|
@ -153,6 +153,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
}
|
||||
|
||||
class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
||||
final String derivationPath;
|
||||
int get labelIndex => index;
|
||||
final String? labelHex;
|
||||
|
||||
|
@ -161,6 +162,7 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
|||
BitcoinSilentPaymentAddressRecord(
|
||||
super.address, {
|
||||
required int labelIndex,
|
||||
this.derivationPath = BitcoinDerivationPaths.SILENT_PAYMENTS_SPEND,
|
||||
super.txCount = 0,
|
||||
super.balance = 0,
|
||||
super.name = '',
|
||||
|
@ -180,6 +182,7 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
|||
|
||||
return BitcoinSilentPaymentAddressRecord(
|
||||
decoded['address'] as String,
|
||||
derivationPath: decoded['derivationPath'] as String,
|
||||
labelIndex: decoded['labelIndex'] as int,
|
||||
isUsed: decoded['isUsed'] as bool? ?? false,
|
||||
txCount: decoded['txCount'] as int? ?? 0,
|
||||
|
@ -192,6 +195,7 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
|||
@override
|
||||
String toJSON() => json.encode({
|
||||
'address': address,
|
||||
'derivationPath': derivationPath,
|
||||
'labelIndex': labelIndex,
|
||||
'isUsed': isUsed,
|
||||
'txCount': txCount,
|
||||
|
@ -222,13 +226,15 @@ class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord {
|
|||
|
||||
return BitcoinReceivedSPAddressRecord(
|
||||
decoded['address'] as String,
|
||||
labelIndex: decoded['index'] as int,
|
||||
labelIndex: decoded['index'] as int? ?? 1,
|
||||
isUsed: decoded['isUsed'] as bool? ?? false,
|
||||
txCount: decoded['txCount'] as int? ?? 0,
|
||||
name: decoded['name'] as String? ?? '',
|
||||
balance: decoded['balance'] as int? ?? 0,
|
||||
labelHex: decoded['label'] as String?,
|
||||
spendKey: ECPrivate.fromHex(decoded['spendKey'] as String),
|
||||
spendKey: (decoded['spendKey'] as String?) == null
|
||||
? ECPrivate.random()
|
||||
: ECPrivate.fromHex(decoded['spendKey'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,17 +10,27 @@ class BitcoinUnspent extends Unspent {
|
|||
factory BitcoinUnspent.fromUTXO(BaseBitcoinAddressRecord address, ElectrumUtxo utxo) =>
|
||||
BitcoinUnspent(address, utxo.txId, utxo.value.toInt(), utxo.vout);
|
||||
|
||||
factory BitcoinUnspent.fromJSON(BaseBitcoinAddressRecord? address, Map<String, dynamic> json) =>
|
||||
BitcoinUnspent(
|
||||
address ?? BitcoinAddressRecord.fromJSON(json['address_record'].toString()),
|
||||
json['tx_hash'] as String,
|
||||
int.parse(json['value'].toString()),
|
||||
int.parse(json['tx_pos'].toString()),
|
||||
);
|
||||
factory BitcoinUnspent.fromJSON(BaseBitcoinAddressRecord? address, Map<String, dynamic> json) {
|
||||
final addressType = json['address_runtimetype'] as String?;
|
||||
final addressRecord = json['address_record'].toString();
|
||||
|
||||
return BitcoinUnspent(
|
||||
address ??
|
||||
(addressType == null
|
||||
? BitcoinAddressRecord.fromJSON(addressRecord)
|
||||
: addressType.contains("SP")
|
||||
? BitcoinReceivedSPAddressRecord.fromJSON(addressRecord)
|
||||
: BitcoinSilentPaymentAddressRecord.fromJSON(addressRecord)),
|
||||
json['tx_hash'] as String,
|
||||
int.parse(json['value'].toString()),
|
||||
int.parse(json['tx_pos'].toString()),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{
|
||||
'address_record': bitcoinAddressRecord.toJSON(),
|
||||
'address_runtimetype': bitcoinAddressRecord.runtimeType.toString(),
|
||||
'tx_hash': hash,
|
||||
'value': value,
|
||||
'tx_pos': vout,
|
||||
|
|
|
@ -55,6 +55,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
bool? alwaysScan,
|
||||
required bool mempoolAPIEnabled,
|
||||
super.hdWallets,
|
||||
super.initialUnspentCoins,
|
||||
}) : super(
|
||||
mnemonic: mnemonic,
|
||||
passphrase: passphrase,
|
||||
|
@ -111,6 +112,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
final Map<CWBitcoinDerivationType, Bip32Slip10Secp256k1> hdWallets = {};
|
||||
|
||||
for (final derivation in walletInfo.derivations ?? <DerivationInfo>[]) {
|
||||
if (derivation.description?.contains("SP") ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (derivation.derivationType == DerivationType.bip39) {
|
||||
seedBytes = Bip39SeedGenerator.generateFromString(mnemonic, passphrase);
|
||||
hdWallets[CWBitcoinDerivationType.bip39] = Bip32Slip10Secp256k1.fromSeed(seedBytes);
|
||||
|
@ -134,8 +139,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
}
|
||||
|
||||
hdWallets[CWBitcoinDerivationType.old] =
|
||||
hdWallets[CWBitcoinDerivationType.bip39] ?? hdWallets[CWBitcoinDerivationType.electrum]!;
|
||||
if (hdWallets[CWBitcoinDerivationType.bip39] != null) {
|
||||
hdWallets[CWBitcoinDerivationType.old_bip39] = hdWallets[CWBitcoinDerivationType.bip39]!;
|
||||
}
|
||||
if (hdWallets[CWBitcoinDerivationType.electrum] != null) {
|
||||
hdWallets[CWBitcoinDerivationType.old_electrum] = hdWallets[CWBitcoinDerivationType.bip39]!;
|
||||
}
|
||||
|
||||
return BitcoinWallet(
|
||||
mnemonic: mnemonic,
|
||||
|
@ -155,6 +164,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
networkParam: network,
|
||||
mempoolAPIEnabled: mempoolAPIEnabled,
|
||||
hdWallets: hdWallets,
|
||||
initialUnspentCoins: [],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -217,6 +227,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
if (mnemonic != null) {
|
||||
for (final derivation in walletInfo.derivations ?? <DerivationInfo>[]) {
|
||||
if (derivation.description?.contains("SP") ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (derivation.derivationType == DerivationType.bip39) {
|
||||
seedBytes = Bip39SeedGenerator.generateFromString(mnemonic, passphrase);
|
||||
hdWallets[CWBitcoinDerivationType.bip39] = Bip32Slip10Secp256k1.fromSeed(seedBytes);
|
||||
|
@ -242,8 +256,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
}
|
||||
|
||||
hdWallets[CWBitcoinDerivationType.old] =
|
||||
hdWallets[CWBitcoinDerivationType.bip39] ?? hdWallets[CWBitcoinDerivationType.electrum]!;
|
||||
if (hdWallets[CWBitcoinDerivationType.bip39] != null) {
|
||||
hdWallets[CWBitcoinDerivationType.old_bip39] = hdWallets[CWBitcoinDerivationType.bip39]!;
|
||||
}
|
||||
if (hdWallets[CWBitcoinDerivationType.electrum] != null) {
|
||||
hdWallets[CWBitcoinDerivationType.old_electrum] = hdWallets[CWBitcoinDerivationType.bip39]!;
|
||||
}
|
||||
}
|
||||
|
||||
return BitcoinWallet(
|
||||
|
@ -266,6 +284,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
alwaysScan: alwaysScan,
|
||||
mempoolAPIEnabled: mempoolAPIEnabled,
|
||||
hdWallets: hdWallets,
|
||||
initialUnspentCoins: snp?.unspentCoins ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -413,41 +432,69 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
}
|
||||
|
||||
// @override
|
||||
// @action
|
||||
// Future<void> updateAllUnspents() async {
|
||||
// List<BitcoinUnspent> updatedUnspentCoins = [];
|
||||
@override
|
||||
@action
|
||||
Future<void> updateAllUnspents() async {
|
||||
List<BitcoinUnspent> updatedUnspentCoins = [];
|
||||
|
||||
// // Update unspents stored from scanned silent payment transactions
|
||||
// transactionHistory.transactions.values.forEach((tx) {
|
||||
// if (tx.unspents != null) {
|
||||
// updatedUnspentCoins.addAll(tx.unspents!);
|
||||
// }
|
||||
// });
|
||||
// Update unspents stored from scanned silent payment transactions
|
||||
transactionHistory.transactions.values.forEach((tx) {
|
||||
if (tx.unspents != null) {
|
||||
updatedUnspentCoins.addAll(tx.unspents!);
|
||||
}
|
||||
});
|
||||
|
||||
// // Set the balance of all non-silent payment and non-mweb addresses to 0 before updating
|
||||
// walletAddresses.allAddresses
|
||||
// .where((element) => element.type != SegwitAddresType.mweb)
|
||||
// .forEach((addr) {
|
||||
// if (addr is! BitcoinSilentPaymentAddressRecord) addr.balance = 0;
|
||||
// });
|
||||
unspentCoins.addAll(updatedUnspentCoins);
|
||||
|
||||
// await Future.wait(walletAddresses.allAddresses
|
||||
// .where((element) => element.type != SegwitAddresType.mweb)
|
||||
// .map((address) async {
|
||||
// updatedUnspentCoins.addAll(await fetchUnspent(address));
|
||||
// }));
|
||||
await super.updateAllUnspents();
|
||||
|
||||
// unspentCoins.addAll(updatedUnspentCoins);
|
||||
final walletAddresses = this.walletAddresses as BitcoinWalletAddresses;
|
||||
|
||||
// if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
|
||||
// unspentCoins.forEach((coin) => addCoinInfo(coin));
|
||||
// return;
|
||||
// }
|
||||
walletAddresses.silentPaymentAddresses.forEach((addressRecord) {
|
||||
addressRecord.txCount = 0;
|
||||
addressRecord.balance = 0;
|
||||
});
|
||||
walletAddresses.receivedSPAddresses.forEach((addressRecord) {
|
||||
addressRecord.txCount = 0;
|
||||
addressRecord.balance = 0;
|
||||
});
|
||||
|
||||
// await updateCoins(unspentCoins.toSet());
|
||||
// await refreshUnspentCoinsInfo();
|
||||
// }
|
||||
final silentPaymentWallet = walletAddresses.silentPaymentWallet;
|
||||
|
||||
unspentCoins.forEach((unspent) {
|
||||
if (unspent.bitcoinAddressRecord is BitcoinReceivedSPAddressRecord) {
|
||||
_updateSilentAddressRecord(unspent);
|
||||
|
||||
final receiveAddressRecord = unspent.bitcoinAddressRecord as BitcoinReceivedSPAddressRecord;
|
||||
final silentPaymentAddress = SilentPaymentAddress(
|
||||
version: silentPaymentWallet!.version,
|
||||
B_scan: silentPaymentWallet.B_scan,
|
||||
B_spend: receiveAddressRecord.labelHex != null
|
||||
? silentPaymentWallet.B_spend.tweakAdd(
|
||||
BigintUtils.fromBytes(
|
||||
BytesUtils.fromHexString(receiveAddressRecord.labelHex!),
|
||||
),
|
||||
)
|
||||
: silentPaymentWallet.B_spend,
|
||||
);
|
||||
|
||||
walletAddresses.silentPaymentAddresses.forEach((addressRecord) {
|
||||
if (addressRecord.address == silentPaymentAddress.toAddress(network)) {
|
||||
addressRecord.txCount += 1;
|
||||
addressRecord.balance += unspent.value;
|
||||
}
|
||||
});
|
||||
walletAddresses.receivedSPAddresses.forEach((addressRecord) {
|
||||
if (addressRecord.address == receiveAddressRecord.address) {
|
||||
addressRecord.txCount += 1;
|
||||
addressRecord.balance += unspent.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await walletAddresses.updateAddressesInBox();
|
||||
}
|
||||
|
||||
@override
|
||||
void updateCoin(BitcoinUnspent coin) {
|
||||
|
@ -536,26 +583,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
@action
|
||||
void _updateSilentAddressRecord(BitcoinUnspent unspent) {
|
||||
final receiveAddressRecord = unspent.bitcoinAddressRecord as BitcoinReceivedSPAddressRecord;
|
||||
final walletAddresses = this.walletAddresses as BitcoinWalletAddresses;
|
||||
final silentPaymentWallet = walletAddresses.silentPaymentWallet;
|
||||
final silentPaymentAddress = SilentPaymentAddress(
|
||||
version: silentPaymentWallet.version,
|
||||
B_scan: silentPaymentWallet.B_scan,
|
||||
B_spend: receiveAddressRecord.labelHex != null
|
||||
? silentPaymentWallet.B_spend.tweakAdd(
|
||||
BigintUtils.fromBytes(BytesUtils.fromHexString(receiveAddressRecord.labelHex!)),
|
||||
)
|
||||
: silentPaymentWallet.B_spend,
|
||||
);
|
||||
|
||||
final addressRecord = walletAddresses.silentPaymentAddresses
|
||||
.firstWhere((address) => address.address == silentPaymentAddress.toString());
|
||||
addressRecord.txCount += 1;
|
||||
addressRecord.balance += unspent.value;
|
||||
|
||||
walletAddresses.addSilentAddresses(
|
||||
[unspent.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord],
|
||||
walletAddresses.addReceivedSPAddresses(
|
||||
[unspent.bitcoinAddressRecord as BitcoinReceivedSPAddressRecord],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -583,6 +613,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
@action
|
||||
Future<void> onTweaksSyncResponse(TweaksSyncResponse result) async {
|
||||
if (result.transactions?.isNotEmpty == true) {
|
||||
(walletAddresses as BitcoinWalletAddresses).silentPaymentAddresses.forEach((addressRecord) {
|
||||
addressRecord.txCount = 0;
|
||||
addressRecord.balance = 0;
|
||||
});
|
||||
(walletAddresses as BitcoinWalletAddresses).receivedSPAddresses.forEach((addressRecord) {
|
||||
addressRecord.txCount = 0;
|
||||
addressRecord.balance = 0;
|
||||
});
|
||||
|
||||
for (final map in result.transactions!.entries) {
|
||||
final txid = map.key;
|
||||
final tx = map.value;
|
||||
|
@ -628,9 +667,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
// else: First time seeing this TX after scanning
|
||||
tx.unspents!.forEach(_updateSilentAddressRecord);
|
||||
|
||||
// Add new TX record
|
||||
transactionHistory.addOne(tx);
|
||||
// Update balance record
|
||||
balance[currency]!.confirmed += tx.amount;
|
||||
}
|
||||
|
||||
|
@ -654,6 +691,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
await walletInfo.updateRestoreHeight(result.height!);
|
||||
}
|
||||
|
||||
await save();
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -675,7 +714,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
workerSendPort!.send(
|
||||
ElectrumWorkerTweaksSubscribeRequest(
|
||||
scanData: ScanData(
|
||||
silentAddress: walletAddresses.silentPaymentWallet,
|
||||
silentPaymentsWallets: walletAddresses.silentPaymentWallets,
|
||||
network: network,
|
||||
height: height,
|
||||
chainTip: chainTip,
|
||||
|
|
|
@ -26,13 +26,17 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
),
|
||||
super(walletInfo) {
|
||||
silentPaymentWallet = SilentPaymentOwner.fromBip32(hdWallet);
|
||||
silentPaymentWallets = [silentPaymentWallet!];
|
||||
}
|
||||
|
||||
@observable
|
||||
late SilentPaymentOwner silentPaymentWallet;
|
||||
SilentPaymentOwner? silentPaymentWallet;
|
||||
final ObservableList<BitcoinSilentPaymentAddressRecord> silentPaymentAddresses;
|
||||
final ObservableList<BitcoinReceivedSPAddressRecord> receivedSPAddresses;
|
||||
|
||||
@observable
|
||||
List<SilentPaymentOwner> silentPaymentWallets = [];
|
||||
|
||||
@observable
|
||||
String? activeSilentAddress;
|
||||
|
||||
|
@ -48,19 +52,70 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
}
|
||||
|
||||
if (silentPaymentAddresses.length == 0) {
|
||||
silentPaymentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||
silentPaymentWallet.toString(),
|
||||
labelIndex: 1,
|
||||
name: "",
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
));
|
||||
silentPaymentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||
silentPaymentWallet.toLabeledSilentPaymentAddress(0).toString(),
|
||||
name: "",
|
||||
labelIndex: 0,
|
||||
labelHex: BytesUtils.toHexString(silentPaymentWallet.generateLabel(0)),
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
));
|
||||
Bip32Path? oldSpendPath;
|
||||
Bip32Path? oldScanPath;
|
||||
|
||||
for (final derivationInfo in walletInfo.derivations ?? <DerivationInfo>[]) {
|
||||
if (derivationInfo.description?.contains("SP") ?? false) {
|
||||
if (derivationInfo.description?.toLowerCase().contains("spend") ?? false) {
|
||||
oldSpendPath = Bip32PathParser.parse(derivationInfo.derivationPath ?? "");
|
||||
} else if (derivationInfo.description?.toLowerCase().contains("scan") ?? false) {
|
||||
oldScanPath = Bip32PathParser.parse(derivationInfo.derivationPath ?? "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldSpendPath != null && oldScanPath != null) {
|
||||
final oldSpendPriv = hdWallet.derive(oldSpendPath).privateKey;
|
||||
final oldScanPriv = hdWallet.derive(oldScanPath).privateKey;
|
||||
|
||||
final oldSilentPaymentWallet = SilentPaymentOwner(
|
||||
b_scan: ECPrivate(oldScanPriv),
|
||||
b_spend: ECPrivate(oldSpendPriv),
|
||||
B_scan: ECPublic.fromBip32(oldScanPriv.publicKey),
|
||||
B_spend: ECPublic.fromBip32(oldSpendPriv.publicKey),
|
||||
version: 0,
|
||||
);
|
||||
silentPaymentWallets.add(oldSilentPaymentWallet);
|
||||
|
||||
silentPaymentAddresses.addAll(
|
||||
[
|
||||
BitcoinSilentPaymentAddressRecord(
|
||||
oldSilentPaymentWallet.toString(),
|
||||
labelIndex: 1,
|
||||
name: "",
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
derivationPath: oldSpendPath.toString(),
|
||||
isHidden: true,
|
||||
),
|
||||
BitcoinSilentPaymentAddressRecord(
|
||||
oldSilentPaymentWallet.toLabeledSilentPaymentAddress(0).toString(),
|
||||
name: "",
|
||||
labelIndex: 0,
|
||||
labelHex: BytesUtils.toHexString(oldSilentPaymentWallet.generateLabel(0)),
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
derivationPath: oldSpendPath.toString(),
|
||||
isHidden: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
silentPaymentAddresses.addAll([
|
||||
BitcoinSilentPaymentAddressRecord(
|
||||
silentPaymentWallet.toString(),
|
||||
labelIndex: 1,
|
||||
name: "",
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
),
|
||||
BitcoinSilentPaymentAddressRecord(
|
||||
silentPaymentWallet!.toLabeledSilentPaymentAddress(0).toString(),
|
||||
name: "",
|
||||
labelIndex: 0,
|
||||
labelHex: BytesUtils.toHexString(silentPaymentWallet!.generateLabel(0)),
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
await updateAddressesInBox();
|
||||
|
@ -97,7 +152,7 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
|
||||
if (selected.labelHex != null) {
|
||||
activeSilentAddress =
|
||||
silentPaymentWallet.toLabeledSilentPaymentAddress(selected.labelIndex).toString();
|
||||
silentPaymentWallet!.toLabeledSilentPaymentAddress(selected.labelIndex).toString();
|
||||
} else {
|
||||
activeSilentAddress = silentPaymentWallet.toString();
|
||||
}
|
||||
|
@ -117,27 +172,27 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
}) {
|
||||
final hdWallet = hdWallets[derivationType]!;
|
||||
|
||||
if (derivationType == CWBitcoinDerivationType.old) {
|
||||
final pub = hdWallet
|
||||
.childKey(Bip32KeyIndex(isChange ? 1 : 0))
|
||||
.childKey(Bip32KeyIndex(index))
|
||||
.publicKey;
|
||||
// if (OLD_DERIVATION_TYPES.contains(derivationType)) {
|
||||
// final pub = hdWallet
|
||||
// .childKey(Bip32KeyIndex(isChange ? 1 : 0))
|
||||
// .childKey(Bip32KeyIndex(index))
|
||||
// .publicKey;
|
||||
|
||||
switch (addressType) {
|
||||
case P2pkhAddressType.p2pkh:
|
||||
return ECPublic.fromBip32(pub).toP2pkhAddress();
|
||||
case SegwitAddresType.p2tr:
|
||||
return ECPublic.fromBip32(pub).toP2trAddress();
|
||||
case SegwitAddresType.p2wsh:
|
||||
return ECPublic.fromBip32(pub).toP2wshAddress();
|
||||
case P2shAddressType.p2wpkhInP2sh:
|
||||
return ECPublic.fromBip32(pub).toP2wpkhInP2sh();
|
||||
case SegwitAddresType.p2wpkh:
|
||||
return ECPublic.fromBip32(pub).toP2wpkhAddress();
|
||||
default:
|
||||
throw ArgumentError('Invalid address type');
|
||||
}
|
||||
}
|
||||
// switch (addressType) {
|
||||
// case P2pkhAddressType.p2pkh:
|
||||
// return ECPublic.fromBip32(pub).toP2pkhAddress();
|
||||
// case SegwitAddresType.p2tr:
|
||||
// return ECPublic.fromBip32(pub).toP2trAddress();
|
||||
// case SegwitAddresType.p2wsh:
|
||||
// return ECPublic.fromBip32(pub).toP2wshAddress();
|
||||
// case P2shAddressType.p2wpkhInP2sh:
|
||||
// return ECPublic.fromBip32(pub).toP2wpkhInP2sh();
|
||||
// case SegwitAddresType.p2wpkh:
|
||||
// return ECPublic.fromBip32(pub).toP2wpkhAddress();
|
||||
// default:
|
||||
// throw ArgumentError('Invalid address type');
|
||||
// }
|
||||
// }
|
||||
|
||||
switch (addressType) {
|
||||
case P2pkhAddressType.p2pkh:
|
||||
|
@ -191,10 +246,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
1;
|
||||
|
||||
final address = BitcoinSilentPaymentAddressRecord(
|
||||
silentPaymentWallet.toLabeledSilentPaymentAddress(currentSPLabelIndex).toString(),
|
||||
silentPaymentWallet!.toLabeledSilentPaymentAddress(currentSPLabelIndex).toString(),
|
||||
labelIndex: currentSPLabelIndex,
|
||||
name: label,
|
||||
labelHex: BytesUtils.toHexString(silentPaymentWallet.generateLabel(currentSPLabelIndex)),
|
||||
labelHex: BytesUtils.toHexString(silentPaymentWallet!.generateLabel(currentSPLabelIndex)),
|
||||
addressType: SilentPaymentsAddresType.p2sp,
|
||||
);
|
||||
|
||||
|
@ -270,6 +325,15 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
updateAddressesByMatch();
|
||||
}
|
||||
|
||||
@action
|
||||
void addReceivedSPAddresses(Iterable<BitcoinReceivedSPAddressRecord> addresses) {
|
||||
final addressesSet = this.receivedSPAddresses.toSet();
|
||||
addressesSet.addAll(addresses);
|
||||
this.receivedSPAddresses.clear();
|
||||
this.receivedSPAddresses.addAll(addressesSet);
|
||||
updateAddressesByMatch();
|
||||
}
|
||||
|
||||
@action
|
||||
void deleteSilentPaymentAddress(String address) {
|
||||
final addressRecord = silentPaymentAddresses.firstWhere((addressRecord) =>
|
||||
|
|
|
@ -15,13 +15,13 @@ class ElectrumTransactionBundle {
|
|||
required this.ins,
|
||||
required this.confirmations,
|
||||
this.time,
|
||||
this.dateValidated,
|
||||
this.isDateValidated,
|
||||
});
|
||||
|
||||
final BtcTransaction originalTransaction;
|
||||
final List<BtcTransaction> ins;
|
||||
final int? time;
|
||||
final bool? dateValidated;
|
||||
final bool? isDateValidated;
|
||||
final int confirmations;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
|
@ -39,7 +39,7 @@ class ElectrumTransactionBundle {
|
|||
ins: (data['ins'] as List<Object>).map((e) => BtcTransaction.fromRaw(e as String)).toList(),
|
||||
confirmations: data['confirmations'] as int,
|
||||
time: data['time'] as int?,
|
||||
dateValidated: data['dateValidated'] as bool?,
|
||||
isDateValidated: data['isDateValidated'] as bool?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
bool isReplaced = false,
|
||||
required DateTime date,
|
||||
required int? time,
|
||||
bool? dateValidated,
|
||||
bool? isDateValidated,
|
||||
required int confirmations,
|
||||
String? to,
|
||||
this.unspents,
|
||||
|
@ -81,7 +81,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
this.isPending = isPending;
|
||||
this.isReplaced = isReplaced;
|
||||
this.confirmations = confirmations;
|
||||
this.dateValidated = dateValidated;
|
||||
this.isDateValidated = isDateValidated;
|
||||
this.to = to;
|
||||
this.additionalInfo = additionalInfo ?? {};
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
date: date,
|
||||
confirmations: bundle.confirmations,
|
||||
time: bundle.time,
|
||||
dateValidated: bundle.dateValidated,
|
||||
isDateValidated: bundle.isDateValidated,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
.toList(),
|
||||
isReceivedSilentPayment: data['isReceivedSilentPayment'] as bool? ?? false,
|
||||
time: data['time'] as int?,
|
||||
dateValidated: data['dateValidated'] as bool?,
|
||||
isDateValidated: data['isDateValidated'] as bool?,
|
||||
additionalInfo: data['additionalInfo'] as Map<String, dynamic>?,
|
||||
);
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
m['outputAddresses'] = outputAddresses;
|
||||
m['isReceivedSilentPayment'] = isReceivedSilentPayment;
|
||||
m['additionalInfo'] = additionalInfo;
|
||||
m['dateValidated'] = dateValidated;
|
||||
m['isDateValidated'] = isDateValidated;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ abstract class ElectrumWalletBase
|
|||
CryptoCurrency? currency,
|
||||
this.alwaysScan,
|
||||
required this.mempoolAPIEnabled,
|
||||
List<BitcoinUnspent> initialUnspentCoins = const [],
|
||||
}) : hdWallets = hdWallets ??
|
||||
{
|
||||
CWBitcoinDerivationType.bip39: getAccountHDWallet(
|
||||
|
@ -84,8 +85,7 @@ abstract class ElectrumWalletBase
|
|||
syncStatus = NotConnectedSyncStatus(),
|
||||
_password = password,
|
||||
isEnabledAutoGenerateSubaddress = true,
|
||||
// TODO: inital unspent coins
|
||||
unspentCoins = BitcoinUnspentCoins(),
|
||||
unspentCoins = BitcoinUnspentCoins.of(initialUnspentCoins),
|
||||
scripthashesListening = [],
|
||||
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of(currency != null
|
||||
? {
|
||||
|
@ -419,6 +419,7 @@ abstract class ElectrumWalletBase
|
|||
workerSendPort!.send(
|
||||
ElectrumWorkerConnectionRequest(
|
||||
uri: node.uri,
|
||||
useSSL: node.useSSL ?? false,
|
||||
network: network,
|
||||
).toJson(),
|
||||
);
|
||||
|
@ -1036,6 +1037,7 @@ abstract class ElectrumWalletBase
|
|||
'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index,
|
||||
'derivationPath': walletInfo.derivationInfo?.derivationPath,
|
||||
'alwaysScan': alwaysScan,
|
||||
'unspents': unspentCoins.map((e) => e.toJson()).toList(),
|
||||
});
|
||||
|
||||
int feeAmountForPriority(TransactionPriority priority, int inputsCount, int outputsCount,
|
||||
|
@ -1214,7 +1216,6 @@ abstract class ElectrumWalletBase
|
|||
}));
|
||||
}));
|
||||
|
||||
unspentCoins.clear();
|
||||
unspentCoins.addAll(updatedUnspentCoins);
|
||||
unspentCoins.forEach(updateCoin);
|
||||
|
||||
|
@ -1918,9 +1919,15 @@ class TxCreateUtxoDetails {
|
|||
});
|
||||
}
|
||||
|
||||
class BitcoinUnspentCoins extends ObservableList<BitcoinUnspent> {
|
||||
class BitcoinUnspentCoins extends ObservableSet<BitcoinUnspent> {
|
||||
BitcoinUnspentCoins() : super();
|
||||
|
||||
static BitcoinUnspentCoins of(Iterable<BitcoinUnspent> unspentCoins) {
|
||||
final coins = BitcoinUnspentCoins();
|
||||
coins.addAll(unspentCoins);
|
||||
return coins;
|
||||
}
|
||||
|
||||
List<UnspentCoinsInfo> forInfo(Iterable<UnspentCoinsInfo> unspentCoinsInfo) {
|
||||
return unspentCoinsInfo.where((element) {
|
||||
final info = this.firstWhereOrNull(
|
||||
|
|
|
@ -11,27 +11,15 @@ import 'package:mobx/mobx.dart';
|
|||
|
||||
part 'electrum_wallet_addresses.g.dart';
|
||||
|
||||
enum CWBitcoinDerivationType { old, electrum, bip39, mweb }
|
||||
enum CWBitcoinDerivationType { old_electrum, electrum, old_bip39, bip39, mweb }
|
||||
|
||||
const OLD_DERIVATION_TYPES = [
|
||||
CWBitcoinDerivationType.old_electrum,
|
||||
CWBitcoinDerivationType.old_bip39
|
||||
];
|
||||
|
||||
class ElectrumWalletAddresses = ElectrumWalletAddressesBase with _$ElectrumWalletAddresses;
|
||||
|
||||
const List<BitcoinAddressType> BITCOIN_ADDRESS_TYPES = [
|
||||
SegwitAddresType.p2wpkh,
|
||||
P2pkhAddressType.p2pkh,
|
||||
SegwitAddresType.p2tr,
|
||||
SegwitAddresType.p2wsh,
|
||||
P2shAddressType.p2wpkhInP2sh,
|
||||
];
|
||||
|
||||
const List<BitcoinAddressType> LITECOIN_ADDRESS_TYPES = [
|
||||
SegwitAddresType.p2wpkh,
|
||||
SegwitAddresType.mweb,
|
||||
];
|
||||
|
||||
const List<BitcoinAddressType> BITCOIN_CASH_ADDRESS_TYPES = [
|
||||
P2pkhAddressType.p2pkh,
|
||||
];
|
||||
|
||||
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||
ElectrumWalletAddressesBase(
|
||||
WalletInfo walletInfo, {
|
||||
|
@ -435,6 +423,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
.length;
|
||||
|
||||
final newAddresses = <BitcoinAddressRecord>[];
|
||||
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final address = BitcoinAddressRecord(
|
||||
await getAddressAsync(
|
||||
|
@ -446,7 +435,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
),
|
||||
index: i,
|
||||
isChange: isChange,
|
||||
isHidden: derivationType == CWBitcoinDerivationType.old,
|
||||
isHidden: OLD_DERIVATION_TYPES.contains(derivationType),
|
||||
addressType: addressType,
|
||||
network: network,
|
||||
derivationInfo: derivationInfo,
|
||||
|
@ -466,27 +455,38 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}
|
||||
|
||||
for (final derivationType in hdWallets.keys) {
|
||||
if (derivationType == CWBitcoinDerivationType.old && addressType == SegwitAddresType.p2wpkh) {
|
||||
// p2wpkh has always had the right derivations, skip if creating old derivations
|
||||
if (OLD_DERIVATION_TYPES.contains(derivationType) && addressType == SegwitAddresType.p2wpkh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final derivationInfo = BitcoinAddressUtils.getDerivationFromType(
|
||||
addressType,
|
||||
isElectrum: derivationType == CWBitcoinDerivationType.electrum,
|
||||
final isElectrum = derivationType == CWBitcoinDerivationType.electrum ||
|
||||
derivationType == CWBitcoinDerivationType.old_electrum;
|
||||
|
||||
final derivationInfos = walletInfo.derivations?.where(
|
||||
(element) => element.scriptType == addressType.toString(),
|
||||
);
|
||||
|
||||
await discoverNewAddresses(
|
||||
derivationType: derivationType,
|
||||
isChange: false,
|
||||
addressType: addressType,
|
||||
derivationInfo: derivationInfo,
|
||||
);
|
||||
await discoverNewAddresses(
|
||||
derivationType: derivationType,
|
||||
isChange: true,
|
||||
addressType: addressType,
|
||||
derivationInfo: derivationInfo,
|
||||
);
|
||||
for (final derivationInfo in derivationInfos ?? <DerivationInfo>[]) {
|
||||
final bitcoinDerivationInfo = BitcoinDerivationInfo(
|
||||
derivationType: isElectrum ? BitcoinDerivationType.electrum : BitcoinDerivationType.bip39,
|
||||
derivationPath: derivationInfo.derivationPath!,
|
||||
scriptType: addressType,
|
||||
);
|
||||
|
||||
await discoverNewAddresses(
|
||||
derivationType: derivationType,
|
||||
isChange: false,
|
||||
addressType: addressType,
|
||||
derivationInfo: bitcoinDerivationInfo,
|
||||
);
|
||||
await discoverNewAddresses(
|
||||
derivationType: derivationType,
|
||||
isChange: true,
|
||||
addressType: addressType,
|
||||
derivationInfo: bitcoinDerivationInfo,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:convert';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
|
@ -23,6 +24,7 @@ class ElectrumWalletSnapshot {
|
|||
required this.silentAddressIndex,
|
||||
required this.mwebAddresses,
|
||||
required this.alwaysScan,
|
||||
required this.unspentCoins,
|
||||
this.passphrase,
|
||||
this.derivationType,
|
||||
this.derivationPath,
|
||||
|
@ -32,6 +34,7 @@ class ElectrumWalletSnapshot {
|
|||
final String password;
|
||||
final WalletType type;
|
||||
final String? addressPageType;
|
||||
List<BitcoinUnspent> unspentCoins;
|
||||
|
||||
@deprecated
|
||||
String? mnemonic;
|
||||
|
@ -127,6 +130,12 @@ class ElectrumWalletSnapshot {
|
|||
silentAddressIndex: silentAddressIndex,
|
||||
mwebAddresses: mwebAddresses,
|
||||
alwaysScan: alwaysScan,
|
||||
unspentCoins: (data['unspent_coins'] as List)
|
||||
.map((e) => BitcoinUnspent.fromJSON(
|
||||
null,
|
||||
e as Map<String, dynamic>,
|
||||
))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,27 +123,41 @@ class ElectrumWorker {
|
|||
_network = request.network;
|
||||
|
||||
_electrumClient = await ElectrumApiProvider.connect(
|
||||
ElectrumTCPService.connect(
|
||||
request.uri,
|
||||
onConnectionStatusChange: (status) {
|
||||
_sendResponse(ElectrumWorkerConnectionResponse(status: status, id: request.id));
|
||||
},
|
||||
defaultRequestTimeOut: const Duration(seconds: 5),
|
||||
connectionTimeOut: const Duration(seconds: 5),
|
||||
),
|
||||
request.useSSL
|
||||
? ElectrumSSLService.connect(
|
||||
request.uri,
|
||||
onConnectionStatusChange: (status) {
|
||||
_sendResponse(ElectrumWorkerConnectionResponse(status: status, id: request.id));
|
||||
},
|
||||
defaultRequestTimeOut: const Duration(seconds: 5),
|
||||
connectionTimeOut: const Duration(seconds: 5),
|
||||
)
|
||||
: ElectrumTCPService.connect(
|
||||
request.uri,
|
||||
onConnectionStatusChange: (status) {
|
||||
_sendResponse(ElectrumWorkerConnectionResponse(status: status, id: request.id));
|
||||
},
|
||||
defaultRequestTimeOut: const Duration(seconds: 5),
|
||||
connectionTimeOut: const Duration(seconds: 5),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleHeadersSubscribe(ElectrumWorkerHeadersSubscribeRequest request) async {
|
||||
final listener = _electrumClient!.subscribe(ElectrumHeaderSubscribe());
|
||||
if (listener == null) {
|
||||
final req = ElectrumHeaderSubscribe();
|
||||
|
||||
final stream = _electrumClient!.subscribe(req);
|
||||
if (stream == null) {
|
||||
_sendError(ElectrumWorkerHeadersSubscribeError(error: 'Failed to subscribe'));
|
||||
return;
|
||||
}
|
||||
|
||||
listener((event) {
|
||||
stream.listen((event) {
|
||||
_sendResponse(
|
||||
ElectrumWorkerHeadersSubscribeResponse(result: event, id: request.id),
|
||||
ElectrumWorkerHeadersSubscribeResponse(
|
||||
result: req.onResponse(event),
|
||||
id: request.id,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -155,22 +169,22 @@ class ElectrumWorker {
|
|||
final address = entry.key;
|
||||
final scripthash = entry.value;
|
||||
|
||||
final listener = await _electrumClient!.subscribe(
|
||||
ElectrumScriptHashSubscribe(scriptHash: scripthash),
|
||||
);
|
||||
final req = ElectrumScriptHashSubscribe(scriptHash: scripthash);
|
||||
|
||||
if (listener == null) {
|
||||
final stream = await _electrumClient!.subscribe(req);
|
||||
|
||||
if (stream == null) {
|
||||
_sendError(ElectrumWorkerScripthashesSubscribeError(error: 'Failed to subscribe'));
|
||||
return;
|
||||
}
|
||||
|
||||
// https://electrumx.readthedocs.io/en/latest/protocol-basics.html#status
|
||||
// The status of the script hash is the hash of the tx history, or null if the string is empty because there are no transactions
|
||||
listener((status) async {
|
||||
stream.listen((status) async {
|
||||
print("status: $status");
|
||||
|
||||
_sendResponse(ElectrumWorkerScripthashesSubscribeResponse(
|
||||
result: {address: status},
|
||||
result: {address: req.onResponse(status)},
|
||||
id: request.id,
|
||||
));
|
||||
});
|
||||
|
@ -210,7 +224,7 @@ class ElectrumWorker {
|
|||
|
||||
// date is validated when the API responds with the same date at least twice
|
||||
// since sometimes the mempool api returns the wrong date at first, and we update
|
||||
if (tx?.dateValidated != true) {
|
||||
if (tx?.isDateValidated != true) {
|
||||
tx = ElectrumTransactionInfo.fromElectrumBundle(
|
||||
await _getTransactionExpanded(
|
||||
hash: txid,
|
||||
|
@ -358,7 +372,7 @@ class ElectrumWorker {
|
|||
}) async {
|
||||
int? time;
|
||||
int? height;
|
||||
bool? dateValidated;
|
||||
bool? isDateValidated;
|
||||
|
||||
final transactionHex = await _electrumClient!.request(
|
||||
ElectrumGetTransactionHex(transactionHash: hash),
|
||||
|
@ -397,7 +411,7 @@ class ElectrumWorker {
|
|||
|
||||
if (date != null) {
|
||||
final newDate = DateTime.fromMillisecondsSinceEpoch(time * 1000);
|
||||
dateValidated = newDate == date;
|
||||
isDateValidated = newDate == date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +444,7 @@ class ElectrumWorker {
|
|||
ins: ins,
|
||||
time: time,
|
||||
confirmations: confirmations ?? 0,
|
||||
dateValidated: dateValidated,
|
||||
isDateValidated: isDateValidated,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -498,12 +512,16 @@ class ElectrumWorker {
|
|||
return amountLeft;
|
||||
}
|
||||
|
||||
final receiver = Receiver(
|
||||
scanData.silentAddress.b_scan.toHex(),
|
||||
scanData.silentAddress.B_spend.toHex(),
|
||||
scanData.network == BitcoinNetwork.testnet,
|
||||
scanData.labelIndexes,
|
||||
scanData.labelIndexes.length,
|
||||
final receivers = scanData.silentPaymentsWallets.map(
|
||||
(wallet) {
|
||||
return Receiver(
|
||||
wallet.b_scan.toHex(),
|
||||
wallet.B_spend.toHex(),
|
||||
scanData.network == BitcoinNetwork.testnet,
|
||||
scanData.labelIndexes,
|
||||
scanData.labelIndexes.length,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// Initial status UI update, send how many blocks in total to scan
|
||||
|
@ -515,24 +533,38 @@ class ElectrumWorker {
|
|||
),
|
||||
));
|
||||
|
||||
final listener = await _electrumClient!.subscribe(
|
||||
ElectrumTweaksSubscribe(height: syncHeight, count: initialCount),
|
||||
final req = ElectrumTweaksSubscribe(
|
||||
height: syncHeight,
|
||||
count: initialCount,
|
||||
historicalMode: false,
|
||||
);
|
||||
|
||||
Future<void> listenFn(ElectrumTweaksSubscribeResponse response) async {
|
||||
final stream = await _electrumClient!.subscribe(req);
|
||||
|
||||
Future<void> listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) async {
|
||||
final response = req.onResponse(event);
|
||||
|
||||
// success or error msg
|
||||
final noData = response.message != null;
|
||||
|
||||
if (noData) {
|
||||
if (scanData.isSingleScan) {
|
||||
return;
|
||||
}
|
||||
|
||||
// re-subscribe to continue receiving messages, starting from the next unscanned height
|
||||
final nextHeight = syncHeight + 1;
|
||||
final nextCount = getCountPerRequest(nextHeight);
|
||||
|
||||
if (nextCount > 0) {
|
||||
final nextListener = await _electrumClient!.subscribe(
|
||||
ElectrumTweaksSubscribe(height: syncHeight, count: initialCount),
|
||||
final nextStream = await _electrumClient!.subscribe(
|
||||
ElectrumTweaksSubscribe(
|
||||
height: syncHeight,
|
||||
count: initialCount,
|
||||
historicalMode: false,
|
||||
),
|
||||
);
|
||||
nextListener?.call(listenFn);
|
||||
nextStream?.listen((event) => listenFn(event, req));
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -558,7 +590,18 @@ class ElectrumWorker {
|
|||
|
||||
try {
|
||||
// scanOutputs called from rust here
|
||||
final addToWallet = scanOutputs(outputPubkeys.keys.toList(), tweak, receiver);
|
||||
final addToWallet = {};
|
||||
|
||||
receivers.forEach((receiver) {
|
||||
final scanResult = scanOutputs(outputPubkeys.keys.toList(), tweak, receiver);
|
||||
|
||||
addToWallet.addAll(scanResult);
|
||||
});
|
||||
// final addToWallet = scanOutputs(
|
||||
// outputPubkeys.keys.toList(),
|
||||
// tweak,
|
||||
// receivers.last,
|
||||
// );
|
||||
|
||||
if (addToWallet.isEmpty) {
|
||||
// no results tx, continue to next tx
|
||||
|
@ -601,7 +644,7 @@ class ElectrumWorker {
|
|||
receivingOutputAddress,
|
||||
labelIndex: 1, // TODO: get actual index/label
|
||||
isUsed: true,
|
||||
spendKey: scanData.silentAddress.b_spend.tweakAdd(
|
||||
spendKey: scanData.silentPaymentsWallets.first.b_spend.tweakAdd(
|
||||
BigintUtils.fromBytes(BytesUtils.fromHexString(t_k)),
|
||||
),
|
||||
txCount: 1,
|
||||
|
@ -618,6 +661,8 @@ class ElectrumWorker {
|
|||
_sendResponse(ElectrumWorkerTweaksSubscribeResponse(
|
||||
result: TweaksSyncResponse(transactions: {txInfo.id: txInfo}),
|
||||
));
|
||||
|
||||
return;
|
||||
} catch (e, stacktrace) {
|
||||
print(stacktrace);
|
||||
print(e.toString());
|
||||
|
@ -631,23 +676,23 @@ class ElectrumWorker {
|
|||
syncHeight = tweakHeight;
|
||||
|
||||
if (tweakHeight >= scanData.chainTip || scanData.isSingleScan) {
|
||||
if (tweakHeight >= scanData.chainTip)
|
||||
_sendResponse(ElectrumWorkerTweaksSubscribeResponse(
|
||||
_sendResponse(
|
||||
ElectrumWorkerTweaksSubscribeResponse(
|
||||
result: TweaksSyncResponse(
|
||||
height: syncHeight,
|
||||
syncStatus: SyncedTipSyncStatus(scanData.chainTip),
|
||||
syncStatus: scanData.isSingleScan
|
||||
? SyncedSyncStatus()
|
||||
: SyncedTipSyncStatus(scanData.chainTip),
|
||||
),
|
||||
));
|
||||
),
|
||||
);
|
||||
|
||||
if (scanData.isSingleScan) {
|
||||
_sendResponse(ElectrumWorkerTweaksSubscribeResponse(
|
||||
result: TweaksSyncResponse(height: syncHeight, syncStatus: SyncedSyncStatus()),
|
||||
));
|
||||
}
|
||||
stream?.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
listener?.call(listenFn);
|
||||
stream?.listen((event) => listenFn(event, req));
|
||||
}
|
||||
|
||||
Future<void> _handleGetVersion(ElectrumWorkerGetVersionRequest request) async {
|
||||
|
|
|
@ -4,10 +4,12 @@ class ElectrumWorkerConnectionRequest implements ElectrumWorkerRequest {
|
|||
ElectrumWorkerConnectionRequest({
|
||||
required this.uri,
|
||||
required this.network,
|
||||
required this.useSSL,
|
||||
this.id,
|
||||
});
|
||||
|
||||
final Uri uri;
|
||||
final bool useSSL;
|
||||
final BasedUtxoNetwork network;
|
||||
final int? id;
|
||||
|
||||
|
@ -21,6 +23,7 @@ class ElectrumWorkerConnectionRequest implements ElectrumWorkerRequest {
|
|||
network: BasedUtxoNetwork.values.firstWhere(
|
||||
(e) => e.toString() == json['network'] as String,
|
||||
),
|
||||
useSSL: json['useSSL'] as bool,
|
||||
id: json['id'] as int?,
|
||||
);
|
||||
}
|
||||
|
@ -31,6 +34,7 @@ class ElectrumWorkerConnectionRequest implements ElectrumWorkerRequest {
|
|||
'method': method,
|
||||
'uri': uri.toString(),
|
||||
'network': network.toString(),
|
||||
'useSSL': useSSL,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
part of 'methods.dart';
|
||||
|
||||
class ScanData {
|
||||
final SilentPaymentOwner silentAddress;
|
||||
final List<SilentPaymentOwner> silentPaymentsWallets;
|
||||
final int height;
|
||||
final BasedUtxoNetwork network;
|
||||
final int chainTip;
|
||||
|
@ -11,7 +11,7 @@ class ScanData {
|
|||
final bool isSingleScan;
|
||||
|
||||
ScanData({
|
||||
required this.silentAddress,
|
||||
required this.silentPaymentsWallets,
|
||||
required this.height,
|
||||
required this.network,
|
||||
required this.chainTip,
|
||||
|
@ -23,7 +23,7 @@ class ScanData {
|
|||
|
||||
factory ScanData.fromHeight(ScanData scanData, int newHeight) {
|
||||
return ScanData(
|
||||
silentAddress: scanData.silentAddress,
|
||||
silentPaymentsWallets: scanData.silentPaymentsWallets,
|
||||
height: newHeight,
|
||||
network: scanData.network,
|
||||
chainTip: scanData.chainTip,
|
||||
|
@ -36,7 +36,7 @@ class ScanData {
|
|||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'silentAddress': silentAddress.toJson(),
|
||||
'silentAddress': silentPaymentsWallets.map((e) => e.toJson()).toList(),
|
||||
'height': height,
|
||||
'network': network.value,
|
||||
'chainTip': chainTip,
|
||||
|
@ -49,7 +49,9 @@ class ScanData {
|
|||
|
||||
static ScanData fromJson(Map<String, dynamic> json) {
|
||||
return ScanData(
|
||||
silentAddress: SilentPaymentOwner.fromJson(json['silentAddress'] as Map<String, dynamic>),
|
||||
silentPaymentsWallets: (json['silentAddress'] as List)
|
||||
.map((e) => SilentPaymentOwner.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
height: json['height'] as int,
|
||||
network: BasedUtxoNetwork.fromName(json['network'] as String),
|
||||
chainTip: json['chainTip'] as int,
|
||||
|
@ -123,11 +125,9 @@ class TweaksSyncResponse {
|
|||
? null
|
||||
: (json['transactions'] as Map<String, dynamic>).map(
|
||||
(key, value) => MapEntry(
|
||||
key,
|
||||
ElectrumTransactionInfo.fromJson(
|
||||
value as Map<String, dynamic>,
|
||||
WalletType.bitcoin,
|
||||
)),
|
||||
key,
|
||||
ElectrumTransactionInfo.fromJson(value as Map<String, dynamic>, WalletType.bitcoin),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ Map<String, dynamic> syncStatusToJson(SyncStatus? status) {
|
|||
if (status == null) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
'progress': status.progress(),
|
||||
'type': status.runtimeType.toString(),
|
||||
|
@ -127,6 +128,8 @@ SyncStatus syncStatusFromJson(Map<String, dynamic> json) {
|
|||
return SyncingSyncStatus(data!['blocksLeft'] as int, data['ptc'] as double);
|
||||
case 'SyncedTipSyncStatus':
|
||||
return SyncedTipSyncStatus(data!['tip'] as int);
|
||||
case 'SyncedSyncStatus':
|
||||
return SyncedSyncStatus();
|
||||
case 'FailedSyncStatus':
|
||||
return FailedSyncStatus(error: data!['error'] as String?);
|
||||
case 'SynchronizingSyncStatus':
|
||||
|
|
|
@ -9,7 +9,7 @@ abstract class TransactionInfo extends Object with Keyable {
|
|||
late TransactionDirection direction;
|
||||
late bool isPending;
|
||||
late DateTime date;
|
||||
bool? dateValidated;
|
||||
bool? isDateValidated;
|
||||
int? height;
|
||||
late int confirmations;
|
||||
String amountFormatted();
|
||||
|
|
|
@ -19,6 +19,8 @@ enum DerivationType {
|
|||
bip39,
|
||||
@HiveField(4)
|
||||
electrum,
|
||||
@HiveField(5)
|
||||
old,
|
||||
}
|
||||
|
||||
@HiveType(typeId: HARDWARE_WALLET_TYPE_TYPE_ID)
|
||||
|
|
|
@ -136,13 +136,24 @@ class CWBitcoin extends Bitcoin {
|
|||
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
|
||||
final electrumWallet = wallet as ElectrumWallet;
|
||||
return electrumWallet.walletAddresses.addressesByReceiveType
|
||||
.map((BaseBitcoinAddressRecord addr) => ElectrumSubAddress(
|
||||
.map(
|
||||
(addr) => ElectrumSubAddress(
|
||||
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(),
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isChange))
|
||||
isChange: addr.isChange,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
@ -336,12 +347,38 @@ class CWBitcoin extends Bitcoin {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<List<BitcoinDerivationInfo>> getDerivationsFromMnemonic({
|
||||
List<DerivationInfo> getOldDerivationInfos(List<DerivationInfo> list) {
|
||||
final oldList = <DerivationInfo>[];
|
||||
oldList.addAll(list);
|
||||
|
||||
for (var derivationInfo in list) {
|
||||
final isElectrum = derivationInfo.derivationType == DerivationType.electrum;
|
||||
|
||||
oldList.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.old,
|
||||
derivationPath: isElectrum
|
||||
? derivationInfo.derivationPath
|
||||
: BitcoinAddressUtils.getDerivationFromType(
|
||||
SegwitAddresType.p2wpkh,
|
||||
).derivationPath.toString(),
|
||||
scriptType: derivationInfo.scriptType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
oldList.addAll(bitcoin!.getOldSPDerivationInfos());
|
||||
|
||||
return oldList;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<DerivationInfo>> getDerivationInfosFromMnemonic({
|
||||
required String mnemonic,
|
||||
required Node node,
|
||||
String? passphrase,
|
||||
}) async {
|
||||
List<BitcoinDerivationInfo> list = [];
|
||||
final list = <DerivationInfo>[];
|
||||
|
||||
late BasedUtxoNetwork network;
|
||||
switch (node.type) {
|
||||
|
@ -371,7 +408,15 @@ class CWBitcoin extends Bitcoin {
|
|||
}
|
||||
|
||||
if (electrumSeedBytes != null) {
|
||||
list.add(BitcoinDerivationInfos.ELECTRUM);
|
||||
for (final addressType in BITCOIN_ADDRESS_TYPES) {
|
||||
list.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.electrum,
|
||||
derivationPath: "m/0'",
|
||||
scriptType: addressType.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var bip39SeedBytes;
|
||||
|
@ -380,7 +425,17 @@ class CWBitcoin extends Bitcoin {
|
|||
} catch (_) {}
|
||||
|
||||
if (bip39SeedBytes != null) {
|
||||
list.add(BitcoinDerivationInfos.BIP84);
|
||||
for (final addressType in BITCOIN_ADDRESS_TYPES) {
|
||||
list.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: BitcoinAddressUtils.getDerivationFromType(
|
||||
addressType,
|
||||
).derivationPath.toString(),
|
||||
scriptType: addressType.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
|
@ -490,6 +545,22 @@ class CWBitcoin extends Bitcoin {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<DerivationInfo> getOldSPDerivationInfos() {
|
||||
return [
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/352'/1'/0'/1'/0",
|
||||
description: "Old SP Scan",
|
||||
),
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/352'/1'/0'/0'/0",
|
||||
description: "Old SP Spend",
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
List<ElectrumSubAddress> getSilentPaymentAddresses(Object wallet) {
|
||||
final walletAddresses = (wallet as BitcoinWallet).walletAddresses as BitcoinWalletAddresses;
|
||||
|
@ -498,6 +569,9 @@ class CWBitcoin extends Bitcoin {
|
|||
id: addr.index,
|
||||
name: addr.name,
|
||||
address: addr.address,
|
||||
derivationPath: Bip32PathParser.parse(addr.derivationPath)
|
||||
.addElem(Bip32KeyIndex(addr.index))
|
||||
.toString(),
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isChange,
|
||||
|
@ -508,14 +582,16 @@ class CWBitcoin extends Bitcoin {
|
|||
@override
|
||||
List<ElectrumSubAddress> getSilentPaymentReceivedAddresses(Object wallet) {
|
||||
final walletAddresses = (wallet as BitcoinWallet).walletAddresses as BitcoinWalletAddresses;
|
||||
return walletAddresses.silentPaymentAddresses
|
||||
return walletAddresses.receivedSPAddresses
|
||||
.map((addr) => ElectrumSubAddress(
|
||||
id: addr.index,
|
||||
name: addr.name,
|
||||
address: addr.address,
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isChange))
|
||||
id: addr.index,
|
||||
name: addr.name,
|
||||
address: addr.address,
|
||||
derivationPath: "",
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isChange,
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,23 +7,25 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
|
||||
class AddressCell extends StatelessWidget {
|
||||
AddressCell(
|
||||
{required this.address,
|
||||
required this.name,
|
||||
required this.isCurrent,
|
||||
required this.isPrimary,
|
||||
required this.backgroundColor,
|
||||
required this.textColor,
|
||||
this.onTap,
|
||||
this.onEdit,
|
||||
this.onHide,
|
||||
this.isHidden = false,
|
||||
this.onDelete,
|
||||
this.txCount,
|
||||
this.balance,
|
||||
this.isChange = false,
|
||||
this.hasBalance = false,
|
||||
this.hasReceived = false});
|
||||
AddressCell({
|
||||
required this.address,
|
||||
required this.derivationPath,
|
||||
required this.name,
|
||||
required this.isCurrent,
|
||||
required this.isPrimary,
|
||||
required this.backgroundColor,
|
||||
required this.textColor,
|
||||
this.onTap,
|
||||
this.onEdit,
|
||||
this.onHide,
|
||||
this.isHidden = false,
|
||||
this.onDelete,
|
||||
this.txCount,
|
||||
this.balance,
|
||||
this.isChange = false,
|
||||
this.hasBalance = false,
|
||||
this.hasReceived = false,
|
||||
});
|
||||
|
||||
factory AddressCell.fromItem(
|
||||
WalletAddressListItem item, {
|
||||
|
@ -39,24 +41,27 @@ class AddressCell extends StatelessWidget {
|
|||
Function()? onDelete,
|
||||
}) =>
|
||||
AddressCell(
|
||||
address: item.address,
|
||||
name: item.name ?? '',
|
||||
isCurrent: isCurrent,
|
||||
isPrimary: item.isPrimary,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
onTap: onTap,
|
||||
onEdit: onEdit,
|
||||
onHide: onHide,
|
||||
isHidden: isHidden,
|
||||
onDelete: onDelete,
|
||||
txCount: item.txCount,
|
||||
balance: item.balance,
|
||||
isChange: item.isChange,
|
||||
hasBalance: hasBalance,
|
||||
hasReceived: hasReceived,);
|
||||
address: item.address,
|
||||
derivationPath: item.derivationPath,
|
||||
name: item.name ?? '',
|
||||
isCurrent: isCurrent,
|
||||
isPrimary: item.isPrimary,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
onTap: onTap,
|
||||
onEdit: onEdit,
|
||||
onHide: onHide,
|
||||
isHidden: isHidden,
|
||||
onDelete: onDelete,
|
||||
txCount: item.txCount,
|
||||
balance: item.balance,
|
||||
isChange: item.isChange,
|
||||
hasBalance: hasBalance,
|
||||
hasReceived: hasReceived,
|
||||
);
|
||||
|
||||
final String address;
|
||||
final String derivationPath;
|
||||
final String name;
|
||||
final bool isCurrent;
|
||||
final bool isPrimary;
|
||||
|
@ -102,7 +107,9 @@ class AddressCell extends StatelessWidget {
|
|||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: name.isNotEmpty ? MainAxisAlignment.spaceBetween : MainAxisAlignment.center,
|
||||
mainAxisAlignment: name.isNotEmpty
|
||||
? MainAxisAlignment.spaceBetween
|
||||
: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Row(
|
||||
|
@ -151,6 +158,21 @@ class AddressCell extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (derivationPath.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Flexible(
|
||||
child: AutoSizeText(
|
||||
derivationPath,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: isChange ? 10 : 14,
|
||||
color: textColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasBalance || hasReceived)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
|
|
|
@ -4,6 +4,7 @@ class WalletAddressListItem extends ListItem {
|
|||
WalletAddressListItem({
|
||||
required this.address,
|
||||
required this.isPrimary,
|
||||
this.derivationPath = "",
|
||||
this.id,
|
||||
this.name,
|
||||
this.txCount,
|
||||
|
@ -18,6 +19,7 @@ class WalletAddressListItem extends ListItem {
|
|||
final int? id;
|
||||
final bool isPrimary;
|
||||
final String address;
|
||||
final String derivationPath;
|
||||
final String? name;
|
||||
final int? txCount;
|
||||
final String? balance;
|
||||
|
|
|
@ -31,8 +31,7 @@ import 'package:mobx/mobx.dart';
|
|||
|
||||
part 'wallet_address_list_view_model.g.dart';
|
||||
|
||||
class WalletAddressListViewModel = WalletAddressListViewModelBase
|
||||
with _$WalletAddressListViewModel;
|
||||
class WalletAddressListViewModel = WalletAddressListViewModelBase with _$WalletAddressListViewModel;
|
||||
|
||||
abstract class PaymentURI {
|
||||
PaymentURI({required this.amount, required this.address});
|
||||
|
@ -205,8 +204,7 @@ class WowneroURI extends PaymentURI {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class WalletAddressListViewModelBase
|
||||
extends WalletChangeListenerViewModel with Store {
|
||||
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
|
||||
WalletAddressListViewModelBase({
|
||||
required AppStore appStore,
|
||||
required this.yatStore,
|
||||
|
@ -227,8 +225,7 @@ abstract class WalletAddressListViewModelBase
|
|||
_init();
|
||||
|
||||
selectedCurrency = walletTypeToCryptoCurrency(wallet.type);
|
||||
hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven]
|
||||
.contains(wallet.type);
|
||||
hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven].contains(wallet.type);
|
||||
}
|
||||
|
||||
static const String _cryptoNumberPattern = '0.00000000';
|
||||
|
@ -241,8 +238,7 @@ abstract class WalletAddressListViewModelBase
|
|||
double? _fiatRate;
|
||||
String _rawAmount = '';
|
||||
|
||||
List<Currency> get currencies =>
|
||||
[walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];
|
||||
List<Currency> get currencies => [walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];
|
||||
|
||||
String get buttonTitle {
|
||||
if (isElectrumWallet) {
|
||||
|
@ -268,8 +264,8 @@ abstract class WalletAddressListViewModelBase
|
|||
WalletType get type => wallet.type;
|
||||
|
||||
@computed
|
||||
WalletAddressListItem get address => WalletAddressListItem(
|
||||
address: wallet.walletAddresses.address, isPrimary: false);
|
||||
WalletAddressListItem get address =>
|
||||
WalletAddressListItem(address: wallet.walletAddresses.address, isPrimary: false);
|
||||
|
||||
@computed
|
||||
PaymentURI get uri {
|
||||
|
@ -313,10 +309,8 @@ abstract class WalletAddressListViewModelBase
|
|||
final addressList = ObservableList<ListItem>();
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
final primaryAddress =
|
||||
monero!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems =
|
||||
monero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final primaryAddress = monero!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems = monero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final isPrimary = subaddress == primaryAddress;
|
||||
|
||||
return WalletAddressListItem(
|
||||
|
@ -332,10 +326,8 @@ abstract class WalletAddressListViewModelBase
|
|||
}
|
||||
|
||||
if (wallet.type == WalletType.wownero) {
|
||||
final primaryAddress =
|
||||
wownero!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems =
|
||||
wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final isPrimary = subaddress == primaryAddress;
|
||||
|
||||
return WalletAddressListItem(
|
||||
|
@ -348,10 +340,8 @@ abstract class WalletAddressListViewModelBase
|
|||
}
|
||||
|
||||
if (wallet.type == WalletType.haven) {
|
||||
final primaryAddress =
|
||||
haven!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems =
|
||||
haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final primaryAddress = haven!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems = haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final isPrimary = subaddress == primaryAddress;
|
||||
|
||||
return WalletAddressListItem(
|
||||
|
@ -365,14 +355,14 @@ abstract class WalletAddressListViewModelBase
|
|||
|
||||
if (isElectrumWallet) {
|
||||
if (bitcoin!.hasSelectedSilentPayments(wallet)) {
|
||||
final addressItems =
|
||||
bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
|
||||
final addressItems = bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
|
||||
final isPrimary = address.id == 0;
|
||||
|
||||
return WalletAddressListItem(
|
||||
id: address.id,
|
||||
isPrimary: isPrimary,
|
||||
name: address.name,
|
||||
derivationPath: address.derivationPath,
|
||||
address: address.address,
|
||||
txCount: address.txCount,
|
||||
balance: AmountConverter.amountIntToString(
|
||||
|
@ -390,6 +380,7 @@ abstract class WalletAddressListViewModelBase
|
|||
isPrimary: false,
|
||||
name: address.name,
|
||||
address: address.address,
|
||||
derivationPath: address.derivationPath,
|
||||
txCount: address.txCount,
|
||||
balance: AmountConverter.amountIntToString(
|
||||
walletTypeToCryptoCurrency(type), address.balance),
|
||||
|
@ -407,6 +398,7 @@ abstract class WalletAddressListViewModelBase
|
|||
isPrimary: isPrimary,
|
||||
name: subaddress.name,
|
||||
address: subaddress.address,
|
||||
derivationPath: subaddress.derivationPath,
|
||||
txCount: subaddress.txCount,
|
||||
balance: AmountConverter.amountIntToString(
|
||||
walletTypeToCryptoCurrency(type), subaddress.balance),
|
||||
|
@ -417,8 +409,7 @@ abstract class WalletAddressListViewModelBase
|
|||
if (wallet.type == WalletType.litecoin && addressItems.length >= 1000) {
|
||||
// find the index of the last item with a txCount > 0
|
||||
final addressItemsList = addressItems.toList();
|
||||
int index = addressItemsList
|
||||
.lastIndexWhere((item) => (item.txCount ?? 0) > 0);
|
||||
int index = addressItemsList.lastIndexWhere((item) => (item.txCount ?? 0) > 0);
|
||||
if (index == -1) {
|
||||
index = 0;
|
||||
}
|
||||
|
@ -432,22 +423,19 @@ abstract class WalletAddressListViewModelBase
|
|||
if (wallet.type == WalletType.ethereum) {
|
||||
final primaryAddress = ethereum!.getAddress(wallet);
|
||||
|
||||
addressList.add(WalletAddressListItem(
|
||||
isPrimary: true, name: null, address: primaryAddress));
|
||||
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.polygon) {
|
||||
final primaryAddress = polygon!.getAddress(wallet);
|
||||
|
||||
addressList.add(WalletAddressListItem(
|
||||
isPrimary: true, name: null, address: primaryAddress));
|
||||
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.solana) {
|
||||
final primaryAddress = solana!.getAddress(wallet);
|
||||
|
||||
addressList.add(WalletAddressListItem(
|
||||
isPrimary: true, name: null, address: primaryAddress));
|
||||
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.nano) {
|
||||
|
@ -461,21 +449,18 @@ abstract class WalletAddressListViewModelBase
|
|||
if (wallet.type == WalletType.tron) {
|
||||
final primaryAddress = tron!.getAddress(wallet);
|
||||
|
||||
addressList.add(WalletAddressListItem(
|
||||
isPrimary: true, name: null, address: primaryAddress));
|
||||
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||
}
|
||||
|
||||
for (var i = 0; i < addressList.length; i++) {
|
||||
if (!(addressList[i] is WalletAddressListItem)) continue;
|
||||
(addressList[i] as WalletAddressListItem).isHidden = wallet
|
||||
.walletAddresses.hiddenAddresses
|
||||
(addressList[i] as WalletAddressListItem).isHidden = wallet.walletAddresses.hiddenAddresses
|
||||
.contains((addressList[i] as WalletAddressListItem).address);
|
||||
}
|
||||
|
||||
for (var i = 0; i < addressList.length; i++) {
|
||||
if (!(addressList[i] is WalletAddressListItem)) continue;
|
||||
(addressList[i] as WalletAddressListItem).isManual = wallet
|
||||
.walletAddresses.manualAddresses
|
||||
(addressList[i] as WalletAddressListItem).isManual = wallet.walletAddresses.manualAddresses
|
||||
.contains((addressList[i] as WalletAddressListItem).address);
|
||||
}
|
||||
|
||||
|
@ -493,8 +478,7 @@ abstract class WalletAddressListViewModelBase
|
|||
|
||||
Future<void> toggleHideAddress(WalletAddressListItem item) async {
|
||||
if (item.isHidden) {
|
||||
wallet.walletAddresses.hiddenAddresses
|
||||
.removeWhere((element) => element == item.address);
|
||||
wallet.walletAddresses.hiddenAddresses.removeWhere((element) => element == item.address);
|
||||
} else {
|
||||
wallet.walletAddresses.hiddenAddresses.add(item.address);
|
||||
}
|
||||
|
@ -543,28 +527,22 @@ abstract class WalletAddressListViewModelBase
|
|||
].contains(wallet.type);
|
||||
|
||||
@computed
|
||||
bool get isElectrumWallet => [
|
||||
WalletType.bitcoin,
|
||||
WalletType.litecoin,
|
||||
WalletType.bitcoinCash
|
||||
].contains(wallet.type);
|
||||
bool get isElectrumWallet =>
|
||||
[WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type);
|
||||
|
||||
@computed
|
||||
bool get isBalanceAvailable => isElectrumWallet;
|
||||
|
||||
@computed
|
||||
bool get isReceivedAvailable =>
|
||||
[WalletType.monero, WalletType.wownero].contains(wallet.type);
|
||||
bool get isReceivedAvailable => [WalletType.monero, WalletType.wownero].contains(wallet.type);
|
||||
|
||||
@computed
|
||||
bool get isSilentPayments =>
|
||||
wallet.type == WalletType.bitcoin &&
|
||||
bitcoin!.hasSelectedSilentPayments(wallet);
|
||||
wallet.type == WalletType.bitcoin && bitcoin!.hasSelectedSilentPayments(wallet);
|
||||
|
||||
@computed
|
||||
bool get isAutoGenerateSubaddressEnabled =>
|
||||
_settingsStore.autoGenerateSubaddressStatus !=
|
||||
AutoGenerateSubaddressStatus.disabled &&
|
||||
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled &&
|
||||
!isSilentPayments;
|
||||
|
||||
@computed
|
||||
|
@ -647,8 +625,7 @@ abstract class WalletAddressListViewModelBase
|
|||
@action
|
||||
void _convertAmountToCrypto() {
|
||||
final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type);
|
||||
final fiatRate =
|
||||
_fiatRate ?? (fiatConversionStore.prices[cryptoCurrency] ?? 0.0);
|
||||
final fiatRate = _fiatRate ?? (fiatConversionStore.prices[cryptoCurrency] ?? 0.0);
|
||||
|
||||
if (fiatRate <= 0.0) {
|
||||
dev.log("Invalid Fiat Rate $fiatRate");
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
|
@ -193,7 +192,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
|
||||
Future<List<DerivationInfo>> getDerivationInfoFromQRCredentials(
|
||||
RestoredWallet restoreWallet) async {
|
||||
var list = <DerivationInfo>[];
|
||||
final list = <DerivationInfo>[];
|
||||
final walletType = restoreWallet.type;
|
||||
var appStore = getIt.get<AppStore>();
|
||||
var node = appStore.settingsStore.getCurrentNode(walletType);
|
||||
|
@ -201,37 +200,11 @@ abstract class WalletCreationVMBase with Store {
|
|||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
final bitcoinDerivations = await bitcoin!.getDerivationsFromMnemonic(
|
||||
return await bitcoin!.getDerivationInfosFromMnemonic(
|
||||
mnemonic: restoreWallet.mnemonicSeed!,
|
||||
node: node,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
|
||||
List<DerivationInfo> list = [];
|
||||
for (var derivation in bitcoinDerivations) {
|
||||
if (derivation.derivationType == DerivationType.electrum) {
|
||||
list.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.electrum,
|
||||
derivationPath: "m/0'",
|
||||
description: "Electrum",
|
||||
scriptType: "p2wpkh",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
list.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/0'/0'",
|
||||
description: "Standard BIP84 native segwit",
|
||||
scriptType: "p2wpkh",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
case WalletType.nano:
|
||||
return nanoUtil!.getDerivationsFromMnemonic(
|
||||
mnemonic: restoreWallet.mnemonicSeed!,
|
||||
|
|
|
@ -91,14 +91,17 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
final height = options['height'] as int? ?? 0;
|
||||
name = options['name'] as String;
|
||||
DerivationInfo? derivationInfo = options["derivationInfo"] as DerivationInfo?;
|
||||
List<DerivationInfo>? derivations = options["derivations"] as List<DerivationInfo>?;
|
||||
|
||||
if (mode == WalletRestoreMode.seed) {
|
||||
final seed = options['seed'] as String;
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroRestoreWalletFromSeedCredentials(
|
||||
name: name, height: height, mnemonic: seed, password: password);
|
||||
name: name,
|
||||
height: height,
|
||||
mnemonic: seed,
|
||||
password: password,
|
||||
);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||
|
@ -106,7 +109,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
mnemonic: seed,
|
||||
password: password,
|
||||
passphrase: passphrase,
|
||||
derivations: derivations,
|
||||
derivations: options["derivations"] as List<DerivationInfo>?,
|
||||
);
|
||||
case WalletType.haven:
|
||||
return haven!.createHavenRestoreWalletFromSeedCredentials(
|
||||
|
@ -256,36 +259,16 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
case WalletType.litecoin:
|
||||
String? mnemonic = credentials['seed'] as String?;
|
||||
String? passphrase = credentials['passphrase'] as String?;
|
||||
final bitcoinDerivations = await bitcoin!.getDerivationsFromMnemonic(
|
||||
final list = await bitcoin!.getDerivationInfosFromMnemonic(
|
||||
mnemonic: mnemonic!,
|
||||
node: node,
|
||||
passphrase: passphrase,
|
||||
);
|
||||
|
||||
List<DerivationInfo> list = [];
|
||||
for (var derivation in bitcoinDerivations) {
|
||||
if (derivation.derivationType.toString().endsWith("electrum")) {
|
||||
list.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.electrum,
|
||||
derivationPath: "m/0'",
|
||||
description: "Electrum",
|
||||
scriptType: "p2wpkh",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
list.add(
|
||||
DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/0'/0'",
|
||||
description: "Standard BIP84 native segwit",
|
||||
scriptType: "p2wpkh",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// is restoring? = add old used derivations
|
||||
final oldList = bitcoin!.getOldDerivationInfos(list);
|
||||
|
||||
return list;
|
||||
return oldList;
|
||||
case WalletType.nano:
|
||||
String? mnemonic = credentials['seed'] as String?;
|
||||
String? seedKey = credentials['private_key'] as String?;
|
||||
|
|
|
@ -176,6 +176,7 @@ abstract class Bitcoin {
|
|||
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate, {int? customRate});
|
||||
|
||||
List<Unspent> getUnspents(Object wallet, {UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any});
|
||||
List<DerivationInfo> getOldSPDerivationInfos();
|
||||
Future<void> updateUnspents(Object wallet);
|
||||
WalletService createBitcoinWalletService(
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
|
@ -198,6 +199,7 @@ abstract class Bitcoin {
|
|||
TransactionPriority getLitecoinTransactionPrioritySlow();
|
||||
Future<List<DerivationType>> compareDerivationMethods(
|
||||
{required String mnemonic, required Node node});
|
||||
List<DerivationInfo> getOldDerivationInfos(List<DerivationInfo> list);
|
||||
Future<List<BitcoinDerivationInfo>> getDerivationsFromMnemonic(
|
||||
{required String mnemonic, required Node node, String? passphrase});
|
||||
Map<DerivationType, List<DerivationInfo>> getElectrumDerivations();
|
||||
|
|
Loading…
Reference in a new issue