-
Notifications
You must be signed in to change notification settings - Fork 189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Electrum sp refactors #1781
base: main
Are you sure you want to change the base?
Electrum sp refactors #1781
Changes from 25 commits
e47846b
7339b78
64caf84
433686b
f3a0ff7
02fabf8
4a4250a
a3e131d
c9a5023
a4561d2
7964b2a
884a822
28804b8
243f734
57f4860
a169db7
6e8b3d7
d4b0165
3950f6c
cc853b9
75aaa6f
378e160
aa6f932
b9f76bd
9bb3d9f
c35dec0
b7ff9ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,39 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:bitcoin_base/bitcoin_base.dart'; | ||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; | ||
|
||
abstract class BaseBitcoinAddressRecord { | ||
BaseBitcoinAddressRecord( | ||
this.address, { | ||
required this.index, | ||
this.isHidden = false, | ||
bool isChange = false, | ||
int txCount = 0, | ||
int balance = 0, | ||
String name = '', | ||
bool isUsed = false, | ||
required this.type, | ||
required this.network, | ||
required this.addressType, | ||
bool? isHidden, | ||
}) : _txCount = txCount, | ||
_balance = balance, | ||
_name = name, | ||
_isUsed = isUsed; | ||
_isUsed = isUsed, | ||
_isHidden = isHidden ?? isChange, | ||
_isChange = isChange; | ||
|
||
@override | ||
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address; | ||
|
||
final String address; | ||
bool isHidden; | ||
bool _isHidden; | ||
bool get isHidden => _isHidden; | ||
final bool _isChange; | ||
bool get isChange => _isChange; | ||
final int index; | ||
int _txCount; | ||
int _balance; | ||
String _name; | ||
bool _isUsed; | ||
BasedUtxoNetwork? network; | ||
|
||
int get txCount => _txCount; | ||
|
||
|
@@ -42,123 +47,207 @@ abstract class BaseBitcoinAddressRecord { | |
|
||
bool get isUsed => _isUsed; | ||
|
||
void setAsUsed() => _isUsed = true; | ||
void setAsUsed() { | ||
_isUsed = true; | ||
_isHidden = true; | ||
} | ||
|
||
void setNewName(String label) => _name = label; | ||
|
||
int get hashCode => address.hashCode; | ||
|
||
BitcoinAddressType type; | ||
BitcoinAddressType addressType; | ||
|
||
String toJSON(); | ||
} | ||
|
||
class BitcoinAddressRecord extends BaseBitcoinAddressRecord { | ||
final BitcoinDerivationInfo derivationInfo; | ||
final CWBitcoinDerivationType derivationType; | ||
|
||
BitcoinAddressRecord( | ||
super.address, { | ||
required super.index, | ||
super.isHidden = false, | ||
required this.derivationInfo, | ||
required this.derivationType, | ||
super.isHidden, | ||
super.isChange = false, | ||
super.txCount = 0, | ||
super.balance = 0, | ||
super.name = '', | ||
super.isUsed = false, | ||
required super.type, | ||
required super.addressType, | ||
String? scriptHash, | ||
required super.network, | ||
}) : scriptHash = scriptHash ?? | ||
(network != null ? BitcoinAddressUtils.scriptHash(address, network: network) : null); | ||
BasedUtxoNetwork? network, | ||
}) { | ||
if (scriptHash == null && network == null) { | ||
throw ArgumentError('either scriptHash or network must be provided'); | ||
} | ||
|
||
factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) { | ||
this.scriptHash = scriptHash ?? BitcoinAddressUtils.scriptHash(address, network: network!); | ||
} | ||
|
||
factory BitcoinAddressRecord.fromJSON(String jsonSource) { | ||
final decoded = json.decode(jsonSource) as Map; | ||
|
||
return BitcoinAddressRecord( | ||
decoded['address'] as String, | ||
index: decoded['index'] as int, | ||
derivationInfo: BitcoinDerivationInfo.fromJSON( | ||
decoded['derivationInfo'] as Map<String, dynamic>, | ||
), | ||
derivationType: CWBitcoinDerivationType.values[decoded['derivationType'] as int], | ||
isHidden: decoded['isHidden'] as bool? ?? false, | ||
isChange: decoded['isChange'] as bool? ?? false, | ||
isUsed: decoded['isUsed'] as bool? ?? false, | ||
txCount: decoded['txCount'] as int? ?? 0, | ||
name: decoded['name'] as String? ?? '', | ||
balance: decoded['balance'] as int? ?? 0, | ||
type: decoded['type'] != null && decoded['type'] != '' | ||
addressType: decoded['type'] != null && decoded['type'] != '' | ||
? BitcoinAddressType.values | ||
.firstWhere((type) => type.toString() == decoded['type'] as String) | ||
: SegwitAddresType.p2wpkh, | ||
scriptHash: decoded['scriptHash'] as String?, | ||
network: network, | ||
); | ||
} | ||
|
||
String? scriptHash; | ||
|
||
String getScriptHash(BasedUtxoNetwork network) { | ||
if (scriptHash != null) return scriptHash!; | ||
scriptHash = BitcoinAddressUtils.scriptHash(address, network: network); | ||
return scriptHash!; | ||
} | ||
late String scriptHash; | ||
|
||
@override | ||
String toJSON() => json.encode({ | ||
'address': address, | ||
'index': index, | ||
'derivationInfo': derivationInfo.toJSON(), | ||
'derivationType': derivationType.index, | ||
'isHidden': isHidden, | ||
'isChange': isChange, | ||
'isUsed': isUsed, | ||
'txCount': txCount, | ||
'name': name, | ||
'balance': balance, | ||
'type': type.toString(), | ||
'type': addressType.toString(), | ||
'scriptHash': scriptHash, | ||
}); | ||
|
||
@override | ||
operator ==(Object other) { | ||
if (identical(this, other)) return true; | ||
|
||
return other is BitcoinAddressRecord && | ||
other.address == address && | ||
other.index == index && | ||
other.derivationInfo == derivationInfo && | ||
other.scriptHash == scriptHash && | ||
other.addressType == addressType && | ||
other.derivationType == derivationType; | ||
} | ||
|
||
@override | ||
int get hashCode => | ||
address.hashCode ^ | ||
index.hashCode ^ | ||
derivationInfo.hashCode ^ | ||
scriptHash.hashCode ^ | ||
addressType.hashCode ^ | ||
derivationType.hashCode; | ||
} | ||
|
||
class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord { | ||
final String derivationPath; | ||
int get labelIndex => index; | ||
final String? labelHex; | ||
|
||
static bool isChangeAddress(int labelIndex) => labelIndex == 0; | ||
|
||
BitcoinSilentPaymentAddressRecord( | ||
super.address, { | ||
required super.index, | ||
super.isHidden = false, | ||
required int labelIndex, | ||
this.derivationPath = BitcoinDerivationPaths.SILENT_PAYMENTS_SPEND, | ||
super.txCount = 0, | ||
super.balance = 0, | ||
super.name = '', | ||
super.isUsed = false, | ||
required this.silentPaymentTweak, | ||
required super.network, | ||
required super.type, | ||
}) : super(); | ||
super.addressType = SilentPaymentsAddresType.p2sp, | ||
super.isHidden, | ||
this.labelHex, | ||
}) : super(index: labelIndex, isChange: isChangeAddress(labelIndex)) { | ||
if (labelIndex != 1 && labelHex == null) { | ||
throw ArgumentError('label must be provided for silent address index != 1'); | ||
} | ||
} | ||
|
||
factory BitcoinSilentPaymentAddressRecord.fromJSON(String jsonSource, | ||
{BasedUtxoNetwork? network}) { | ||
final decoded = json.decode(jsonSource) as Map; | ||
|
||
return BitcoinSilentPaymentAddressRecord( | ||
decoded['address'] as String, | ||
index: decoded['index'] as int, | ||
isHidden: decoded['isHidden'] as bool? ?? false, | ||
derivationPath: decoded['derivationPath'] as String, | ||
labelIndex: decoded['labelIndex'] as int, | ||
isUsed: decoded['isUsed'] as bool? ?? false, | ||
txCount: decoded['txCount'] as int? ?? 0, | ||
name: decoded['name'] as String? ?? '', | ||
balance: decoded['balance'] as int? ?? 0, | ||
network: (decoded['network'] as String?) == null | ||
? network | ||
: BasedUtxoNetwork.fromName(decoded['network'] as String), | ||
silentPaymentTweak: decoded['silent_payment_tweak'] as String?, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are we no longer saving the tweak? isn't it needed for sending |
||
type: decoded['type'] != null && decoded['type'] != '' | ||
? BitcoinAddressType.values | ||
.firstWhere((type) => type.toString() == decoded['type'] as String) | ||
: SilentPaymentsAddresType.p2sp, | ||
labelHex: decoded['labelHex'] as String?, | ||
); | ||
} | ||
|
||
final String? silentPaymentTweak; | ||
@override | ||
String toJSON() => json.encode({ | ||
'address': address, | ||
'derivationPath': derivationPath, | ||
'labelIndex': labelIndex, | ||
'isUsed': isUsed, | ||
'txCount': txCount, | ||
'name': name, | ||
'balance': balance, | ||
'type': addressType.toString(), | ||
'labelHex': labelHex, | ||
}); | ||
} | ||
|
||
class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord { | ||
final ECPrivate spendKey; | ||
|
||
BitcoinReceivedSPAddressRecord( | ||
super.address, { | ||
required super.labelIndex, | ||
super.txCount = 0, | ||
super.balance = 0, | ||
super.name = '', | ||
super.isUsed = false, | ||
required this.spendKey, | ||
super.addressType = SegwitAddresType.p2tr, | ||
super.labelHex, | ||
}) : super(isHidden: true); | ||
|
||
factory BitcoinReceivedSPAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) { | ||
final decoded = json.decode(jsonSource) as Map; | ||
|
||
return BitcoinReceivedSPAddressRecord( | ||
decoded['address'] as String, | ||
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: (decoded['spendKey'] as String?) == null | ||
? ECPrivate.random() | ||
: ECPrivate.fromHex(decoded['spendKey'] as String), | ||
); | ||
} | ||
|
||
@override | ||
String toJSON() => json.encode({ | ||
'address': address, | ||
'index': index, | ||
'isHidden': isHidden, | ||
'labelIndex': labelIndex, | ||
'isUsed': isUsed, | ||
'txCount': txCount, | ||
'name': name, | ||
'balance': balance, | ||
'type': type.toString(), | ||
'network': network?.value, | ||
'silent_payment_tweak': silentPaymentTweak, | ||
'type': addressType.toString(), | ||
'labelHex': labelHex, | ||
'spend_key': spendKey.toString(), | ||
}); | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ import 'dart:async'; | |
|
||
import 'package:bitcoin_base/bitcoin_base.dart'; | ||
import 'package:blockchain_utils/blockchain_utils.dart'; | ||
import 'package:cw_bitcoin/utils.dart'; | ||
import 'package:cw_core/hardware/hardware_account_data.dart'; | ||
import 'package:ledger_bitcoin/ledger_bitcoin.dart'; | ||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; | ||
|
@@ -12,8 +11,7 @@ class BitcoinHardwareWalletService { | |
|
||
final LedgerConnection ledgerConnection; | ||
|
||
Future<List<HardwareAccountData>> getAvailableAccounts( | ||
{int index = 0, int limit = 5}) async { | ||
Future<List<HardwareAccountData>> getAvailableAccounts({int index = 0, int limit = 5}) async { | ||
final bitcoinLedgerApp = BitcoinLedgerApp(ledgerConnection); | ||
|
||
final masterFp = await bitcoinLedgerApp.getMasterFingerprint(); | ||
|
@@ -23,13 +21,14 @@ class BitcoinHardwareWalletService { | |
|
||
for (final i in indexRange) { | ||
final derivationPath = "m/84'/0'/$i'"; | ||
final xpub = | ||
await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath); | ||
Bip32Slip10Secp256k1 hd = | ||
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0)); | ||
|
||
final address = generateP2WPKHAddress( | ||
hd: hd, index: 0, network: BitcoinNetwork.mainnet); | ||
final xpub = await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath); | ||
final hd = Bip32Slip10Secp256k1.fromExtendedKey(xpub) | ||
.childKey(Bip32KeyIndex(0)) | ||
.childKey(Bip32KeyIndex(index)); | ||
Comment on lines
23
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need to double check this with you and Konstantin |
||
|
||
final address = ECPublic.fromBip32( | ||
hd.publicKey, | ||
).toP2wpkhAddress().toAddress(BitcoinNetwork.mainnet); | ||
|
||
accounts.add(HardwareAccountData( | ||
address: address, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we are sure that network won't be null, then shouldn't we make it required?
you are not setting it in the
fromJson
function so it will be null