Skip to content
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

Open
wants to merge 79 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
e47846b
feat: begin delegated scan, big refactors
rafael-xmr Oct 4, 2024
7339b78
refactor: init
rafael-xmr Oct 28, 2024
64caf84
fix: restore flow slow, checking unspents
rafael-xmr Oct 29, 2024
433686b
feat: derivationinfo to address records
rafael-xmr Oct 30, 2024
f3a0ff7
feat: init electrum worker
rafael-xmr Oct 30, 2024
02fabf8
feat: electrum worker types
rafael-xmr Oct 31, 2024
4a4250a
feat: tx history worker
rafael-xmr Nov 1, 2024
a3e131d
feat: all address derivations
rafael-xmr Nov 4, 2024
c9a5023
feat: unspents and tweaks subscribe method
rafael-xmr Nov 5, 2024
a4561d2
chore: deps
rafael-xmr Nov 5, 2024
7964b2a
chore: deps
rafael-xmr Nov 5, 2024
884a822
fix: fee and addresses
rafael-xmr Nov 6, 2024
28804b8
Improve sending tx for electrum (#1790)
OmarHatem28 Nov 6, 2024
243f734
Merge branch 'main' into electrum-sp-refactors
OmarHatem28 Nov 6, 2024
57f4860
fix: tx dates
rafael-xmr Nov 7, 2024
a169db7
Merge remote-tracking branch 'origin/electrum-sp-refactors' into elec…
rafael-xmr Nov 7, 2024
6e8b3d7
misc
rafael-xmr Nov 7, 2024
d4b0165
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 12, 2024
3950f6c
refactor: misc
rafael-xmr Nov 16, 2024
cc853b9
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 16, 2024
75aaa6f
chore: build scripts
rafael-xmr Nov 17, 2024
378e160
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 17, 2024
aa6f932
chore: build errors
rafael-xmr Nov 17, 2024
b9f76bd
fix: btc create
rafael-xmr Nov 17, 2024
9bb3d9f
fix: btc restore
rafael-xmr Nov 17, 2024
c35dec0
feat: restore & scan imp
rafael-xmr Nov 23, 2024
b7ff9ab
fix: api & create
rafael-xmr Nov 23, 2024
e16a218
feat: fix rescan & stop, new card
rafael-xmr Nov 24, 2024
d30c852
chore: build
rafael-xmr Nov 24, 2024
74bae5d
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 27, 2024
3ee697b
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 27, 2024
95bb566
a
rafael-xmr Nov 27, 2024
046d30b
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 28, 2024
a2bbd6a
fix: change addr
rafael-xmr Nov 28, 2024
143e5d7
Revert 95bb566d09a7146c3b0b7b9a3183c1e969da6ee8
rafael-xmr Nov 28, 2024
cde88c0
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Nov 29, 2024
a97b552
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Dec 9, 2024
8264d38
fix: null check
rafael-xmr Dec 9, 2024
183fd89
chore: deps
rafael-xmr Dec 9, 2024
b927af9
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Dec 9, 2024
f702a19
chore: printVs
rafael-xmr Dec 9, 2024
6cbb4c6
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Dec 16, 2024
51590a6
feat: tx broadcast, error handling, remove electrum.dart
rafael-xmr Dec 19, 2024
dded5a7
Merge branch 'main' into electrum-sp-refactors
OmarHatem28 Dec 20, 2024
1646a67
fix: scan
rafael-xmr Dec 20, 2024
321bc1e
Merge remote-tracking branch 'origin/electrum-sp-refactors' into elec…
rafael-xmr Dec 20, 2024
a07be3d
chore: prints
rafael-xmr Dec 20, 2024
fb5aa9d
feat: fee estimation, review comments
rafael-xmr Dec 26, 2024
5284fd8
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Dec 26, 2024
cf9d64b
chore: build
rafael-xmr Dec 26, 2024
081a250
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Dec 27, 2024
bcf9aae
refactor: reviews
rafael-xmr Dec 30, 2024
6019370
refactor: reviews
rafael-xmr Jan 2, 2025
da478f3
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Jan 2, 2025
4594990
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Jan 7, 2025
c21d163
refactor: reviewing [skip ci]
rafael-xmr Jan 7, 2025
ad607e0
refactor: reviewing [skip ci]
rafael-xmr Jan 8, 2025
de773b3
refactor: reduce unneeded [skip ci]
rafael-xmr Jan 8, 2025
a6c021e
feat: fixes & improvements around fee types [skip ci]
rafael-xmr Jan 8, 2025
a09cb62
refactor: misc [skip ci]
rafael-xmr Jan 8, 2025
7436140
Merge branch 'main' into electrum-sp-refactors
OmarHatem28 Jan 9, 2025
1c5be4c
feat: merging bitcoin_base & blockchain_utils
rafael-xmr Jan 10, 2025
c10b9c2
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Jan 13, 2025
d7d12f0
fix: review comments and backward compatibility
rafael-xmr Jan 14, 2025
24a0b45
Merge remote-tracking branch 'origin/electrum-sp-refactors' into elec…
rafael-xmr Jan 14, 2025
73fe865
chore: deps
rafael-xmr Jan 14, 2025
91f0f87
Update pubspec.yaml
rafael-xmr Jan 14, 2025
83ba770
refactor: reviewing [skip ci]
rafael-xmr Jan 14, 2025
092f499
Merge remote-tracking branch 'origin/electrum-sp-refactors' into elec…
rafael-xmr Jan 14, 2025
3a3d4f6
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors…
rafael-xmr Jan 14, 2025
7a18a89
refactor: minor unneeded [skip ci]
rafael-xmr Jan 14, 2025
a2bf180
feat: batch requests
rafael-xmr Jan 15, 2025
5b60350
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Jan 15, 2025
f1345fa
chore: print
rafael-xmr Jan 15, 2025
f3e96c6
chore: temp fix
rafael-xmr Jan 15, 2025
7ef28df
Revert "chore: temp fix"
rafael-xmr Jan 15, 2025
c3fdc5e
feat: improve batch request even further, make initial faster
rafael-xmr Jan 16, 2025
ec48810
Merge remote-tracking branch 'origin/main' into electrum-sp-refactors
rafael-xmr Jan 16, 2025
e3058c9
feat(batch): fix initial sync + date update
rafael-xmr Jan 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ android/app/.externalNativeBuild/
cw_monero/ios/External/
cw_monero/cw_monero/android/.externalNativeBuild/
cw_monero/cw_monero/android/.cxx/
cw_monero/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux

# Generated dart files
**/*.g.dart
Expand Down Expand Up @@ -176,6 +177,7 @@ integration_test/playground.dart

# Monero.dart (Monero_C)
scripts/monero_c
scripts/android/app_env.fish
# iOS generated framework bin
ios/MoneroWallet.framework/MoneroWallet
ios/WowneroWallet.framework/WowneroWallet
23 changes: 0 additions & 23 deletions cw_bitcoin/lib/address_from_output.dart

This file was deleted.

241 changes: 204 additions & 37 deletions cw_bitcoin/lib/bitcoin_address_record.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
import 'dart:convert';

import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.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,
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;

Expand All @@ -42,7 +48,11 @@ 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;
Expand All @@ -53,27 +63,45 @@ abstract class BaseBitcoinAddressRecord {
}

class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
final BitcoinDerivationInfo derivationInfo;
final CWBitcoinDerivationType cwDerivationType;

BitcoinAddressRecord(
super.address, {
required super.index,
super.isHidden = false,
required this.derivationInfo,
required this.cwDerivationType,
super.isHidden,
super.isChange = false,
super.txCount = 0,
super.balance = 0,
super.name = '',
super.isUsed = false,
required super.type,
String? scriptHash,
required super.network,
}) : scriptHash = scriptHash ??
(network != null ? BitcoinAddressUtils.scriptHash(address, network: network) : null);
BasedUtxoNetwork? network,
}) {
if (scriptHash != null) {
this.scriptHash = scriptHash;
} else if (network != null) {
this.scriptHash = BitcoinAddressUtils.scriptHash(address, network: network);
} else {
throw ArgumentError('either scriptHash or network must be provided');
}
}

factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? 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>,
),
cwDerivationType: 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? ?? '',
Expand All @@ -83,82 +111,221 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
.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': cwDerivationType.index,
'isHidden': isHidden,
'isChange': isChange,
'isUsed': isUsed,
'txCount': txCount,
'name': name,
'balance': balance,
'type': type.toString(),
'scriptHash': scriptHash,
});

@override
bool 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.type == type &&
other.cwDerivationType == cwDerivationType;
}

@override
int get hashCode =>
address.hashCode ^
index.hashCode ^
derivationInfo.hashCode ^
scriptHash.hashCode ^
type.hashCode ^
cwDerivationType.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.type = SilentPaymentsAddresType.p2sp,
rafael-xmr marked this conversation as resolved.
Show resolved Hide resolved
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,
derivationPath: decoded['derivationPath'] as String,
labelIndex: decoded['labelIndex'] as int,
OmarHatem28 marked this conversation as resolved.
Show resolved Hide resolved
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['labelHex'] as String?,
);
}

@override
String toJSON() => json.encode({
'address': address,
'derivationPath': derivationPath,
'labelIndex': labelIndex,
'isUsed': isUsed,
'txCount': txCount,
'name': name,
'balance': balance,
'type': type.toString(),
'labelHex': labelHex,
});
}

class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord {
final String tweak;

BitcoinReceivedSPAddressRecord(
super.address, {
required super.labelIndex,
super.txCount = 0,
super.balance = 0,
super.name = '',
super.isUsed = false,
required this.tweak,
super.type = SegwitAddresType.p2tr,
OmarHatem28 marked this conversation as resolved.
Show resolved Hide resolved
super.labelHex,
}) : super(isHidden: true);

SilentPaymentOwner getSPWallet(
List<SilentPaymentOwner> silentPaymentsWallets, [
BasedUtxoNetwork network = BitcoinNetwork.mainnet,
]) {
final spAddress = silentPaymentsWallets.firstWhere(
(wallet) => wallet.toAddress(network) == this.address,
orElse: () => throw ArgumentError('SP wallet not found'),
);

return spAddress;
}

ECPrivate getSpendKey(
List<SilentPaymentOwner> silentPaymentsWallets, [
BasedUtxoNetwork network = BitcoinNetwork.mainnet,
]) {
return getSPWallet(silentPaymentsWallets, network)
.b_spend
.tweakAdd(BigintUtils.fromBytes(BytesUtils.fromHexString(tweak)));
}

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?,
tweak: decoded['tweak'] as String? ?? '',
rafael-xmr marked this conversation as resolved.
Show resolved Hide resolved
);
}

@override
String toJSON() => json.encode({
'address': address,
'labelIndex': labelIndex,
rafael-xmr marked this conversation as resolved.
Show resolved Hide resolved
'isUsed': isUsed,
'txCount': txCount,
'name': name,
'balance': balance,
'type': type.toString(),
'labelHex': labelHex,
'tweak': tweak,
});
}

class LitecoinMWEBAddressRecord extends BaseBitcoinAddressRecord {
LitecoinMWEBAddressRecord(
super.address, {
required super.index,
super.isHidden,
super.isChange = false,
super.txCount = 0,
super.balance = 0,
super.name = '',
super.isUsed = false,
BasedUtxoNetwork? network,
super.type = SegwitAddresType.mweb,
});

factory LitecoinMWEBAddressRecord.fromJSON(String jsonSource) {
final decoded = json.decode(jsonSource) as Map;

return LitecoinMWEBAddressRecord(
decoded['address'] as String,
index: decoded['index'] 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,
network: (decoded['network'] as String?) == null
? network
: BasedUtxoNetwork.fromName(decoded['network'] as String),
silentPaymentTweak: decoded['silent_payment_tweak'] as String?,
rafael-xmr marked this conversation as resolved.
Show resolved Hide resolved
type: decoded['type'] != null && decoded['type'] != ''
? BitcoinAddressType.values
.firstWhere((type) => type.toString() == decoded['type'] as String)
: SilentPaymentsAddresType.p2sp,
);
}

final String? silentPaymentTweak;

@override
String toJSON() => json.encode({
'address': address,
'index': index,
'isHidden': isHidden,
'isChange': isChange,
'isUsed': isUsed,
'txCount': txCount,
'name': name,
'balance': balance,
'type': type.toString(),
'network': network?.value,
'silent_payment_tweak': silentPaymentTweak,
});

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is BitcoinAddressRecord &&
other.address == address &&
other.index == index &&
other.type == type;
}

@override
int get hashCode => address.hashCode ^ index.hashCode ^ type.hashCode;
}
Loading
Loading