mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 12:09:43 +00:00
feat: derivationinfo to address records
This commit is contained in:
parent
64caf8479e
commit
433686bce3
16 changed files with 253 additions and 212 deletions
|
@ -6,7 +6,7 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
BaseBitcoinAddressRecord(
|
BaseBitcoinAddressRecord(
|
||||||
this.address, {
|
this.address, {
|
||||||
required this.index,
|
required this.index,
|
||||||
this.isChange = false,
|
bool isChange = false,
|
||||||
int txCount = 0,
|
int txCount = 0,
|
||||||
int balance = 0,
|
int balance = 0,
|
||||||
String name = '',
|
String name = '',
|
||||||
|
@ -17,7 +17,8 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
_balance = balance,
|
_balance = balance,
|
||||||
_name = name,
|
_name = name,
|
||||||
_isUsed = isUsed,
|
_isUsed = isUsed,
|
||||||
_isHidden = isHidden ?? isChange;
|
_isHidden = isHidden ?? isChange,
|
||||||
|
_isChange = isChange;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
|
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
|
||||||
|
@ -25,7 +26,8 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
final String address;
|
final String address;
|
||||||
final bool _isHidden;
|
final bool _isHidden;
|
||||||
bool get isHidden => _isHidden;
|
bool get isHidden => _isHidden;
|
||||||
bool isChange;
|
final bool _isChange;
|
||||||
|
bool get isChange => _isChange;
|
||||||
final int index;
|
final int index;
|
||||||
int _txCount;
|
int _txCount;
|
||||||
int _balance;
|
int _balance;
|
||||||
|
@ -55,9 +57,12 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
|
final BitcoinDerivationInfo derivationInfo;
|
||||||
|
|
||||||
BitcoinAddressRecord(
|
BitcoinAddressRecord(
|
||||||
super.address, {
|
super.address, {
|
||||||
required super.index,
|
required super.index,
|
||||||
|
required this.derivationInfo,
|
||||||
super.isHidden,
|
super.isHidden,
|
||||||
super.isChange = false,
|
super.isChange = false,
|
||||||
super.txCount = 0,
|
super.txCount = 0,
|
||||||
|
@ -81,6 +86,9 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
return BitcoinAddressRecord(
|
return BitcoinAddressRecord(
|
||||||
decoded['address'] as String,
|
decoded['address'] as String,
|
||||||
index: decoded['index'] as int,
|
index: decoded['index'] as int,
|
||||||
|
derivationInfo: BitcoinDerivationInfo.fromJSON(
|
||||||
|
decoded['derivationInfo'] as Map<String, dynamic>,
|
||||||
|
),
|
||||||
isHidden: decoded['isHidden'] as bool? ?? false,
|
isHidden: decoded['isHidden'] as bool? ?? false,
|
||||||
isChange: decoded['isChange'] as bool? ?? false,
|
isChange: decoded['isChange'] as bool? ?? false,
|
||||||
isUsed: decoded['isUsed'] as bool? ?? false,
|
isUsed: decoded['isUsed'] as bool? ?? false,
|
||||||
|
@ -101,6 +109,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
String toJSON() => json.encode({
|
String toJSON() => json.encode({
|
||||||
'address': address,
|
'address': address,
|
||||||
'index': index,
|
'index': index,
|
||||||
|
'derivationInfo': derivationInfo.toJSON(),
|
||||||
'isHidden': isHidden,
|
'isHidden': isHidden,
|
||||||
'isChange': isChange,
|
'isChange': isChange,
|
||||||
'isUsed': isUsed,
|
'isUsed': isUsed,
|
||||||
|
@ -116,6 +125,8 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
int get labelIndex => index;
|
int get labelIndex => index;
|
||||||
final String? labelHex;
|
final String? labelHex;
|
||||||
|
|
||||||
|
static bool isChangeAddress(int labelIndex) => labelIndex == 0;
|
||||||
|
|
||||||
BitcoinSilentPaymentAddressRecord(
|
BitcoinSilentPaymentAddressRecord(
|
||||||
super.address, {
|
super.address, {
|
||||||
required int labelIndex,
|
required int labelIndex,
|
||||||
|
@ -126,9 +137,9 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
super.type = SilentPaymentsAddresType.p2sp,
|
super.type = SilentPaymentsAddresType.p2sp,
|
||||||
super.isHidden,
|
super.isHidden,
|
||||||
this.labelHex,
|
this.labelHex,
|
||||||
}) : super(index: labelIndex, isChange: labelIndex == 0) {
|
}) : super(index: labelIndex, isChange: isChangeAddress(labelIndex)) {
|
||||||
if (labelIndex != 1 && labelHex == null) {
|
if (labelIndex != 1 && labelHex == null) {
|
||||||
throw ArgumentError('label must be provided for silent address index > 0');
|
throw ArgumentError('label must be provided for silent address index != 1');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,14 @@ class BitcoinHardwareWalletService {
|
||||||
final xpub = await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
|
final xpub = await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
|
||||||
final bip32 = Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
|
final bip32 = Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
|
||||||
|
|
||||||
|
final fullPath = Bip32PathParser.parse(derivationPath).addElem(Bip32KeyIndex(0));
|
||||||
|
|
||||||
|
final address = ECPublic.fromBip32(bip32.derive(fullPath).publicKey)
|
||||||
|
.toP2wpkhAddress()
|
||||||
|
.toAddress(BitcoinNetwork.mainnet);
|
||||||
|
|
||||||
accounts.add(HardwareAccountData(
|
accounts.add(HardwareAccountData(
|
||||||
address: P2wpkhAddress.fromBip32(bip32: bip32, isChange: false, index: i)
|
address: address,
|
||||||
.toAddress(BitcoinNetwork.mainnet),
|
|
||||||
accountIndex: i,
|
accountIndex: i,
|
||||||
derivationPath: derivationPath,
|
derivationPath: derivationPath,
|
||||||
masterFingerprint: masterFp,
|
masterFingerprint: masterFp,
|
||||||
|
|
|
@ -32,7 +32,10 @@ class BitcoinUnspent extends Unspent {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object o) {
|
bool operator ==(Object o) {
|
||||||
print('BitcoinUnspent operator ==');
|
if (identical(this, o)) return true;
|
||||||
return o is BitcoinUnspent && hash == o.hash && vout == o.vout;
|
return o is BitcoinUnspent && hash == o.hash && vout == o.vout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(hash, vout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
updatedUnspentCoins.addAll(await fetchUnspent(address));
|
updatedUnspentCoins.addAll(await fetchUnspent(address));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
unspentCoins = updatedUnspentCoins.toSet();
|
unspentCoins.addAll(updatedUnspentCoins);
|
||||||
|
|
||||||
if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
|
if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
|
||||||
unspentCoins.forEach((coin) => addCoinInfo(coin));
|
unspentCoins.forEach((coin) => addCoinInfo(coin));
|
||||||
|
@ -1033,3 +1033,58 @@ Future<void> delegatedScan(ScanData scanData) async {
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ScanNode {
|
||||||
|
final Uri uri;
|
||||||
|
final bool? useSSL;
|
||||||
|
|
||||||
|
ScanNode(this.uri, this.useSSL);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScanData {
|
||||||
|
final SendPort sendPort;
|
||||||
|
final SilentPaymentOwner silentAddress;
|
||||||
|
final int height;
|
||||||
|
final ScanNode? node;
|
||||||
|
final BasedUtxoNetwork network;
|
||||||
|
final int chainTip;
|
||||||
|
final List<String> transactionHistoryIds;
|
||||||
|
final Map<String, String> labels;
|
||||||
|
final List<int> labelIndexes;
|
||||||
|
final bool isSingleScan;
|
||||||
|
|
||||||
|
ScanData({
|
||||||
|
required this.sendPort,
|
||||||
|
required this.silentAddress,
|
||||||
|
required this.height,
|
||||||
|
required this.node,
|
||||||
|
required this.network,
|
||||||
|
required this.chainTip,
|
||||||
|
required this.transactionHistoryIds,
|
||||||
|
required this.labels,
|
||||||
|
required this.labelIndexes,
|
||||||
|
required this.isSingleScan,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ScanData.fromHeight(ScanData scanData, int newHeight) {
|
||||||
|
return ScanData(
|
||||||
|
sendPort: scanData.sendPort,
|
||||||
|
silentAddress: scanData.silentAddress,
|
||||||
|
height: newHeight,
|
||||||
|
node: scanData.node,
|
||||||
|
network: scanData.network,
|
||||||
|
chainTip: scanData.chainTip,
|
||||||
|
transactionHistoryIds: scanData.transactionHistoryIds,
|
||||||
|
labels: scanData.labels,
|
||||||
|
labelIndexes: scanData.labelIndexes,
|
||||||
|
isSingleScan: scanData.isSingleScan,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SyncResponse {
|
||||||
|
final int height;
|
||||||
|
final SyncStatus syncStatus;
|
||||||
|
|
||||||
|
SyncResponse(this.height, this.syncStatus);
|
||||||
|
}
|
||||||
|
|
|
@ -39,27 +39,44 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) {
|
}) {
|
||||||
switch (addressType) {
|
switch (addressType) {
|
||||||
case P2pkhAddressType.p2pkh:
|
case P2pkhAddressType.p2pkh:
|
||||||
return P2pkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
|
return P2pkhAddress.fromDerivation(
|
||||||
case SegwitAddresType.p2tr:
|
|
||||||
return P2trAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
|
|
||||||
case SegwitAddresType.p2wsh:
|
|
||||||
return P2wshAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
|
|
||||||
case P2shAddressType.p2wpkhInP2sh:
|
|
||||||
return P2shAddress.fromBip32(
|
|
||||||
bip32: bip32,
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
case SegwitAddresType.p2tr:
|
||||||
|
return P2trAddress.fromDerivation(
|
||||||
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
case SegwitAddresType.p2wsh:
|
||||||
|
return P2wshAddress.fromDerivation(
|
||||||
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
case P2shAddressType.p2wpkhInP2sh:
|
||||||
|
return P2shAddress.fromDerivation(
|
||||||
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
isChange: isChange,
|
isChange: isChange,
|
||||||
index: index,
|
index: index,
|
||||||
type: P2shAddressType.p2wpkhInP2sh,
|
type: P2shAddressType.p2wpkhInP2sh,
|
||||||
);
|
);
|
||||||
case SegwitAddresType.p2wpkh:
|
case SegwitAddresType.p2wpkh:
|
||||||
return P2wpkhAddress.fromBip32(
|
return P2wpkhAddress.fromDerivation(
|
||||||
bip32: bip32,
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
isChange: isChange,
|
isChange: isChange,
|
||||||
index: index,
|
index: index,
|
||||||
isElectrum: false, // TODO:
|
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
throw ArgumentError('Invalid address type');
|
throw ArgumentError('Invalid address type');
|
||||||
|
|
|
@ -4,11 +4,8 @@ import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/utils/file.dart';
|
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
|
||||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
|
||||||
|
|
||||||
part 'electrum_transaction_history.g.dart';
|
part 'electrum_transaction_history.g.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:isolate';
|
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
@ -38,7 +37,6 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger;
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:hex/hex.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
part 'electrum_wallet.g.dart';
|
part 'electrum_wallet.g.dart';
|
||||||
|
@ -69,7 +67,8 @@ abstract class ElectrumWalletBase
|
||||||
_password = password,
|
_password = password,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
isEnabledAutoGenerateSubaddress = true,
|
isEnabledAutoGenerateSubaddress = true,
|
||||||
unspentCoins = {},
|
// TODO: inital unspent coins
|
||||||
|
unspentCoins = ObservableSet(),
|
||||||
scripthashesListening = {},
|
scripthashesListening = {},
|
||||||
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of(currency != null
|
balance = ObservableMap<CryptoCurrency, ElectrumBalance>.of(currency != null
|
||||||
? {
|
? {
|
||||||
|
@ -221,8 +220,7 @@ abstract class ElectrumWalletBase
|
||||||
);
|
);
|
||||||
|
|
||||||
String _password;
|
String _password;
|
||||||
@observable
|
ObservableSet<BitcoinUnspent> unspentCoins;
|
||||||
Set<BitcoinUnspent> unspentCoins;
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
TransactionPriorities? feeRates;
|
TransactionPriorities? feeRates;
|
||||||
|
@ -404,7 +402,7 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
bool _isBelowDust(int amount) => amount <= _dustAmount && network != BitcoinNetwork.testnet;
|
bool _isBelowDust(int amount) => amount <= _dustAmount && network != BitcoinNetwork.testnet;
|
||||||
|
|
||||||
UtxoDetails _createUTXOS({
|
TxCreateUtxoDetails _createUTXOS({
|
||||||
required bool sendAll,
|
required bool sendAll,
|
||||||
required int credentialsAmount,
|
required int credentialsAmount,
|
||||||
required bool paysToSilentPayment,
|
required bool paysToSilentPayment,
|
||||||
|
@ -484,13 +482,13 @@ abstract class ElectrumWalletBase
|
||||||
.toHex();
|
.toHex();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: isElectrum
|
if (utx.bitcoinAddressRecord is BitcoinAddressRecord) {
|
||||||
final derivationPath = BitcoinAddressUtils.getDerivationPath(
|
final derivationPath = (utx.bitcoinAddressRecord as BitcoinAddressRecord)
|
||||||
type: utx.bitcoinAddressRecord.type,
|
.derivationInfo
|
||||||
account: utx.bitcoinAddressRecord.isChange ? 1 : 0,
|
.derivationPath
|
||||||
index: utx.bitcoinAddressRecord.index,
|
.toString();
|
||||||
);
|
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
|
||||||
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
|
}
|
||||||
|
|
||||||
utxos.add(
|
utxos.add(
|
||||||
UtxoWithAddress(
|
UtxoWithAddress(
|
||||||
|
@ -521,7 +519,7 @@ abstract class ElectrumWalletBase
|
||||||
throw BitcoinTransactionNoInputsException();
|
throw BitcoinTransactionNoInputsException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return UtxoDetails(
|
return TxCreateUtxoDetails(
|
||||||
availableInputs: availableInputs,
|
availableInputs: availableInputs,
|
||||||
unconfirmedCoins: unconfirmedCoins,
|
unconfirmedCoins: unconfirmedCoins,
|
||||||
utxos: utxos,
|
utxos: utxos,
|
||||||
|
@ -662,11 +660,7 @@ abstract class ElectrumWalletBase
|
||||||
isChange: true,
|
isChange: true,
|
||||||
));
|
));
|
||||||
|
|
||||||
final changeDerivationPath = BitcoinAddressUtils.getDerivationPath(
|
final changeDerivationPath = changeAddress.derivationInfo.derivationPath.toString();
|
||||||
type: changeAddress.type,
|
|
||||||
account: changeAddress.isChange ? 1 : 0,
|
|
||||||
index: changeAddress.index,
|
|
||||||
);
|
|
||||||
utxoDetails.publicKeys[address.pubKeyHash()] =
|
utxoDetails.publicKeys[address.pubKeyHash()] =
|
||||||
PublicKeyWithDerivationPath('', changeDerivationPath);
|
PublicKeyWithDerivationPath('', changeDerivationPath);
|
||||||
|
|
||||||
|
@ -1176,7 +1170,7 @@ abstract class ElectrumWalletBase
|
||||||
updatedUnspentCoins.addAll(await fetchUnspent(address));
|
updatedUnspentCoins.addAll(await fetchUnspent(address));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
unspentCoins = updatedUnspentCoins.toSet();
|
unspentCoins.addAll(updatedUnspentCoins);
|
||||||
|
|
||||||
if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
|
if (unspentCoinsInfo.length != updatedUnspentCoins.length) {
|
||||||
unspentCoins.forEach((coin) => addCoinInfo(coin));
|
unspentCoins.forEach((coin) => addCoinInfo(coin));
|
||||||
|
@ -1220,17 +1214,7 @@ abstract class ElectrumWalletBase
|
||||||
final newUnspentCoins = (await fetchUnspent(addressRecord)).toSet();
|
final newUnspentCoins = (await fetchUnspent(addressRecord)).toSet();
|
||||||
await updateCoins(newUnspentCoins);
|
await updateCoins(newUnspentCoins);
|
||||||
|
|
||||||
print([1, unspentCoins.containsAll(newUnspentCoins)]);
|
unspentCoins.addAll(newUnspentCoins);
|
||||||
if (!unspentCoins.containsAll(newUnspentCoins)) {
|
|
||||||
newUnspentCoins.forEach((coin) {
|
|
||||||
print(unspentCoins.contains(coin));
|
|
||||||
print([coin.vout, coin.hash]);
|
|
||||||
print([unspentCoins.first.vout, unspentCoins.first.hash]);
|
|
||||||
if (!unspentCoins.contains(coin)) {
|
|
||||||
unspentCoins.add(coin);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (unspentCoinsInfo.length != unspentCoins.length) {
|
// if (unspentCoinsInfo.length != unspentCoins.length) {
|
||||||
// unspentCoins.forEach(addCoinInfo);
|
// unspentCoins.forEach(addCoinInfo);
|
||||||
|
@ -1400,7 +1384,7 @@ abstract class ElectrumWalletBase
|
||||||
if (index + 1 <= script.length) {
|
if (index + 1 <= script.length) {
|
||||||
try {
|
try {
|
||||||
final opReturnData = script[index + 1].toString();
|
final opReturnData = script[index + 1].toString();
|
||||||
memo = utf8.decode(HEX.decode(opReturnData));
|
memo = StringUtils.decode(BytesUtils.fromHexString(opReturnData));
|
||||||
continue;
|
continue;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
throw Exception('Cannot decode OP_RETURN data');
|
throw Exception('Cannot decode OP_RETURN data');
|
||||||
|
@ -1708,6 +1692,7 @@ abstract class ElectrumWalletBase
|
||||||
isChange: addressRecord.isChange,
|
isChange: addressRecord.isChange,
|
||||||
gap: gapLimit,
|
gap: gapLimit,
|
||||||
type: addressRecord.type,
|
type: addressRecord.type,
|
||||||
|
derivationInfo: BitcoinAddressUtils.getDerivationFromType(addressRecord.type),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1805,21 +1790,17 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> signMessage(String message, {String? address = null}) async {
|
Future<String> signMessage(String message, {String? address = null}) async {
|
||||||
Bip32Slip10Secp256k1 HD = bip32;
|
final record = walletAddresses.getFromAddresses(address!);
|
||||||
|
|
||||||
final record = walletAddresses.allAddresses.firstWhere((element) => element.address == address);
|
final path = Bip32PathParser.parse(walletInfo.derivationInfo!.derivationPath!)
|
||||||
|
.addElem(
|
||||||
|
Bip32KeyIndex(BitcoinAddressUtils.getAccountFromChange(record.isChange)),
|
||||||
|
)
|
||||||
|
.addElem(Bip32KeyIndex(record.index));
|
||||||
|
|
||||||
if (record.isChange) {
|
final priv = ECPrivate.fromHex(bip32.derive(path).privateKey.toHex());
|
||||||
HD = HD.childKey(Bip32KeyIndex(1));
|
|
||||||
} else {
|
|
||||||
HD = HD.childKey(Bip32KeyIndex(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
HD = HD.childKey(Bip32KeyIndex(record.index));
|
final hexEncoded = priv.signMessage(StringUtils.encode(message));
|
||||||
final priv = ECPrivate.fromHex(HD.privateKey.privKey.toHex());
|
|
||||||
|
|
||||||
String messagePrefix = '\x18Bitcoin Signed Message:\n';
|
|
||||||
final hexEncoded = priv.signMessage(utf8.encode(message), messagePrefix: messagePrefix);
|
|
||||||
final decodedSig = hex.decode(hexEncoded);
|
final decodedSig = hex.decode(hexEncoded);
|
||||||
return base64Encode(decodedSig);
|
return base64Encode(decodedSig);
|
||||||
}
|
}
|
||||||
|
@ -1835,7 +1816,7 @@ abstract class ElectrumWalletBase
|
||||||
if (signature.endsWith('=')) {
|
if (signature.endsWith('=')) {
|
||||||
sigDecodedBytes = base64.decode(signature);
|
sigDecodedBytes = base64.decode(signature);
|
||||||
} else {
|
} else {
|
||||||
sigDecodedBytes = hex.decode(signature);
|
sigDecodedBytes = BytesUtils.fromHexString(signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigDecodedBytes.length != 64 && sigDecodedBytes.length != 65) {
|
if (sigDecodedBytes.length != 64 && sigDecodedBytes.length != 65) {
|
||||||
|
@ -1845,7 +1826,7 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
String messagePrefix = '\x18Bitcoin Signed Message:\n';
|
String messagePrefix = '\x18Bitcoin Signed Message:\n';
|
||||||
final messageHash = QuickCrypto.sha256Hash(
|
final messageHash = QuickCrypto.sha256Hash(
|
||||||
BitcoinSignerUtils.magicMessage(utf8.encode(message), messagePrefix));
|
BitcoinSignerUtils.magicMessage(StringUtils.encode(message), messagePrefix));
|
||||||
|
|
||||||
List<int> correctSignature =
|
List<int> correctSignature =
|
||||||
sigDecodedBytes.length == 65 ? sigDecodedBytes.sublist(1) : List.from(sigDecodedBytes);
|
sigDecodedBytes.length == 65 ? sigDecodedBytes.sublist(1) : List.from(sigDecodedBytes);
|
||||||
|
@ -1911,14 +1892,14 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.disconnected:
|
case ConnectionStatus.disconnected:
|
||||||
// if (syncStatus is! NotConnectedSyncStatus) {
|
if (syncStatus is! NotConnectedSyncStatus) {
|
||||||
// syncStatus = NotConnectedSyncStatus();
|
syncStatus = NotConnectedSyncStatus();
|
||||||
// }
|
}
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.failed:
|
case ConnectionStatus.failed:
|
||||||
// if (syncStatus is! LostConnectionSyncStatus) {
|
if (syncStatus is! LostConnectionSyncStatus) {
|
||||||
// syncStatus = LostConnectionSyncStatus();
|
syncStatus = LostConnectionSyncStatus();
|
||||||
// }
|
}
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.connecting:
|
case ConnectionStatus.connecting:
|
||||||
if (syncStatus is! ConnectingSyncStatus) {
|
if (syncStatus is! ConnectingSyncStatus) {
|
||||||
|
@ -1989,7 +1970,7 @@ abstract class ElectrumWalletBase
|
||||||
if (index + 1 <= script.length) {
|
if (index + 1 <= script.length) {
|
||||||
try {
|
try {
|
||||||
final opReturnData = script[index + 1].toString();
|
final opReturnData = script[index + 1].toString();
|
||||||
final decodedString = utf8.decode(HEX.decode(opReturnData));
|
final decodedString = StringUtils.decode(BytesUtils.fromHexString(opReturnData));
|
||||||
outputAddresses.add('OP_RETURN:$decodedString');
|
outputAddresses.add('OP_RETURN:$decodedString');
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
outputAddresses.add('OP_RETURN:');
|
outputAddresses.add('OP_RETURN:');
|
||||||
|
@ -2005,61 +1986,6 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScanNode {
|
|
||||||
final Uri uri;
|
|
||||||
final bool? useSSL;
|
|
||||||
|
|
||||||
ScanNode(this.uri, this.useSSL);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ScanData {
|
|
||||||
final SendPort sendPort;
|
|
||||||
final SilentPaymentOwner silentAddress;
|
|
||||||
final int height;
|
|
||||||
final ScanNode? node;
|
|
||||||
final BasedUtxoNetwork network;
|
|
||||||
final int chainTip;
|
|
||||||
final List<String> transactionHistoryIds;
|
|
||||||
final Map<String, String> labels;
|
|
||||||
final List<int> labelIndexes;
|
|
||||||
final bool isSingleScan;
|
|
||||||
|
|
||||||
ScanData({
|
|
||||||
required this.sendPort,
|
|
||||||
required this.silentAddress,
|
|
||||||
required this.height,
|
|
||||||
required this.node,
|
|
||||||
required this.network,
|
|
||||||
required this.chainTip,
|
|
||||||
required this.transactionHistoryIds,
|
|
||||||
required this.labels,
|
|
||||||
required this.labelIndexes,
|
|
||||||
required this.isSingleScan,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory ScanData.fromHeight(ScanData scanData, int newHeight) {
|
|
||||||
return ScanData(
|
|
||||||
sendPort: scanData.sendPort,
|
|
||||||
silentAddress: scanData.silentAddress,
|
|
||||||
height: newHeight,
|
|
||||||
node: scanData.node,
|
|
||||||
network: scanData.network,
|
|
||||||
chainTip: scanData.chainTip,
|
|
||||||
transactionHistoryIds: scanData.transactionHistoryIds,
|
|
||||||
labels: scanData.labels,
|
|
||||||
labelIndexes: scanData.labelIndexes,
|
|
||||||
isSingleScan: scanData.isSingleScan,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SyncResponse {
|
|
||||||
final int height;
|
|
||||||
final SyncStatus syncStatus;
|
|
||||||
|
|
||||||
SyncResponse(this.height, this.syncStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
class EstimatedTxResult {
|
class EstimatedTxResult {
|
||||||
EstimatedTxResult({
|
EstimatedTxResult({
|
||||||
required this.utxos,
|
required this.utxos,
|
||||||
|
@ -2095,7 +2021,7 @@ class PublicKeyWithDerivationPath {
|
||||||
final String publicKey;
|
final String publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UtxoDetails {
|
class TxCreateUtxoDetails {
|
||||||
final List<BitcoinUnspent> availableInputs;
|
final List<BitcoinUnspent> availableInputs;
|
||||||
final List<BitcoinUnspent> unconfirmedCoins;
|
final List<BitcoinUnspent> unconfirmedCoins;
|
||||||
final List<UtxoWithAddress> utxos;
|
final List<UtxoWithAddress> utxos;
|
||||||
|
@ -2106,7 +2032,7 @@ class UtxoDetails {
|
||||||
final bool spendsSilentPayment;
|
final bool spendsSilentPayment;
|
||||||
final bool spendsUnconfirmedTX;
|
final bool spendsUnconfirmedTX;
|
||||||
|
|
||||||
UtxoDetails({
|
TxCreateUtxoDetails({
|
||||||
required this.availableInputs,
|
required this.availableInputs,
|
||||||
required this.unconfirmedCoins,
|
required this.unconfirmedCoins,
|
||||||
required this.utxos,
|
required this.utxos,
|
||||||
|
|
|
@ -43,7 +43,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
int initialSilentAddressIndex = 0,
|
int initialSilentAddressIndex = 0,
|
||||||
List<BitcoinAddressRecord>? initialMwebAddresses,
|
List<BitcoinAddressRecord>? initialMwebAddresses,
|
||||||
BitcoinAddressType? initialAddressPageType,
|
BitcoinAddressType? initialAddressPageType,
|
||||||
}) : _allAddresses = (initialAddresses ?? []).toSet(),
|
}) : _allAddresses = ObservableSet.of(initialAddresses ?? []),
|
||||||
addressesByReceiveType =
|
addressesByReceiveType =
|
||||||
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
||||||
receiveAddresses = ObservableList<BitcoinAddressRecord>.of(
|
receiveAddresses = ObservableList<BitcoinAddressRecord>.of(
|
||||||
|
@ -63,11 +63,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
mwebAddresses =
|
mwebAddresses =
|
||||||
ObservableList<BitcoinAddressRecord>.of((initialMwebAddresses ?? []).toSet()),
|
ObservableList<BitcoinAddressRecord>.of((initialMwebAddresses ?? []).toSet()),
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
silentAddress = SilentPaymentOwner.fromPrivateKeys(
|
// TODO: initial silent address, not every time
|
||||||
b_scan: ECPrivate.fromHex(bip32.derive(SCAN_PATH).privateKey.toHex()),
|
silentAddress = SilentPaymentOwner.fromBip32(bip32);
|
||||||
b_spend: ECPrivate.fromHex(bip32.derive(SPEND_PATH).privateKey.toHex()),
|
|
||||||
network: network,
|
|
||||||
);
|
|
||||||
if (silentAddresses.length == 0) {
|
if (silentAddresses.length == 0) {
|
||||||
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||||
silentAddress.toString(),
|
silentAddress.toString(),
|
||||||
|
@ -91,8 +89,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
static const defaultChangeAddressesCount = 17;
|
static const defaultChangeAddressesCount = 17;
|
||||||
static const gap = 20;
|
static const gap = 20;
|
||||||
|
|
||||||
@observable
|
final ObservableSet<BitcoinAddressRecord> _allAddresses;
|
||||||
final Set<BitcoinAddressRecord> _allAddresses;
|
|
||||||
final ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
|
final ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
|
||||||
final ObservableList<BitcoinAddressRecord> receiveAddresses;
|
final ObservableList<BitcoinAddressRecord> receiveAddresses;
|
||||||
final ObservableList<BitcoinAddressRecord> changeAddresses;
|
final ObservableList<BitcoinAddressRecord> changeAddresses;
|
||||||
|
@ -119,6 +116,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
@computed
|
@computed
|
||||||
List<BitcoinAddressRecord> get allAddresses => _allAddresses.toList();
|
List<BitcoinAddressRecord> get allAddresses => _allAddresses.toList();
|
||||||
|
|
||||||
|
BitcoinAddressRecord getFromAddresses(String address) {
|
||||||
|
return _allAddresses.firstWhere((element) => element.address == address);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@computed
|
@computed
|
||||||
String get address {
|
String get address {
|
||||||
|
@ -189,7 +190,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get primaryAddress => getAddress(isChange: false, index: 0, addressType: addressPageType);
|
String get primaryAddress => _allAddresses.first.address;
|
||||||
|
|
||||||
Map<String, int> currentReceiveAddressIndexByType;
|
Map<String, int> currentReceiveAddressIndexByType;
|
||||||
|
|
||||||
|
@ -250,7 +251,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
updateAddressesByMatch();
|
updateAddressesByMatch();
|
||||||
updateReceiveAddresses();
|
updateReceiveAddresses();
|
||||||
updateChangeAddresses();
|
updateChangeAddresses();
|
||||||
_validateAddresses();
|
|
||||||
await updateAddressesInBox();
|
await updateAddressesInBox();
|
||||||
|
|
||||||
if (currentReceiveAddressIndex >= receiveAddresses.length) {
|
if (currentReceiveAddressIndex >= receiveAddresses.length) {
|
||||||
|
@ -263,15 +263,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<BitcoinAddressRecord> getChangeAddress(
|
Future<BitcoinAddressRecord> getChangeAddress({
|
||||||
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
List<BitcoinUnspent>? inputs,
|
||||||
|
List<BitcoinOutput>? outputs,
|
||||||
|
bool isPegIn = false,
|
||||||
|
}) async {
|
||||||
updateChangeAddresses();
|
updateChangeAddresses();
|
||||||
|
|
||||||
if (changeAddresses.isEmpty) {
|
|
||||||
final newAddresses = await _createNewAddresses(gap, isChange: true);
|
|
||||||
addAddresses(newAddresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentChangeAddressIndex >= changeAddresses.length) {
|
if (currentChangeAddressIndex >= changeAddresses.length) {
|
||||||
currentChangeAddressIndex = 0;
|
currentChangeAddressIndex = 0;
|
||||||
}
|
}
|
||||||
|
@ -326,13 +324,20 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
final newAddressIndex = addressesByReceiveType.fold(
|
final newAddressIndex = addressesByReceiveType.fold(
|
||||||
0, (int acc, addressRecord) => addressRecord.isChange == false ? acc + 1 : acc);
|
0, (int acc, addressRecord) => addressRecord.isChange == false ? acc + 1 : acc);
|
||||||
|
|
||||||
|
final derivationInfo = BitcoinAddressUtils.getDerivationFromType(addressPageType);
|
||||||
final address = BitcoinAddressRecord(
|
final address = BitcoinAddressRecord(
|
||||||
getAddress(isChange: false, index: newAddressIndex, addressType: addressPageType),
|
getAddress(
|
||||||
|
isChange: false,
|
||||||
|
index: newAddressIndex,
|
||||||
|
addressType: addressPageType,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
),
|
||||||
index: newAddressIndex,
|
index: newAddressIndex,
|
||||||
isChange: false,
|
isChange: false,
|
||||||
name: label,
|
name: label,
|
||||||
type: addressPageType,
|
type: addressPageType,
|
||||||
network: network,
|
network: network,
|
||||||
|
derivationInfo: BitcoinAddressUtils.getDerivationFromType(addressPageType),
|
||||||
);
|
);
|
||||||
_allAddresses.add(address);
|
_allAddresses.add(address);
|
||||||
Future.delayed(Duration.zero, () => updateAddressesByMatch());
|
Future.delayed(Duration.zero, () => updateAddressesByMatch());
|
||||||
|
@ -343,6 +348,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) {
|
}) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
@ -351,17 +357,28 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) {
|
}) {
|
||||||
return generateAddress(isChange: isChange, index: index, addressType: addressType)
|
return generateAddress(
|
||||||
.toAddress(network);
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
addressType: addressType,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
).toAddress(network);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getAddressAsync({
|
Future<String> getAddressAsync({
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) async =>
|
}) async =>
|
||||||
getAddress(isChange: isChange, index: index, addressType: addressType);
|
getAddress(
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
addressType: addressType,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
);
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void addBitcoinAddressTypes() {
|
void addBitcoinAddressTypes() {
|
||||||
|
@ -551,23 +568,41 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int gap,
|
required int gap,
|
||||||
required BitcoinAddressType type,
|
required BitcoinAddressType type,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) async {
|
}) async {
|
||||||
print("_allAddresses: ${_allAddresses.length}");
|
final newAddresses = await _createNewAddresses(
|
||||||
final newAddresses = await _createNewAddresses(gap, isChange: isChange, type: type);
|
gap,
|
||||||
|
isChange: isChange,
|
||||||
|
type: type,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
);
|
||||||
addAddresses(newAddresses);
|
addAddresses(newAddresses);
|
||||||
print("_allAddresses: ${_allAddresses.length}");
|
|
||||||
return newAddresses;
|
return newAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> generateInitialAddresses({required BitcoinAddressType type}) async {
|
Future<void> generateInitialAddresses({required BitcoinAddressType type}) async {
|
||||||
await discoverAddresses(isChange: false, gap: defaultReceiveAddressesCount, type: type);
|
// TODO: try all other derivations
|
||||||
await discoverAddresses(isChange: true, gap: defaultChangeAddressesCount, type: type);
|
final derivationInfo = BitcoinAddressUtils.getDerivationFromType(type);
|
||||||
|
|
||||||
|
await discoverAddresses(
|
||||||
|
isChange: false,
|
||||||
|
gap: defaultReceiveAddressesCount,
|
||||||
|
type: type,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
);
|
||||||
|
await discoverAddresses(
|
||||||
|
isChange: true,
|
||||||
|
gap: defaultChangeAddressesCount,
|
||||||
|
type: type,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<List<BitcoinAddressRecord>> _createNewAddresses(
|
Future<List<BitcoinAddressRecord>> _createNewAddresses(
|
||||||
int count, {
|
int count, {
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
bool isChange = false,
|
bool isChange = false,
|
||||||
BitcoinAddressType? type,
|
BitcoinAddressType? type,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -580,11 +615,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
isChange: isChange,
|
isChange: isChange,
|
||||||
index: i,
|
index: i,
|
||||||
addressType: type ?? addressPageType,
|
addressType: type ?? addressPageType,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
),
|
),
|
||||||
index: i,
|
index: i,
|
||||||
isChange: isChange,
|
isChange: isChange,
|
||||||
type: type ?? addressPageType,
|
type: type ?? addressPageType,
|
||||||
network: network,
|
network: network,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
);
|
);
|
||||||
list.add(address);
|
list.add(address);
|
||||||
}
|
}
|
||||||
|
@ -618,32 +655,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
updateAddressesByMatch();
|
updateAddressesByMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _validateAddresses() {
|
|
||||||
_allAddresses.forEach((element) async {
|
|
||||||
if (element.type == SegwitAddresType.mweb) {
|
|
||||||
// this would add a ton of startup lag for mweb addresses since we have 1000 of them
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!element.isChange &&
|
|
||||||
element.address !=
|
|
||||||
await getAddressAsync(
|
|
||||||
isChange: false,
|
|
||||||
index: element.index,
|
|
||||||
addressType: element.type,
|
|
||||||
)) {
|
|
||||||
element.isChange = true;
|
|
||||||
} else if (element.isChange &&
|
|
||||||
element.address !=
|
|
||||||
await getAddressAsync(
|
|
||||||
isChange: true,
|
|
||||||
index: element.index,
|
|
||||||
addressType: element.type,
|
|
||||||
)) {
|
|
||||||
element.isChange = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> setAddressType(BitcoinAddressType type) async {
|
Future<void> setAddressType(BitcoinAddressType type) async {
|
||||||
_addressPageType = type;
|
_addressPageType = type;
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
|
||||||
import 'package:cw_core/pathForWallet.dart';
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -92,7 +91,7 @@ class ElectrumWalletSnapshot {
|
||||||
|
|
||||||
final derivationType = DerivationType
|
final derivationType = DerivationType
|
||||||
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
|
||||||
final derivationPath = data['derivationPath'] as String? ?? electrum_path;
|
final derivationPath = data['derivationPath'] as String? ?? ELECTRUM_PATH;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
regularAddressIndexByType = {
|
regularAddressIndexByType = {
|
||||||
|
|
|
@ -28,7 +28,12 @@ class LitecoinHardwareWalletService {
|
||||||
final bip32 =
|
final bip32 =
|
||||||
Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion).childKey(Bip32KeyIndex(0));
|
Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion).childKey(Bip32KeyIndex(0));
|
||||||
|
|
||||||
final address = P2wpkhAddress.fromBip32(bip32: bip32, isChange: false, index: 0);
|
final address = P2wpkhAddress.fromDerivation(
|
||||||
|
bip32: bip32,
|
||||||
|
derivationInfo: BitcoinDerivationInfos.LITECOIN,
|
||||||
|
isChange: false,
|
||||||
|
index: 0,
|
||||||
|
);
|
||||||
|
|
||||||
accounts.add(HardwareAccountData(
|
accounts.add(HardwareAccountData(
|
||||||
address: address.toAddress(LitecoinNetwork.mainnet),
|
address: address.toAddress(LitecoinNetwork.mainnet),
|
||||||
|
|
|
@ -21,7 +21,6 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/pending_transaction.dart';
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
@ -243,7 +242,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
walletInfo.derivationInfo ??= DerivationInfo();
|
walletInfo.derivationInfo ??= DerivationInfo();
|
||||||
|
|
||||||
// set the default if not present:
|
// set the default if not present:
|
||||||
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
|
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? ELECTRUM_PATH;
|
||||||
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
|
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
|
||||||
|
|
||||||
Uint8List? seedBytes = null;
|
Uint8List? seedBytes = null;
|
||||||
|
@ -435,13 +434,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@override
|
@override
|
||||||
Future<void> rescan({
|
Future<void> rescan({required int height}) async {
|
||||||
required int height,
|
|
||||||
int? chainTip,
|
|
||||||
ScanData? scanData,
|
|
||||||
bool? doSingleScan,
|
|
||||||
bool? usingElectrs,
|
|
||||||
}) async {
|
|
||||||
_syncTimer?.cancel();
|
_syncTimer?.cancel();
|
||||||
await walletInfo.updateRestoreHeight(height);
|
await walletInfo.updateRestoreHeight(height);
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
index: e.key,
|
index: e.key,
|
||||||
type: SegwitAddresType.mweb,
|
type: SegwitAddresType.mweb,
|
||||||
network: network,
|
network: network,
|
||||||
|
derivationInfo: BitcoinAddressUtils.getDerivationFromType(SegwitAddresType.p2wpkh),
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
addMwebAddresses(addressRecords);
|
addMwebAddresses(addressRecords);
|
||||||
|
@ -121,12 +122,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) {
|
}) {
|
||||||
if (addressType == SegwitAddresType.mweb) {
|
if (addressType == SegwitAddresType.mweb) {
|
||||||
return MwebAddress.fromAddress(address: mwebAddrs[0], network: network);
|
return MwebAddress.fromAddress(address: mwebAddrs[0], network: network);
|
||||||
}
|
}
|
||||||
|
|
||||||
return P2wpkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
|
return P2wpkhAddress.fromDerivation(
|
||||||
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,12 +142,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) async {
|
}) async {
|
||||||
if (addressType == SegwitAddresType.mweb) {
|
if (addressType == SegwitAddresType.mweb) {
|
||||||
await ensureMwebAddressUpToIndexExists(index);
|
await ensureMwebAddressUpToIndexExists(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getAddress(isChange: isChange, index: index, addressType: addressType);
|
return getAddress(
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
addressType: addressType,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -194,6 +207,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
index: 0,
|
index: 0,
|
||||||
type: SegwitAddresType.mweb,
|
type: SegwitAddresType.mweb,
|
||||||
network: network,
|
network: network,
|
||||||
|
derivationInfo: BitcoinAddressUtils.getDerivationFromType(SegwitAddresType.p2wpkh),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -411,10 +411,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_identity_services_web
|
name: google_identity_services_web
|
||||||
sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6"
|
sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.1+4"
|
version: "0.3.0+2"
|
||||||
googleapis_auth:
|
googleapis_auth:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -467,10 +467,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.2"
|
version: "1.2.0"
|
||||||
http2:
|
http2:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -845,10 +845,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2"
|
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.2.2"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1041,18 +1041,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.4.2"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42"
|
sha256: "939ab60734a4f8fa95feacb55804fa278de28bdeef38e616dc08e44a84adea23"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.3"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -153,6 +153,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
isChange: addr.isChange,
|
isChange: addr.isChange,
|
||||||
type: P2pkhAddressType.p2pkh,
|
type: P2pkhAddressType.p2pkh,
|
||||||
network: BitcoinCashNetwork.mainnet,
|
network: BitcoinCashNetwork.mainnet,
|
||||||
|
derivationInfo: BitcoinAddressUtils.getDerivationFromType(P2pkhAddressType.p2pkh),
|
||||||
);
|
);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return BitcoinAddressRecord(
|
return BitcoinAddressRecord(
|
||||||
|
@ -161,6 +162,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
isChange: addr.isChange,
|
isChange: addr.isChange,
|
||||||
type: P2pkhAddressType.p2pkh,
|
type: P2pkhAddressType.p2pkh,
|
||||||
network: BitcoinCashNetwork.mainnet,
|
network: BitcoinCashNetwork.mainnet,
|
||||||
|
derivationInfo: BitcoinAddressUtils.getDerivationFromType(P2pkhAddressType.p2pkh),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|
|
@ -24,6 +24,12 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
||||||
required bool isChange,
|
required bool isChange,
|
||||||
required int index,
|
required int index,
|
||||||
required BitcoinAddressType addressType,
|
required BitcoinAddressType addressType,
|
||||||
|
required BitcoinDerivationInfo derivationInfo,
|
||||||
}) =>
|
}) =>
|
||||||
P2pkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index);
|
P2pkhAddress.fromDerivation(
|
||||||
|
bip32: bip32,
|
||||||
|
derivationInfo: derivationInfo,
|
||||||
|
isChange: isChange,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,9 +196,6 @@ class WalletInfo extends HiveObject {
|
||||||
@HiveField(24)
|
@HiveField(24)
|
||||||
List<String>? manualAddresses;
|
List<String>? manualAddresses;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
|
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
|
||||||
|
|
||||||
set yatLastUsedAddress(String address) {
|
set yatLastUsedAddress(String address) {
|
||||||
|
|
Loading…
Reference in a new issue