CakeWallet/cw_bitcoin/lib/bitcoin_wallet_addresses.dart

482 lines
16 KiB
Dart
Raw Normal View History

import 'dart:convert';
import 'package:collection/collection.dart';
Btc address types (#1263) * inital migration changes * feat: rest of changes * minor fix [skip ci] * fix: P2wshAddress & wallet address index * fix: address review comments * fix: address type restore * feat: add testnet * Fix review comments Remove bitcoin_base from cw_core * Fix address not matching selected type on start * remove un-necessary parameter [skip ci] * Remove bitcoin specific code from main lib Fix possible runtime exception from list wrong access * Minor fix * fix: fixes for Testnet * fix: bitcoin receive option dependency breaks monerocom * Fix issues when building Monero.com * feat: Transaction Builder changes * fix: discover addresses, testnet restoring, duplicate unspent coins, and taproot address vs schnorr sig tweak * fix: remove print * feat: improve error when failed broadcast response * feat: create fish shell env script * fix: unmodifiable maps * fix: build * fix: build * fix: computed observable side effect bug * feat: add nix script for android build_all * fix: wrong keypairs used for signing * fix: wrong addresses when using fromScriptPubKey scripts * fix(actual commit): testnet tx expanded + wrong addresses when using fromScriptPubKey scripts (update bitcoin_base deps) * fix: self-send [skip ci] * fix: p2wsh * fix: testnet fees * New versions * Update macos build number Minor UI fix * fix: use new bitcoin_base ref, fix tx list wrong hex value & refactor hidden vs hd use - if always use sideHd for isHidden, it is easier to simplify the functions instead of passing both which can be error prone - (ps: now this could probably be changed, for example from isHidden to isChange since with address list we now see "hidden" addresses) * Fix if condition to handle litecoin case * fix: self-send, change address was always making direction incoming * refactor: improve estimation function, add more inputs if balance missing * fix: new bitcoin_base update, fixes script issues * Update evm chain wallet service arguments * Fix translation [skip ci] * Fix translation [skip ci] * Update strings_fr.arb [skip ci] * fix: async isChange function not being awaited, refactor to reduce looping into a single place * fix: _address vs address, missing p2sh * fix: minor mistake in storing p2sh page type [skip ci] * refactor: use already matched addresses property * feat: improved perfomance for fetching transaction histories * feat: continue perfomance change, improve address discovery only to last address by type with history * fix: make sure transaction list is sorted by date * refactor: isTestnet only for bitcoin * fix: walletInfo type null case * fix: deprecated p2pk * refactor: make condition more readable * refactor: remove unnecessary Str variant * refactor: make condition more readable * fix: infinite loop possible * Revert removing isTestnet from other wallets [skip ci] * refactor: rename addresses when matched by receive type * Make the beta build [skip ci] Remove app_env.fish --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
2024-02-23 13:13:30 -03:00
import 'package:bitcoin_base/bitcoin_base.dart';
2024-11-04 19:29:25 -03:00
import 'package:blockchain_utils/blockchain_utils.dart';
2024-11-07 13:01:32 -03:00
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/seedbyte_types.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart';
part 'bitcoin_wallet_addresses.g.dart';
CW-432-Add-Bitcoin-Cash-BCH (#1041) * initial commit * creating and restoring a wallet * [skip ci] add transaction priority * fix send and unspent screen * fix transaction priority type * replace Unspend with BitcoinUnspent * add transaction creation * fix transaction details screen * minor fix * fix create side wallet * basic transaction creation flow * fix fiat amount calculation * edit wallet * minor fix * fix address book parsing * merge commit fixes * minor fixes * Update gradle.properties * fix bch unspent coins * minor fix * fix BitcoinCashTransactionPriority * Fetch tags first before switching to one of them * Update build_haven.sh * Update build_haven.sh * Update build_haven.sh * Update build_haven.sh * update transaction build function * Update build_haven.sh * add ability to rename and delete * fix address format * Update pubspec.lock * Revert "fix address format" This reverts commit 1549bf4d8c3bdb0addbd6e3c5f049ebc3799ff8f. * fix address format for exange * restore from qr * Update configure.dart * [skip ci] minor fix * fix default fee rate * Update onramper_buy_provider.dart * Update wallet_address_list_view_model.dart * PR comments fixes * Update exchange_view_model.dart * fix merge conflict * Update address_validator.dart * merge fixes * update initialMigrationVersion * move cw_bitbox to Cake tech * PR fixes * PR fixes * Fix configure.dart brackets * update the new version text after macos * dummy change to run workflow * Fix Nano restore from QR issue Fix Conflicts with main * PR fixes * Update app_config.sh --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
2023-10-13 01:50:16 +03:00
class BitcoinWalletAddresses = BitcoinWalletAddressesBase with _$BitcoinWalletAddresses;
CW-432-Add-Bitcoin-Cash-BCH (#1041) * initial commit * creating and restoring a wallet * [skip ci] add transaction priority * fix send and unspent screen * fix transaction priority type * replace Unspend with BitcoinUnspent * add transaction creation * fix transaction details screen * minor fix * fix create side wallet * basic transaction creation flow * fix fiat amount calculation * edit wallet * minor fix * fix address book parsing * merge commit fixes * minor fixes * Update gradle.properties * fix bch unspent coins * minor fix * fix BitcoinCashTransactionPriority * Fetch tags first before switching to one of them * Update build_haven.sh * Update build_haven.sh * Update build_haven.sh * Update build_haven.sh * update transaction build function * Update build_haven.sh * add ability to rename and delete * fix address format * Update pubspec.lock * Revert "fix address format" This reverts commit 1549bf4d8c3bdb0addbd6e3c5f049ebc3799ff8f. * fix address format for exange * restore from qr * Update configure.dart * [skip ci] minor fix * fix default fee rate * Update onramper_buy_provider.dart * Update wallet_address_list_view_model.dart * PR comments fixes * Update exchange_view_model.dart * fix merge conflict * Update address_validator.dart * merge fixes * update initialMigrationVersion * move cw_bitbox to Cake tech * PR fixes * PR fixes * Fix configure.dart brackets * update the new version text after macos * dummy change to run workflow * Fix Nano restore from QR issue Fix Conflicts with main * PR fixes * Update app_config.sh --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
2023-10-13 01:50:16 +03:00
abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
Btc address types (#1263) * inital migration changes * feat: rest of changes * minor fix [skip ci] * fix: P2wshAddress & wallet address index * fix: address review comments * fix: address type restore * feat: add testnet * Fix review comments Remove bitcoin_base from cw_core * Fix address not matching selected type on start * remove un-necessary parameter [skip ci] * Remove bitcoin specific code from main lib Fix possible runtime exception from list wrong access * Minor fix * fix: fixes for Testnet * fix: bitcoin receive option dependency breaks monerocom * Fix issues when building Monero.com * feat: Transaction Builder changes * fix: discover addresses, testnet restoring, duplicate unspent coins, and taproot address vs schnorr sig tweak * fix: remove print * feat: improve error when failed broadcast response * feat: create fish shell env script * fix: unmodifiable maps * fix: build * fix: build * fix: computed observable side effect bug * feat: add nix script for android build_all * fix: wrong keypairs used for signing * fix: wrong addresses when using fromScriptPubKey scripts * fix(actual commit): testnet tx expanded + wrong addresses when using fromScriptPubKey scripts (update bitcoin_base deps) * fix: self-send [skip ci] * fix: p2wsh * fix: testnet fees * New versions * Update macos build number Minor UI fix * fix: use new bitcoin_base ref, fix tx list wrong hex value & refactor hidden vs hd use - if always use sideHd for isHidden, it is easier to simplify the functions instead of passing both which can be error prone - (ps: now this could probably be changed, for example from isHidden to isChange since with address list we now see "hidden" addresses) * Fix if condition to handle litecoin case * fix: self-send, change address was always making direction incoming * refactor: improve estimation function, add more inputs if balance missing * fix: new bitcoin_base update, fixes script issues * Update evm chain wallet service arguments * Fix translation [skip ci] * Fix translation [skip ci] * Update strings_fr.arb [skip ci] * fix: async isChange function not being awaited, refactor to reduce looping into a single place * fix: _address vs address, missing p2sh * fix: minor mistake in storing p2sh page type [skip ci] * refactor: use already matched addresses property * feat: improved perfomance for fetching transaction histories * feat: continue perfomance change, improve address discovery only to last address by type with history * fix: make sure transaction list is sorted by date * refactor: isTestnet only for bitcoin * fix: walletInfo type null case * fix: deprecated p2pk * refactor: make condition more readable * refactor: remove unnecessary Str variant * refactor: make condition more readable * fix: infinite loop possible * Revert removing isTestnet from other wallets [skip ci] * refactor: rename addresses when matched by receive type * Make the beta build [skip ci] Remove app_env.fish --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
2024-02-23 13:13:30 -03:00
BitcoinWalletAddressesBase(
WalletInfo walletInfo, {
2025-01-08 09:41:21 -03:00
required super.hdWallets,
Btc address types (#1263) * inital migration changes * feat: rest of changes * minor fix [skip ci] * fix: P2wshAddress & wallet address index * fix: address review comments * fix: address type restore * feat: add testnet * Fix review comments Remove bitcoin_base from cw_core * Fix address not matching selected type on start * remove un-necessary parameter [skip ci] * Remove bitcoin specific code from main lib Fix possible runtime exception from list wrong access * Minor fix * fix: fixes for Testnet * fix: bitcoin receive option dependency breaks monerocom * Fix issues when building Monero.com * feat: Transaction Builder changes * fix: discover addresses, testnet restoring, duplicate unspent coins, and taproot address vs schnorr sig tweak * fix: remove print * feat: improve error when failed broadcast response * feat: create fish shell env script * fix: unmodifiable maps * fix: build * fix: build * fix: computed observable side effect bug * feat: add nix script for android build_all * fix: wrong keypairs used for signing * fix: wrong addresses when using fromScriptPubKey scripts * fix(actual commit): testnet tx expanded + wrong addresses when using fromScriptPubKey scripts (update bitcoin_base deps) * fix: self-send [skip ci] * fix: p2wsh * fix: testnet fees * New versions * Update macos build number Minor UI fix * fix: use new bitcoin_base ref, fix tx list wrong hex value & refactor hidden vs hd use - if always use sideHd for isHidden, it is easier to simplify the functions instead of passing both which can be error prone - (ps: now this could probably be changed, for example from isHidden to isChange since with address list we now see "hidden" addresses) * Fix if condition to handle litecoin case * fix: self-send, change address was always making direction incoming * refactor: improve estimation function, add more inputs if balance missing * fix: new bitcoin_base update, fixes script issues * Update evm chain wallet service arguments * Fix translation [skip ci] * Fix translation [skip ci] * Update strings_fr.arb [skip ci] * fix: async isChange function not being awaited, refactor to reduce looping into a single place * fix: _address vs address, missing p2sh * fix: minor mistake in storing p2sh page type [skip ci] * refactor: use already matched addresses property * feat: improved perfomance for fetching transaction histories * feat: continue perfomance change, improve address discovery only to last address by type with history * fix: make sure transaction list is sorted by date * refactor: isTestnet only for bitcoin * fix: walletInfo type null case * fix: deprecated p2pk * refactor: make condition more readable * refactor: remove unnecessary Str variant * refactor: make condition more readable * fix: infinite loop possible * Revert removing isTestnet from other wallets [skip ci] * refactor: rename addresses when matched by receive type * Make the beta build [skip ci] Remove app_env.fish --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
2024-02-23 13:13:30 -03:00
required super.network,
required super.isHardwareWallet,
super.initialAddressesRecords,
super.initialActiveAddressIndex,
super.initialAddressPageType,
2025-02-17 16:56:46 -03:00
this.loadedFromNewSnapshot = false,
2024-11-07 13:01:32 -03:00
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
List<BitcoinReceivedSPAddressRecord>? initialReceivedSPAddresses,
}) : silentPaymentAddresses = ObservableList<BitcoinSilentPaymentAddressRecord>.of(
(initialSilentAddresses ?? []).toSet(),
),
receivedSPAddresses = ObservableList<BitcoinReceivedSPAddressRecord>.of(
(initialReceivedSPAddresses ?? []).toSet(),
),
super(walletInfo) {
silentPaymentWallet = SilentPaymentOwner.fromBip32(hdWallet);
2024-11-16 14:53:00 -03:00
silentPaymentWallets = [silentPaymentWallet!];
2024-11-07 13:01:32 -03:00
}
2025-02-17 16:56:46 -03:00
final bool loadedFromNewSnapshot;
2025-03-13 16:50:03 -03:00
static const _OLD_SP_PATH = "m/352'/1'/0'/#'/0";
2025-02-17 16:56:46 -03:00
// NOTE: ordered in priority: eg. p2wpkh always first, most used address, etc.
2025-01-24 17:37:57 -03:00
@override
final walletAddressTypes = [
2025-01-21 14:02:01 -03:00
SegwitAddressType.p2wpkh,
2025-04-22 18:47:13 -03:00
SegwitAddressType.p2tr,
P2shAddressType.p2wpkhInP2sh,
P2pkhAddressType.p2pkh,
SegwitAddressType.p2wsh,
2025-01-21 14:02:01 -03:00
];
2024-11-07 13:01:32 -03:00
@observable
2024-11-16 14:53:00 -03:00
SilentPaymentOwner? silentPaymentWallet;
2024-11-07 13:01:32 -03:00
final ObservableList<BitcoinSilentPaymentAddressRecord> silentPaymentAddresses;
final ObservableList<BitcoinReceivedSPAddressRecord> receivedSPAddresses;
2024-11-16 14:53:00 -03:00
@observable
List<SilentPaymentOwner> silentPaymentWallets = [];
2024-11-07 13:01:32 -03:00
@observable
BitcoinSilentPaymentAddressRecord? activeSilentAddress;
2025-02-17 18:40:45 -03:00
@observable
String? scanningSilentAddress;
2025-02-17 16:56:46 -03:00
@observable
int silentAddressIndex = 0;
@override
Future<void> init() async {
2025-03-13 16:50:03 -03:00
if (silentPaymentAddresses.isEmpty) generateInitialSPAddresses();
2025-02-25 11:40:28 -03:00
super.init();
}
2025-01-14 17:57:59 -03:00
@action
2025-02-17 16:56:46 -03:00
Future<void> generateInitialSPAddresses() async {
2025-02-25 11:40:28 -03:00
final addAddresses = silentPaymentAddresses.isEmpty;
2025-02-17 16:56:46 -03:00
// Only initiate these old addresses if restoring a wallet and possibly wants the older cake derivation path
2025-02-25 11:40:28 -03:00
if (walletInfo.isRecovery || silentPaymentAddresses.length > 2) {
2025-03-13 16:50:03 -03:00
final oldScanPath = Bip32PathParser.parse(_OLD_SP_PATH.replaceFirst("#", "1"));
final oldSpendPath = Bip32PathParser.parse(_OLD_SP_PATH.replaceFirst("#", "0"));
2025-01-14 17:57:59 -03:00
final oldSilentPaymentWallet = SilentPaymentOwner.fromPrivateKeys(
b_scan: ECPrivate(hdWallet.derive(oldScanPath).privateKey),
b_spend: ECPrivate(hdWallet.derive(oldSpendPath).privateKey),
);
silentPaymentWallets.add(oldSilentPaymentWallet);
2025-02-25 11:40:28 -03:00
if (addAddresses)
silentPaymentAddresses.addAll(
[
BitcoinSilentPaymentAddressRecord(
oldSilentPaymentWallet.toString(),
2025-04-18 08:49:10 -03:00
network: network,
2025-02-25 11:40:28 -03:00
labelIndex: 0,
name: "",
type: SilentPaymentsAddresType.p2sp,
derivationPath: oldSpendPath.toString(),
isHidden: true,
isChange: false,
),
BitcoinSilentPaymentAddressRecord(
oldSilentPaymentWallet.toLabeledSilentPaymentAddress(0).toString(),
2025-04-18 08:49:10 -03:00
network: network,
2025-02-25 11:40:28 -03:00
name: "",
labelIndex: 0,
labelHex: BytesUtils.toHexString(oldSilentPaymentWallet.generateLabel(0)),
type: SilentPaymentsAddresType.p2sp,
derivationPath: oldSpendPath.toString(),
isHidden: true,
isChange: true,
),
],
);
2025-01-14 17:57:59 -03:00
}
2025-02-25 11:40:28 -03:00
if (addAddresses)
silentPaymentAddresses.addAll([
BitcoinSilentPaymentAddressRecord(
silentPaymentWallet!.toString(),
2025-04-18 08:49:10 -03:00
network: network,
2025-02-25 11:40:28 -03:00
labelIndex: 0,
name: "",
type: SilentPaymentsAddresType.p2sp,
isChange: false,
),
BitcoinSilentPaymentAddressRecord(
silentPaymentWallet!.toLabeledSilentPaymentAddress(0).toString(),
2025-04-18 08:49:10 -03:00
network: network,
2025-02-25 11:40:28 -03:00
name: "",
labelIndex: 0,
labelHex: BytesUtils.toHexString(silentPaymentWallet!.generateLabel(0)),
type: SilentPaymentsAddresType.p2sp,
isChange: true,
),
]);
2025-02-17 16:56:46 -03:00
}
2025-01-14 17:57:59 -03:00
@override
@action
void resetActiveAddress() {
if (activeSilentAddress != null &&
(activeSilentAddress!.isChange || activeSilentAddress!.isHidden)) {
try {
activeSilentAddress = silentPaymentAddresses.firstWhere(
(addressRecord) =>
addressRecord.labelIndex == silentAddressIndex &&
!addressRecord.isChange &&
!addressRecord.isHidden,
);
return;
} catch (_) {}
}
super.resetActiveAddress();
}
2024-11-07 13:01:32 -03:00
@override
@computed
String get address {
if (addressPageType == SilentPaymentsAddresType.p2sp) {
if (activeSilentAddress != null) {
return activeSilentAddress!.address;
2024-11-07 13:01:32 -03:00
}
return silentPaymentWallet.toString();
}
return super.address;
}
@override
set address(String addr) {
if (addressPageType == SilentPaymentsAddresType.p2sp) {
final selected = silentPaymentAddresses
.firstWhereOrNull((addressRecord) => addressRecord.address == addr) ??
silentPaymentAddresses[0];
2024-11-07 13:01:32 -03:00
activeSilentAddress = selected;
if (!selected.isChange) {
silentAddressIndex = selected.labelIndex;
2024-11-07 13:01:32 -03:00
}
2024-11-07 13:01:32 -03:00
return;
}
super.address = addr;
}
@override
@action
2025-02-17 16:56:46 -03:00
BaseBitcoinAddressRecord generateNewAddress({String label = '', bool? isHidden}) {
2024-11-07 13:01:32 -03:00
if (addressPageType == SilentPaymentsAddresType.p2sp) {
2025-02-17 16:56:46 -03:00
return generateNewSPAddress(label: label, isHidden: isHidden);
}
return super.generateNewAddress(label: label);
}
@action
BaseBitcoinAddressRecord generateNewSPAddress({String label = '', bool? isHidden}) {
isHidden ??= false;
final existingSilentPaymentAddresses = silentPaymentAddresses
.where(
(a) => !a.isChange && (isHidden == true ? a.isHidden : !a.isHidden),
)
.toList();
final nextSPLabelIndex = existingSilentPaymentAddresses.length;
late BitcoinSilentPaymentAddressRecord address;
if (isHidden == true) {
2025-03-13 16:50:03 -03:00
final oldScanPath = Bip32PathParser.parse(_OLD_SP_PATH.replaceFirst("#", "1"));
final oldSpendPath = Bip32PathParser.parse(_OLD_SP_PATH.replaceFirst("#", "0"));
2025-02-17 16:56:46 -03:00
final oldSilentPaymentWallet = SilentPaymentOwner.fromPrivateKeys(
b_scan: ECPrivate(hdWallet.derive(oldScanPath).privateKey),
b_spend: ECPrivate(hdWallet.derive(oldSpendPath).privateKey),
);
address = BitcoinSilentPaymentAddressRecord(
oldSilentPaymentWallet.toLabeledSilentPaymentAddress(nextSPLabelIndex).toString(),
2025-04-18 08:49:10 -03:00
network: network,
2025-02-17 16:56:46 -03:00
labelIndex: nextSPLabelIndex,
derivationPath: oldSpendPath.toString(),
name: label,
labelHex: BytesUtils.toHexString(oldSilentPaymentWallet.generateLabel(nextSPLabelIndex)),
type: SilentPaymentsAddresType.p2sp,
isChange: false,
isHidden: true,
);
} else {
address = BitcoinSilentPaymentAddressRecord(
silentPaymentWallet!.toLabeledSilentPaymentAddress(nextSPLabelIndex).toString(),
2025-04-18 08:49:10 -03:00
network: network,
labelIndex: nextSPLabelIndex,
2024-11-07 13:01:32 -03:00
name: label,
labelHex: BytesUtils.toHexString(silentPaymentWallet!.generateLabel(nextSPLabelIndex)),
2025-01-07 19:26:48 -03:00
type: SilentPaymentsAddresType.p2sp,
isChange: false,
2025-02-17 16:56:46 -03:00
isHidden: false,
2024-11-07 13:01:32 -03:00
);
}
2025-02-17 16:56:46 -03:00
silentPaymentAddresses.add(address);
return address;
2024-11-07 13:01:32 -03:00
}
2025-01-27 20:08:06 -03:00
@override
@action
Future<void> updateAddressesInBox() async {
// receiveAddressesMapped.entries.forEach((e) {
// final addressType = e.key;
// final addresses = e.value;
// for (final addr in addresses) {
// if (getIsReceive(addr)) {
// allAddressesMap[addr.address] = addr.name;
// final isCurrentType = addr.type == addressPageType;
// if (addressType == SilentPaymentsAddresType.p2sp) {
// final addressString =
// '${addr.address.substring(0, 9 + 5)}...${addr.address.substring(addr.address.length - 9, addr.address.length)}';
// if (!isCurrentType) {
// addressesMap[addr.address] = addr.name.isEmpty
// ? "Silent Payments" + ': $addressString'
// : "Silent Payments - " + addr.name + ': $addressString';
// } else {
// addressesMap[address] = 'Active - Silent Payments' + ': $addressString';
// }
// // Silent Payments address don't break the loop because all are used
// // break;
// } else {
// if (!isCurrentType) {
// addressesMap[addr.address] = '${addressType.value.toUpperCase()}: ${addr.address}';
// } else {
// addressesMap[address] = 'Active - ${addressType.value.toUpperCase()}: $address';
// }
// // Break the loop, already got the firt unused address
// break;
// }
// }
// }
// });
2025-01-27 20:08:06 -03:00
await saveAddressesInBox();
}
2024-11-07 13:01:32 -03:00
@override
@action
void updateAddress(String address, String label) {
super.updateAddress(address, label);
BaseBitcoinAddressRecord? foundAddress;
silentPaymentAddresses.forEach((addressRecord) {
if (addressRecord.address == address) {
foundAddress = addressRecord;
}
});
if (foundAddress != null) {
foundAddress!.setNewName(label);
final index =
silentPaymentAddresses.indexOf(foundAddress as BitcoinSilentPaymentAddressRecord);
silentPaymentAddresses.remove(foundAddress);
silentPaymentAddresses.insert(index, foundAddress as BitcoinSilentPaymentAddressRecord);
}
}
@action
void addSilentAddresses(Iterable<BitcoinSilentPaymentAddressRecord> addresses) {
final addressesSet = this.silentPaymentAddresses.toSet();
addressesSet.addAll(addresses);
this.silentPaymentAddresses.clear();
this.silentPaymentAddresses.addAll(addressesSet);
}
2024-11-16 14:53:00 -03:00
@action
void addReceivedSPAddresses(Iterable<BitcoinReceivedSPAddressRecord> addresses) {
final addressesSet = this.receivedSPAddresses.toSet();
addressesSet.addAll(addresses);
this.receivedSPAddresses.clear();
this.receivedSPAddresses.addAll(addressesSet);
}
2024-11-07 13:01:32 -03:00
@action
void deleteSilentPaymentAddress(String address) {
2025-02-17 16:56:46 -03:00
final addressRecord = silentPaymentAddresses.firstWhereOrNull(
2025-02-18 15:51:28 -03:00
(addressRecord) => addressRecord.address == address,
2025-02-17 16:56:46 -03:00
);
if (addressRecord == null) {
return;
}
2024-11-07 13:01:32 -03:00
silentPaymentAddresses.remove(addressRecord);
}
2025-02-25 11:40:28 -03:00
Map<String, int> getLabels(List<String> addresses) {
2025-01-27 20:08:06 -03:00
final labels = <String, int>{};
2024-11-07 13:01:32 -03:00
for (int i = 0; i < silentPaymentAddresses.length; i++) {
final silentAddressRecord = silentPaymentAddresses[i];
if (!addresses.any((addr) => addr.startsWith(silentAddressRecord.address.substring(0, 9)))) {
2025-02-17 18:40:45 -03:00
continue;
}
2024-11-07 13:01:32 -03:00
final silentPaymentTweak = silentAddressRecord.labelHex;
2025-01-27 20:08:06 -03:00
if (silentPaymentTweak != null) {
labels[silentPaymentTweak] = silentAddressRecord.labelIndex;
2024-11-07 13:01:32 -03:00
}
}
return labels;
}
2025-02-17 18:40:45 -03:00
List<String> getUsableSilentPaymentAddresses() {
2025-03-13 16:50:03 -03:00
final oldSpendPath = Bip32PathParser.parse(_OLD_SP_PATH.replaceFirst("#", "0"));
2025-02-17 18:40:45 -03:00
final primaryAddress = silentPaymentAddresses.firstWhere(
(addressRecord) =>
!addressRecord.isChange &&
addressRecord.labelIndex == 0 &&
addressRecord.indexedDerivationPath != oldSpendPath.toString(),
2025-02-17 18:40:45 -03:00
);
2025-02-18 15:51:28 -03:00
final list = [primaryAddress.address];
final hiddenAddress = silentPaymentAddresses.firstWhereOrNull(
2025-02-17 18:40:45 -03:00
(addressRecord) =>
!addressRecord.isChange &&
addressRecord.labelIndex == 0 &&
addressRecord.indexedDerivationPath == oldSpendPath.toString(),
2025-02-17 18:40:45 -03:00
);
2025-02-18 15:51:28 -03:00
// Do it like this to keep in order,
// the primary address always first in the list
if (hiddenAddress != null) {
list.add(hiddenAddress.address);
}
return list;
2025-02-17 18:40:45 -03:00
}
@action
void setSilentPaymentsScanWallet(String address) {
scanningSilentAddress = address;
}
2024-11-07 13:01:32 -03:00
Map<String, dynamic> toJson() {
final json = super.toJson();
json['silentPaymentAddresses'] =
silentPaymentAddresses.map((address) => address.toJSON()).toList();
json['receivedSPAddresses'] = receivedSPAddresses.map((address) => address.toJSON()).toList();
json['silentAddressIndex'] = silentAddressIndex.toString();
2025-02-17 16:56:46 -03:00
json['loadedFromNewSnapshot'] = true;
2024-11-07 13:01:32 -03:00
return json;
}
static Map<String, dynamic> fromSnapshot(Map<dynamic, dynamic> data) {
final electrumSnapshot = ElectrumWalletAddressesBase.fromSnapshot(data);
final silentAddressesTmp = data['silent_addresses'] as List? ?? <Object>[];
final silentPaymentAddresses = <BitcoinReceivedSPAddressRecord>[];
final receivedSPAddresses = <BitcoinSilentPaymentAddressRecord>[];
silentAddressesTmp.whereType<String>().forEach((j) {
final decoded = json.decode(j) as Map;
if (decoded['tweak'] != null || decoded['silent_payment_tweak'] != null) {
silentPaymentAddresses.add(BitcoinReceivedSPAddressRecord.fromJSON(j));
} else {
receivedSPAddresses.add(BitcoinSilentPaymentAddressRecord.fromJSON(j));
}
});
var silentAddressIndex = 0;
try {
silentAddressIndex = int.parse(data['silent_address_index'] as String? ?? '0');
} catch (_) {}
return {
'allAddresses': electrumSnapshot["addresses"],
'addressPageType': data['address_page_type'] as String?,
'receiveAddressIndexByType': electrumSnapshot["receiveAddressIndexByType"],
'changeAddressIndexByType': electrumSnapshot["changeAddressIndexByType"],
'silentPaymentAddresses': silentPaymentAddresses,
'receivedSPAddresses': receivedSPAddresses,
'silentAddressIndex': silentAddressIndex,
};
}
static BitcoinWalletAddresses fromJson(
2025-02-18 15:51:28 -03:00
Map<String, dynamic> snp,
WalletInfo walletInfo, {
required Map<SeedBytesType, Bip32Slip10Secp256k1> hdWallets,
required BasedUtxoNetwork network,
required bool isHardwareWallet,
}) {
final electrumJson = ElectrumWalletAddressesBase.fromJson(
snp,
walletInfo,
hdWallets: hdWallets,
network: network,
isHardwareWallet: isHardwareWallet,
);
2025-02-18 15:51:28 -03:00
final initialSilentAddresses = (snp['silentPaymentAddresses'] as List)
.map(
(address) => BitcoinSilentPaymentAddressRecord.fromJSON(address as String),
)
.toList();
2025-02-18 15:51:28 -03:00
final initialReceivedSPAddresses = (snp['receivedSPAddresses'] as List)
.map(
(address) => BitcoinReceivedSPAddressRecord.fromJSON(address as String),
)
.toList();
return BitcoinWalletAddresses(
walletInfo,
hdWallets: hdWallets,
network: network,
isHardwareWallet: isHardwareWallet,
initialAddressesRecords: electrumJson.addressesRecords,
initialAddressPageType: electrumJson.addressPageType,
initialActiveAddressIndex: electrumJson.activeIndexByType,
initialSilentAddresses: initialSilentAddresses,
initialReceivedSPAddresses: initialReceivedSPAddresses,
2025-02-18 15:51:28 -03:00
loadedFromNewSnapshot: snp['loadedFromNewSnapshot'] as bool? ?? false,
);
}
CW-432-Add-Bitcoin-Cash-BCH (#1041) * initial commit * creating and restoring a wallet * [skip ci] add transaction priority * fix send and unspent screen * fix transaction priority type * replace Unspend with BitcoinUnspent * add transaction creation * fix transaction details screen * minor fix * fix create side wallet * basic transaction creation flow * fix fiat amount calculation * edit wallet * minor fix * fix address book parsing * merge commit fixes * minor fixes * Update gradle.properties * fix bch unspent coins * minor fix * fix BitcoinCashTransactionPriority * Fetch tags first before switching to one of them * Update build_haven.sh * Update build_haven.sh * Update build_haven.sh * Update build_haven.sh * update transaction build function * Update build_haven.sh * add ability to rename and delete * fix address format * Update pubspec.lock * Revert "fix address format" This reverts commit 1549bf4d8c3bdb0addbd6e3c5f049ebc3799ff8f. * fix address format for exange * restore from qr * Update configure.dart * [skip ci] minor fix * fix default fee rate * Update onramper_buy_provider.dart * Update wallet_address_list_view_model.dart * PR comments fixes * Update exchange_view_model.dart * fix merge conflict * Update address_validator.dart * merge fixes * update initialMigrationVersion * move cw_bitbox to Cake tech * PR fixes * PR fixes * Fix configure.dart brackets * update the new version text after macos * dummy change to run workflow * Fix Nano restore from QR issue Fix Conflicts with main * PR fixes * Update app_config.sh --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
2023-10-13 01:50:16 +03:00
}