mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-22 10:45:08 +00:00
feat: begin delegated scan, big refactors
This commit is contained in:
parent
b8ffd47f06
commit
e47846bc7d
50 changed files with 649 additions and 473 deletions
|
@ -6,13 +6,12 @@ abstract class BaseBitcoinAddressRecord {
|
|||
BaseBitcoinAddressRecord(
|
||||
this.address, {
|
||||
required this.index,
|
||||
this.isHidden = false,
|
||||
this.isChange = false,
|
||||
int txCount = 0,
|
||||
int balance = 0,
|
||||
String name = '',
|
||||
bool isUsed = false,
|
||||
required this.type,
|
||||
required this.network,
|
||||
}) : _txCount = txCount,
|
||||
_balance = balance,
|
||||
_name = name,
|
||||
|
@ -22,13 +21,12 @@ abstract class BaseBitcoinAddressRecord {
|
|||
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
|
||||
|
||||
final String address;
|
||||
bool isHidden;
|
||||
bool isChange;
|
||||
final int index;
|
||||
int _txCount;
|
||||
int _balance;
|
||||
String _name;
|
||||
bool _isUsed;
|
||||
BasedUtxoNetwork? network;
|
||||
|
||||
int get txCount => _txCount;
|
||||
|
||||
|
@ -56,24 +54,29 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
BitcoinAddressRecord(
|
||||
super.address, {
|
||||
required super.index,
|
||||
super.isHidden = false,
|
||||
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 && 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,
|
||||
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? ?? '',
|
||||
|
@ -83,23 +86,16 @@ 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,
|
||||
'isHidden': isHidden,
|
||||
'isChange': isChange,
|
||||
'isUsed': isUsed,
|
||||
'txCount': txCount,
|
||||
'name': name,
|
||||
|
@ -110,18 +106,23 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
|||
}
|
||||
|
||||
class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
||||
int get labelIndex => index;
|
||||
final String? labelHex;
|
||||
|
||||
BitcoinSilentPaymentAddressRecord(
|
||||
super.address, {
|
||||
required super.index,
|
||||
super.isHidden = false,
|
||||
required int labelIndex,
|
||||
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,
|
||||
this.labelHex,
|
||||
}) : super(index: labelIndex, isChange: labelIndex == 0) {
|
||||
if (labelIndex != 1 && labelHex == null) {
|
||||
throw ArgumentError('label must be provided for silent address index > 0');
|
||||
}
|
||||
}
|
||||
|
||||
factory BitcoinSilentPaymentAddressRecord.fromJSON(String jsonSource,
|
||||
{BasedUtxoNetwork? network}) {
|
||||
|
@ -129,36 +130,68 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {
|
|||
|
||||
return BitcoinSilentPaymentAddressRecord(
|
||||
decoded['address'] as String,
|
||||
index: decoded['index'] as int,
|
||||
isHidden: decoded['isHidden'] as bool? ?? false,
|
||||
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?,
|
||||
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,
|
||||
'index': index,
|
||||
'isHidden': isHidden,
|
||||
'labelIndex': labelIndex,
|
||||
'isUsed': isUsed,
|
||||
'txCount': txCount,
|
||||
'name': name,
|
||||
'balance': balance,
|
||||
'type': type.toString(),
|
||||
'network': network?.value,
|
||||
'silent_payment_tweak': silentPaymentTweak,
|
||||
'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.type = SegwitAddresType.p2tr,
|
||||
super.labelHex,
|
||||
});
|
||||
|
||||
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,
|
||||
isUsed: decoded['isUsed'] as bool? ?? false,
|
||||
txCount: decoded['txCount'] as int? ?? 0,
|
||||
name: decoded['name'] as String? ?? '',
|
||||
balance: decoded['balance'] as int? ?? 0,
|
||||
labelHex: decoded['label'] as String?,
|
||||
spendKey: ECPrivate.fromHex(decoded['spendKey'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toJSON() => json.encode({
|
||||
'address': address,
|
||||
'labelIndex': labelIndex,
|
||||
'isUsed': isUsed,
|
||||
'txCount': txCount,
|
||||
'name': name,
|
||||
'balance': balance,
|
||||
'type': type.toString(),
|
||||
'labelHex': labelHex,
|
||||
'spend_key': spendKey.toString(),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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,16 +21,13 @@ class BitcoinHardwareWalletService {
|
|||
|
||||
for (final i in indexRange) {
|
||||
final derivationPath = "m/84'/0'/$i'";
|
||||
final xpub =
|
||||
await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
|
||||
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);
|
||||
|
||||
accounts.add(HardwareAccountData(
|
||||
address: address,
|
||||
address: P2wpkhAddress.fromBip32(bip32: hd, account: i, index: 0)
|
||||
.toAddress(BitcoinNetwork.mainnet),
|
||||
accountIndex: i,
|
||||
derivationPath: derivationPath,
|
||||
masterFingerprint: masterFp,
|
||||
|
|
|
@ -26,42 +26,3 @@ class BitcoinUnspent extends Unspent {
|
|||
|
||||
final BaseBitcoinAddressRecord bitcoinAddressRecord;
|
||||
}
|
||||
|
||||
class BitcoinSilentPaymentsUnspent extends BitcoinUnspent {
|
||||
BitcoinSilentPaymentsUnspent(
|
||||
BitcoinSilentPaymentAddressRecord addressRecord,
|
||||
String hash,
|
||||
int value,
|
||||
int vout, {
|
||||
required this.silentPaymentTweak,
|
||||
required this.silentPaymentLabel,
|
||||
}) : super(addressRecord, hash, value, vout);
|
||||
|
||||
@override
|
||||
factory BitcoinSilentPaymentsUnspent.fromJSON(
|
||||
BitcoinSilentPaymentAddressRecord? address, Map<String, dynamic> json) =>
|
||||
BitcoinSilentPaymentsUnspent(
|
||||
address ?? BitcoinSilentPaymentAddressRecord.fromJSON(json['address_record'].toString()),
|
||||
json['tx_hash'] as String,
|
||||
json['value'] as int,
|
||||
json['tx_pos'] as int,
|
||||
silentPaymentTweak: json['silent_payment_tweak'] as String?,
|
||||
silentPaymentLabel: json['silent_payment_label'] as String?,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{
|
||||
'address_record': bitcoinAddressRecord.toJSON(),
|
||||
'tx_hash': hash,
|
||||
'value': value,
|
||||
'tx_pos': vout,
|
||||
'silent_payment_tweak': silentPaymentTweak,
|
||||
'silent_payment_label': silentPaymentLabel,
|
||||
};
|
||||
return json;
|
||||
}
|
||||
|
||||
String? silentPaymentTweak;
|
||||
String? silentPaymentLabel;
|
||||
}
|
||||
|
|
|
@ -61,16 +61,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
currency: networkParam == BitcoinNetwork.testnet
|
||||
? CryptoCurrency.tbtc
|
||||
: CryptoCurrency.btc,
|
||||
currency:
|
||||
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
|
||||
alwaysScan: alwaysScan,
|
||||
) {
|
||||
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
||||
// the sideHd derivation path = m/84'/0'/0'/1 (account 1, index unspecified here)
|
||||
// String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
||||
// String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
|
||||
// final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
||||
walletAddresses = BitcoinWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
|
@ -78,17 +72,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
initialSilentAddresses: initialSilentAddresses,
|
||||
initialSilentAddressIndex: initialSilentAddressIndex,
|
||||
mainHd: hd,
|
||||
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||
bip32: bip32,
|
||||
network: networkParam ?? network,
|
||||
masterHd:
|
||||
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
||||
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||
);
|
||||
|
||||
autorun((_) {
|
||||
this.walletAddresses.isEnabledAutoGenerateSubaddress =
|
||||
this.isEnabledAutoGenerateSubaddress;
|
||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -189,10 +178,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
walletInfo.derivationInfo ??= DerivationInfo();
|
||||
|
||||
// set the default if not present:
|
||||
walletInfo.derivationInfo!.derivationPath ??=
|
||||
snp?.derivationPath ?? electrum_path;
|
||||
walletInfo.derivationInfo!.derivationType ??=
|
||||
snp?.derivationType ?? DerivationType.electrum;
|
||||
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
|
||||
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
|
||||
|
||||
Uint8List? seedBytes = null;
|
||||
final mnemonic = keysData.mnemonic;
|
||||
|
@ -260,10 +247,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
||||
for (final utxo in utxos) {
|
||||
final rawTx =
|
||||
await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
||||
final publicKeyAndDerivationPath =
|
||||
publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
||||
final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
||||
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
||||
|
||||
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
||||
utxo: utxo.utxo,
|
||||
|
@ -275,8 +260,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
));
|
||||
}
|
||||
|
||||
final psbt = PSBTTransactionBuild(
|
||||
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
||||
final psbt =
|
||||
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
||||
|
||||
final rawHex = await _bitcoinLedgerApp!.signPsbt(psbt: psbt.psbt);
|
||||
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
||||
|
@ -286,17 +271,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
Future<String> signMessage(String message, {String? address = null}) async {
|
||||
if (walletInfo.isHardwareWallet) {
|
||||
final addressEntry = address != null
|
||||
? walletAddresses.allAddresses
|
||||
.firstWhere((element) => element.address == address)
|
||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
|
||||
: null;
|
||||
final index = addressEntry?.index ?? 0;
|
||||
final isChange = addressEntry?.isHidden == true ? 1 : 0;
|
||||
final isChange = addressEntry?.isChange == true ? 1 : 0;
|
||||
final accountPath = walletInfo.derivationInfo?.derivationPath;
|
||||
final derivationPath =
|
||||
accountPath != null ? "$accountPath/$isChange/$index" : null;
|
||||
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
|
||||
|
||||
final signature = await _bitcoinLedgerApp!.signMessage(
|
||||
message: ascii.encode(message), signDerivationPath: derivationPath);
|
||||
final signature = await _bitcoinLedgerApp!
|
||||
.signMessage(message: ascii.encode(message), signDerivationPath: derivationPath);
|
||||
return base64Encode(signature);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:blockchain_utils/bip/bip/bip32/bip32.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
|
@ -12,8 +11,7 @@ class BitcoinWalletAddresses = BitcoinWalletAddressesBase with _$BitcoinWalletAd
|
|||
abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
|
||||
BitcoinWalletAddressesBase(
|
||||
WalletInfo walletInfo, {
|
||||
required super.mainHd,
|
||||
required super.sideHd,
|
||||
required super.bip32,
|
||||
required super.network,
|
||||
required super.isHardwareWallet,
|
||||
super.initialAddresses,
|
||||
|
@ -21,24 +19,33 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
super.initialChangeAddressIndex,
|
||||
super.initialSilentAddresses,
|
||||
super.initialSilentAddressIndex = 0,
|
||||
super.masterHd,
|
||||
}) : super(walletInfo);
|
||||
|
||||
@override
|
||||
String getAddress(
|
||||
{required int index, required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType}) {
|
||||
if (addressType == P2pkhAddressType.p2pkh)
|
||||
return generateP2PKHAddress(hd: hd, index: index, network: network);
|
||||
|
||||
if (addressType == SegwitAddresType.p2tr)
|
||||
return generateP2TRAddress(hd: hd, index: index, network: network);
|
||||
|
||||
if (addressType == SegwitAddresType.p2wsh)
|
||||
return generateP2WSHAddress(hd: hd, index: index, network: network);
|
||||
|
||||
if (addressType == P2shAddressType.p2wpkhInP2sh)
|
||||
return generateP2SHAddress(hd: hd, index: index, network: network);
|
||||
|
||||
return generateP2WPKHAddress(hd: hd, index: index, network: network);
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BitcoinAddressType addressType,
|
||||
}) {
|
||||
switch (addressType) {
|
||||
case P2pkhAddressType.p2pkh:
|
||||
return P2pkhAddress.fromBip32(account: account, bip32: hd, index: index);
|
||||
case SegwitAddresType.p2tr:
|
||||
return P2trAddress.fromBip32(account: account, bip32: hd, index: index);
|
||||
case SegwitAddresType.p2wsh:
|
||||
return P2wshAddress.fromBip32(account: account, bip32: hd, index: index);
|
||||
case P2shAddressType.p2wpkhInP2sh:
|
||||
return P2shAddress.fromBip32(
|
||||
account: account,
|
||||
bip32: hd,
|
||||
index: index,
|
||||
type: P2shAddressType.p2wpkhInP2sh,
|
||||
);
|
||||
case SegwitAddresType.p2wpkh:
|
||||
return P2wpkhAddress.fromBip32(account: account, bip32: hd, index: index);
|
||||
default:
|
||||
throw ArgumentError('Invalid address type');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,13 +317,38 @@ class ElectrumClient {
|
|||
Future<Map<String, dynamic>> getHeader({required int height}) async =>
|
||||
await call(method: 'blockchain.block.get_header', params: [height]) as Map<String, dynamic>;
|
||||
|
||||
BehaviorSubject<Object>? tweaksSubscribe({required int height, required int count}) {
|
||||
return subscribe<Object>(
|
||||
BehaviorSubject<Object>? tweaksSubscribe({required int height, required int count}) =>
|
||||
subscribe<Object>(
|
||||
id: 'blockchain.tweaks.subscribe',
|
||||
method: 'blockchain.tweaks.subscribe',
|
||||
params: [height, count, false],
|
||||
);
|
||||
}
|
||||
|
||||
Future<dynamic> tweaksRegister({
|
||||
required String secViewKey,
|
||||
required String pubSpendKey,
|
||||
List<int> labels = const [],
|
||||
}) =>
|
||||
call(
|
||||
method: 'blockchain.tweaks.subscribe',
|
||||
params: [secViewKey, pubSpendKey, labels],
|
||||
);
|
||||
|
||||
Future<dynamic> tweaksErase({required String pubSpendKey}) => call(
|
||||
method: 'blockchain.tweaks.erase',
|
||||
params: [pubSpendKey],
|
||||
);
|
||||
|
||||
BehaviorSubject<Object>? tweaksScan({required String pubSpendKey}) => subscribe<Object>(
|
||||
id: 'blockchain.tweaks.scan',
|
||||
method: 'blockchain.tweaks.scan',
|
||||
params: [pubSpendKey],
|
||||
);
|
||||
|
||||
Future<dynamic> tweaksGet({required String pubSpendKey}) => call(
|
||||
method: 'blockchain.tweaks.get',
|
||||
params: [pubSpendKey],
|
||||
);
|
||||
|
||||
Future<dynamic> getTweaks({required int height}) async =>
|
||||
await callWithTimeout(method: 'blockchain.tweaks.subscribe', params: [height, 1, false]);
|
||||
|
@ -527,6 +552,7 @@ class ElectrumClient {
|
|||
_tasks[method]?.subject?.add(params.last);
|
||||
break;
|
||||
case 'blockchain.tweaks.subscribe':
|
||||
case 'blockchain.tweaks.scan':
|
||||
final params = request['params'] as List<dynamic>;
|
||||
_tasks[_tasks.keys.first]?.subject?.add(params.last);
|
||||
break;
|
||||
|
|
|
@ -22,7 +22,7 @@ class ElectrumTransactionBundle {
|
|||
}
|
||||
|
||||
class ElectrumTransactionInfo extends TransactionInfo {
|
||||
List<BitcoinSilentPaymentsUnspent>? unspents;
|
||||
List<BitcoinUnspent>? unspents;
|
||||
bool isReceivedSilentPayment;
|
||||
|
||||
ElectrumTransactionInfo(
|
||||
|
@ -208,8 +208,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
outputAddresses.isEmpty ? [] : outputAddresses.map((e) => e.toString()).toList(),
|
||||
to: data['to'] as String?,
|
||||
unspents: unspents
|
||||
.map((unspent) =>
|
||||
BitcoinSilentPaymentsUnspent.fromJSON(null, unspent as Map<String, dynamic>))
|
||||
.map((unspent) => BitcoinUnspent.fromJSON(null, unspent as Map<String, dynamic>))
|
||||
.toList(),
|
||||
isReceivedSilentPayment: data['isReceivedSilentPayment'] as bool? ?? false,
|
||||
);
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'dart:io';
|
|||
import 'dart:isolate';
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
@ -23,7 +22,6 @@ import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
|||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:cw_bitcoin/exceptions.dart';
|
||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/get_height_by_date.dart';
|
||||
|
@ -52,10 +50,9 @@ part 'electrum_wallet.g.dart';
|
|||
|
||||
class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet;
|
||||
|
||||
abstract class ElectrumWalletBase extends WalletBase<
|
||||
ElectrumBalance,
|
||||
ElectrumTransactionHistory,
|
||||
ElectrumTransactionInfo> with Store, WalletKeysFile {
|
||||
abstract class ElectrumWalletBase
|
||||
extends WalletBase<ElectrumBalance, ElectrumTransactionHistory, ElectrumTransactionInfo>
|
||||
with Store, WalletKeysFile {
|
||||
ElectrumWalletBase({
|
||||
required String password,
|
||||
required WalletInfo walletInfo,
|
||||
|
@ -71,8 +68,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
ElectrumBalance? initialBalance,
|
||||
CryptoCurrency? currency,
|
||||
this.alwaysScan,
|
||||
}) : accountHD = getAccountHDWallet(
|
||||
currency, network, seedBytes, xpub, walletInfo.derivationInfo),
|
||||
}) : bip32 = getAccountHDWallet(currency, network, seedBytes, xpub, walletInfo.derivationInfo),
|
||||
syncStatus = NotConnectedSyncStatus(),
|
||||
_password = password,
|
||||
_feeRates = <int>[],
|
||||
|
@ -107,12 +103,8 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
sharedPrefs.complete(SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
static Bip32Slip10Secp256k1 getAccountHDWallet(
|
||||
CryptoCurrency? currency,
|
||||
BasedUtxoNetwork network,
|
||||
Uint8List? seedBytes,
|
||||
String? xpub,
|
||||
DerivationInfo? derivationInfo) {
|
||||
static Bip32Slip10Secp256k1 getAccountHDWallet(CryptoCurrency? currency, BasedUtxoNetwork network,
|
||||
Uint8List? seedBytes, String? xpub, DerivationInfo? derivationInfo) {
|
||||
if (seedBytes == null && xpub == null) {
|
||||
throw Exception(
|
||||
"To create a Wallet you need either a seed or an xpub. This should not happen");
|
||||
|
@ -123,10 +115,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
case CryptoCurrency.btc:
|
||||
case CryptoCurrency.ltc:
|
||||
case CryptoCurrency.tbtc:
|
||||
return Bip32Slip10Secp256k1.fromSeed(seedBytes, getKeyNetVersion(network))
|
||||
.derivePath(_hardenedDerivationPath(
|
||||
derivationInfo?.derivationPath ?? electrum_path))
|
||||
as Bip32Slip10Secp256k1;
|
||||
return Bip32Slip10Secp256k1.fromSeed(seedBytes);
|
||||
case CryptoCurrency.bch:
|
||||
return bitcoinCashHDWallet(seedBytes);
|
||||
default:
|
||||
|
@ -134,13 +123,11 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
}
|
||||
}
|
||||
|
||||
return Bip32Slip10Secp256k1.fromExtendedKey(
|
||||
xpub!, getKeyNetVersion(network));
|
||||
return Bip32Slip10Secp256k1.fromExtendedKey(xpub!, getKeyNetVersion(network));
|
||||
}
|
||||
|
||||
static Bip32Slip10Secp256k1 bitcoinCashHDWallet(Uint8List seedBytes) =>
|
||||
Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'")
|
||||
as Bip32Slip10Secp256k1;
|
||||
Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'") as Bip32Slip10Secp256k1;
|
||||
|
||||
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
||||
inputsCount * 68 + outputsCounts * 34 + 10;
|
||||
|
@ -156,13 +143,9 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
bool? alwaysScan;
|
||||
|
||||
final Bip32Slip10Secp256k1 accountHD;
|
||||
final Bip32Slip10Secp256k1 bip32;
|
||||
final String? _mnemonic;
|
||||
|
||||
Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0));
|
||||
|
||||
Bip32Slip10Secp256k1 get sideHd => accountHD.childKey(Bip32KeyIndex(1));
|
||||
|
||||
final EncryptionFileUtils encryptionFileUtils;
|
||||
|
||||
@override
|
||||
|
@ -193,16 +176,16 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
List<String> get scriptHashes => walletAddresses.addressesByReceiveType
|
||||
.where((addr) => RegexUtils.addressTypeFromStr(addr.address, network) is! MwebAddress)
|
||||
.map((addr) => (addr as BitcoinAddressRecord).getScriptHash(network))
|
||||
.map((addr) => (addr as BitcoinAddressRecord).scriptHash)
|
||||
.toList();
|
||||
|
||||
List<String> get publicScriptHashes => walletAddresses.allAddresses
|
||||
.where((addr) => !addr.isHidden)
|
||||
.where((addr) => !addr.isChange)
|
||||
.where((addr) => RegexUtils.addressTypeFromStr(addr.address, network) is! MwebAddress)
|
||||
.map((addr) => addr.getScriptHash(network))
|
||||
.map((addr) => addr.scriptHash)
|
||||
.toList();
|
||||
|
||||
String get xpub => accountHD.publicKey.toExtended;
|
||||
String get xpub => bip32.publicKey.toExtended;
|
||||
|
||||
@override
|
||||
String? get seed => _mnemonic;
|
||||
|
@ -235,6 +218,36 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
return isMempoolAPIEnabled;
|
||||
}
|
||||
|
||||
// @action
|
||||
// Future<void> registerSilentPaymentsKey(bool register) async {
|
||||
// silentPaymentsScanningActive = active;
|
||||
|
||||
// if (active) {
|
||||
// syncStatus = AttemptingScanSyncStatus();
|
||||
|
||||
// final tip = await getUpdatedChainTip();
|
||||
|
||||
// if (tip == walletInfo.restoreHeight) {
|
||||
// syncStatus = SyncedTipSyncStatus(tip);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (tip > walletInfo.restoreHeight) {
|
||||
// _setListeners(walletInfo.restoreHeight, chainTipParam: _currentChainTip);
|
||||
// }
|
||||
// } else {
|
||||
// alwaysScan = false;
|
||||
|
||||
// _isolate?.then((value) => value.kill(priority: Isolate.immediate));
|
||||
|
||||
// if (electrumClient.isConnected) {
|
||||
// syncStatus = SyncedSyncStatus();
|
||||
// } else {
|
||||
// syncStatus = NotConnectedSyncStatus();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@action
|
||||
Future<void> setSilentPaymentsScanning(bool active) async {
|
||||
silentPaymentsScanningActive = active;
|
||||
|
@ -286,9 +299,9 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
@override
|
||||
BitcoinWalletKeys get keys => BitcoinWalletKeys(
|
||||
wif: WifEncoder.encode(hd.privateKey.raw, netVer: network.wifNetVer),
|
||||
privateKey: hd.privateKey.toHex(),
|
||||
publicKey: hd.publicKey.toHex(),
|
||||
wif: WifEncoder.encode(bip32.privateKey.raw, netVer: network.wifNetVer),
|
||||
privateKey: bip32.privateKey.toHex(),
|
||||
publicKey: bip32.publicKey.toHex(),
|
||||
);
|
||||
|
||||
String _password;
|
||||
|
@ -337,7 +350,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
final receivePort = ReceivePort();
|
||||
_isolate = Isolate.spawn(
|
||||
startRefresh,
|
||||
delegatedScan,
|
||||
ScanData(
|
||||
sendPort: receivePort.sendPort,
|
||||
silentAddress: walletAddresses.silentAddress!,
|
||||
|
@ -351,8 +364,8 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
: null,
|
||||
labels: walletAddresses.labels,
|
||||
labelIndexes: walletAddresses.silentAddresses
|
||||
.where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.index >= 1)
|
||||
.map((addr) => addr.index)
|
||||
.where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.labelIndex >= 1)
|
||||
.map((addr) => addr.labelIndex)
|
||||
.toList(),
|
||||
isSingleScan: doSingleScan ?? false,
|
||||
));
|
||||
|
@ -433,17 +446,17 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
});
|
||||
}
|
||||
|
||||
void _updateSilentAddressRecord(BitcoinSilentPaymentsUnspent unspent) {
|
||||
void _updateSilentAddressRecord(BitcoinUnspent unspent) {
|
||||
final receiveAddressRecord = unspent.bitcoinAddressRecord as BitcoinReceivedSPAddressRecord;
|
||||
final silentAddress = walletAddresses.silentAddress!;
|
||||
final silentPaymentAddress = SilentPaymentAddress(
|
||||
version: silentAddress.version,
|
||||
B_scan: silentAddress.B_scan,
|
||||
B_spend: unspent.silentPaymentLabel != null
|
||||
B_spend: receiveAddressRecord.labelHex != null
|
||||
? silentAddress.B_spend.tweakAdd(
|
||||
BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)),
|
||||
BigintUtils.fromBytes(BytesUtils.fromHexString(receiveAddressRecord.labelHex!)),
|
||||
)
|
||||
: silentAddress.B_spend,
|
||||
network: network,
|
||||
);
|
||||
|
||||
final addressRecord = walletAddresses.silentAddresses
|
||||
|
@ -652,22 +665,16 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
ECPrivate? privkey;
|
||||
bool? isSilentPayment = false;
|
||||
|
||||
final hd = utx.bitcoinAddressRecord.isHidden
|
||||
? walletAddresses.sideHd
|
||||
: walletAddresses.mainHd;
|
||||
|
||||
if (utx.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
|
||||
final unspentAddress = utx.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
|
||||
privkey = walletAddresses.silentAddress!.b_spend.tweakAdd(
|
||||
BigintUtils.fromBytes(
|
||||
BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!),
|
||||
),
|
||||
);
|
||||
if (utx.bitcoinAddressRecord is BitcoinReceivedSPAddressRecord) {
|
||||
privkey = (utx.bitcoinAddressRecord as BitcoinReceivedSPAddressRecord).spendKey;
|
||||
spendsSilentPayment = true;
|
||||
isSilentPayment = true;
|
||||
} else if (!isHardwareWallet) {
|
||||
privkey =
|
||||
generateECPrivate(hd: hd, index: utx.bitcoinAddressRecord.index, network: network);
|
||||
privkey = ECPrivate.fromBip32(
|
||||
bip32: walletAddresses.bip32,
|
||||
account: utx.bitcoinAddressRecord.isChange ? 1 : 0,
|
||||
index: utx.bitcoinAddressRecord.index,
|
||||
);
|
||||
}
|
||||
|
||||
vinOutpoints.add(Outpoint(txid: utx.hash, index: utx.vout));
|
||||
|
@ -682,12 +689,15 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
pubKeyHex = privkey.getPublic().toHex();
|
||||
} else {
|
||||
pubKeyHex = hd.childKey(Bip32KeyIndex(utx.bitcoinAddressRecord.index)).publicKey.toHex();
|
||||
pubKeyHex = walletAddresses.bip32
|
||||
.childKey(Bip32KeyIndex(utx.bitcoinAddressRecord.index))
|
||||
.publicKey
|
||||
.toHex();
|
||||
}
|
||||
|
||||
final derivationPath =
|
||||
"${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? electrum_path)}"
|
||||
"/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}"
|
||||
"/${utx.bitcoinAddressRecord.isChange ? "1" : "0"}"
|
||||
"/${utx.bitcoinAddressRecord.index}";
|
||||
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
|
||||
|
||||
|
@ -1233,8 +1243,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
}
|
||||
}
|
||||
|
||||
void setLedgerConnection(ledger.LedgerConnection connection) =>
|
||||
throw UnimplementedError();
|
||||
void setLedgerConnection(ledger.LedgerConnection connection) => throw UnimplementedError();
|
||||
|
||||
Future<BtcTransaction> buildHardwareWalletTransaction({
|
||||
required List<BitcoinBaseOutput> outputs,
|
||||
|
@ -1467,13 +1476,13 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
List<Map<String, dynamic>> unspents = [];
|
||||
List<BitcoinUnspent> updatedUnspentCoins = [];
|
||||
|
||||
unspents = await electrumClient.getListUnspent(address.getScriptHash(network));
|
||||
unspents = await electrumClient.getListUnspent(address.scriptHash);
|
||||
|
||||
await Future.wait(unspents.map((unspent) async {
|
||||
try {
|
||||
final coin = BitcoinUnspent.fromJSON(address, unspent);
|
||||
final tx = await fetchTransactionInfo(hash: coin.hash);
|
||||
coin.isChange = address.isHidden;
|
||||
coin.isChange = address.isChange;
|
||||
coin.confirmations = tx?.confirmations;
|
||||
|
||||
updatedUnspentCoins.add(coin);
|
||||
|
@ -1495,7 +1504,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
value: coin.value,
|
||||
vout: coin.vout,
|
||||
isChange: coin.isChange,
|
||||
isSilentPayment: coin is BitcoinSilentPaymentsUnspent,
|
||||
isSilentPayment: coin.bitcoinAddressRecord is BitcoinReceivedSPAddressRecord,
|
||||
);
|
||||
|
||||
await unspentCoinsInfo.add(newInfo);
|
||||
|
@ -1543,7 +1552,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
final bundle = await getTransactionExpanded(hash: txId);
|
||||
final outputs = bundle.originalTransaction.outputs;
|
||||
|
||||
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden);
|
||||
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isChange);
|
||||
|
||||
// look for a change address in the outputs
|
||||
final changeOutput = outputs.firstWhereOrNull((output) => changeAddresses.any(
|
||||
|
@ -1592,12 +1601,11 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
walletAddresses.allAddresses.firstWhere((element) => element.address == address);
|
||||
|
||||
final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network);
|
||||
final privkey = generateECPrivate(
|
||||
hd: addressRecord.isHidden
|
||||
? walletAddresses.sideHd
|
||||
: walletAddresses.mainHd,
|
||||
final privkey = ECPrivate.fromBip32(
|
||||
bip32: walletAddresses.bip32,
|
||||
account: addressRecord.isChange ? 1 : 0,
|
||||
index: addressRecord.index,
|
||||
network: network);
|
||||
);
|
||||
|
||||
privateKeys.add(privkey);
|
||||
|
||||
|
@ -1672,7 +1680,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
}
|
||||
|
||||
// Identify all change outputs
|
||||
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden);
|
||||
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isChange);
|
||||
final List<BitcoinOutput> changeOutputs = outputs
|
||||
.where((output) => changeAddresses
|
||||
.any((element) => element.address == output.address.toAddress(network)))
|
||||
|
@ -1777,8 +1785,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
if (height != null) {
|
||||
if (time == null && height > 0) {
|
||||
time = (getDateByBitcoinHeight(height).millisecondsSinceEpoch / 1000)
|
||||
.round();
|
||||
time = (getDateByBitcoinHeight(height).millisecondsSinceEpoch / 1000).round();
|
||||
}
|
||||
|
||||
if (confirmations == null) {
|
||||
|
@ -1879,8 +1886,8 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
BitcoinAddressType type,
|
||||
) async {
|
||||
final addressesByType = walletAddresses.allAddresses.where((addr) => addr.type == type);
|
||||
final hiddenAddresses = addressesByType.where((addr) => addr.isHidden == true);
|
||||
final receiveAddresses = addressesByType.where((addr) => addr.isHidden == false);
|
||||
final hiddenAddresses = addressesByType.where((addr) => addr.isChange == true);
|
||||
final receiveAddresses = addressesByType.where((addr) => addr.isChange == false);
|
||||
walletAddresses.hiddenAddresses.addAll(hiddenAddresses.map((e) => e.address));
|
||||
await walletAddresses.saveAddressesInBox();
|
||||
await Future.wait(addressesByType.map((addressRecord) async {
|
||||
|
@ -1890,10 +1897,10 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
addressRecord.txCount = history.length;
|
||||
historiesWithDetails.addAll(history);
|
||||
|
||||
final matchedAddresses = addressRecord.isHidden ? hiddenAddresses : receiveAddresses;
|
||||
final matchedAddresses = addressRecord.isChange ? hiddenAddresses : receiveAddresses;
|
||||
final isUsedAddressUnderGap = matchedAddresses.toList().indexOf(addressRecord) >=
|
||||
matchedAddresses.length -
|
||||
(addressRecord.isHidden
|
||||
(addressRecord.isChange
|
||||
? ElectrumWalletAddressesBase.defaultChangeAddressesCount
|
||||
: ElectrumWalletAddressesBase.defaultReceiveAddressesCount);
|
||||
|
||||
|
@ -1903,7 +1910,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
// Discover new addresses for the same address type until the gap limit is respected
|
||||
await walletAddresses.discoverAddresses(
|
||||
matchedAddresses.toList(),
|
||||
addressRecord.isHidden,
|
||||
addressRecord.isChange,
|
||||
(address) async {
|
||||
await subscribeForUpdates();
|
||||
return _fetchAddressHistory(address, await getCurrentChainTip())
|
||||
|
@ -1929,7 +1936,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
try {
|
||||
final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
|
||||
|
||||
final history = await electrumClient.getHistory(addressRecord.getScriptHash(network));
|
||||
final history = await electrumClient.getHistory(addressRecord.scriptHash);
|
||||
|
||||
if (history.isNotEmpty) {
|
||||
addressRecord.setAsUsed();
|
||||
|
@ -2010,12 +2017,12 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
Future<void> subscribeForUpdates() async {
|
||||
final unsubscribedScriptHashes = walletAddresses.allAddresses.where(
|
||||
(address) =>
|
||||
!_scripthashesUpdateSubject.containsKey(address.getScriptHash(network)) &&
|
||||
!_scripthashesUpdateSubject.containsKey(address.scriptHash) &&
|
||||
address.type != SegwitAddresType.mweb,
|
||||
);
|
||||
|
||||
await Future.wait(unsubscribedScriptHashes.map((address) async {
|
||||
final sh = address.getScriptHash(network);
|
||||
final sh = address.scriptHash;
|
||||
if (!(_scripthashesUpdateSubject[sh]?.isClosed ?? true)) {
|
||||
try {
|
||||
await _scripthashesUpdateSubject[sh]?.close();
|
||||
|
@ -2054,7 +2061,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
final balanceFutures = <Future<Map<String, dynamic>>>[];
|
||||
for (var i = 0; i < addresses.length; i++) {
|
||||
final addressRecord = addresses[i];
|
||||
final sh = addressRecord.getScriptHash(network);
|
||||
final sh = addressRecord.scriptHash;
|
||||
final balanceFuture = electrumClient.getBalance(sh);
|
||||
balanceFutures.add(balanceFuture);
|
||||
}
|
||||
|
@ -2095,6 +2102,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
for (var i = 0; i < balances.length; i++) {
|
||||
final addressRecord = addresses[i];
|
||||
final balance = balances[i];
|
||||
try {
|
||||
final confirmed = balance['confirmed'] as int? ?? 0;
|
||||
final unconfirmed = balance['unconfirmed'] as int? ?? 0;
|
||||
totalConfirmed += confirmed;
|
||||
|
@ -2104,6 +2112,7 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
if (confirmed > 0 || unconfirmed > 0) {
|
||||
addressRecord.setAsUsed();
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return ElectrumBalance(
|
||||
|
@ -2124,10 +2133,17 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
@override
|
||||
Future<String> signMessage(String message, {String? address = null}) async {
|
||||
final index = address != null
|
||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
|
||||
: null;
|
||||
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
|
||||
Bip32Slip10Secp256k1 HD = bip32;
|
||||
|
||||
final record = walletAddresses.allAddresses.firstWhere((element) => element.address == address);
|
||||
|
||||
if (record.isChange) {
|
||||
HD = HD.childKey(Bip32KeyIndex(1));
|
||||
} else {
|
||||
HD = HD.childKey(Bip32KeyIndex(0));
|
||||
}
|
||||
|
||||
HD = HD.childKey(Bip32KeyIndex(record.index));
|
||||
final priv = ECPrivate.fromHex(HD.privateKey.privKey.toHex());
|
||||
|
||||
String messagePrefix = '\x18Bitcoin Signed Message:\n';
|
||||
|
@ -2223,7 +2239,6 @@ abstract class ElectrumWalletBase extends WalletBase<
|
|||
|
||||
@action
|
||||
void _onConnectionStatusChange(ConnectionStatus status) {
|
||||
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
if (syncStatus is NotConnectedSyncStatus ||
|
||||
|
@ -2396,6 +2411,137 @@ class SyncResponse {
|
|||
SyncResponse(this.height, this.syncStatus);
|
||||
}
|
||||
|
||||
Future<void> delegatedScan(ScanData scanData) async {
|
||||
int syncHeight = scanData.height;
|
||||
int initialSyncHeight = syncHeight;
|
||||
|
||||
BehaviorSubject<Object>? tweaksSubscription = null;
|
||||
|
||||
final electrumClient = scanData.electrumClient;
|
||||
await electrumClient.connectToUri(
|
||||
scanData.node?.uri ?? Uri.parse("tcp://electrs.cakewallet.com:50001"),
|
||||
useSSL: scanData.node?.useSSL ?? false,
|
||||
);
|
||||
|
||||
if (tweaksSubscription == null) {
|
||||
scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
|
||||
|
||||
tweaksSubscription = await electrumClient.tweaksScan(
|
||||
pubSpendKey: scanData.silentAddress.B_spend.toHex(),
|
||||
);
|
||||
|
||||
Future<void> listenFn(t) async {
|
||||
final tweaks = t as Map<String, dynamic>;
|
||||
final msg = tweaks["message"];
|
||||
|
||||
// success or error msg
|
||||
final noData = msg != null;
|
||||
if (noData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Continuous status UI update, send how many blocks left to scan
|
||||
final syncingStatus = scanData.isSingleScan
|
||||
? SyncingSyncStatus(1, 0)
|
||||
: SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, syncHeight);
|
||||
scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
|
||||
|
||||
final blockHeight = tweaks.keys.first;
|
||||
final tweakHeight = int.parse(blockHeight);
|
||||
|
||||
try {
|
||||
final blockTweaks = tweaks[blockHeight] as Map<String, dynamic>;
|
||||
|
||||
for (var j = 0; j < blockTweaks.keys.length; j++) {
|
||||
final txid = blockTweaks.keys.elementAt(j);
|
||||
final details = blockTweaks[txid] as Map<String, dynamic>;
|
||||
final outputPubkeys = (details["output_pubkeys"] as Map<dynamic, dynamic>);
|
||||
final spendingKey = details["spending_key"].toString();
|
||||
|
||||
try {
|
||||
// placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s)
|
||||
final txInfo = ElectrumTransactionInfo(
|
||||
WalletType.bitcoin,
|
||||
id: txid,
|
||||
height: tweakHeight,
|
||||
amount: 0,
|
||||
fee: 0,
|
||||
direction: TransactionDirection.incoming,
|
||||
isPending: false,
|
||||
isReplaced: false,
|
||||
date: scanData.network == BitcoinNetwork.mainnet
|
||||
? getDateByBitcoinHeight(tweakHeight)
|
||||
: DateTime.now(),
|
||||
confirmations: scanData.chainTip - tweakHeight + 1,
|
||||
unspents: [],
|
||||
isReceivedSilentPayment: true,
|
||||
);
|
||||
|
||||
outputPubkeys.forEach((pos, value) {
|
||||
final secKey = ECPrivate.fromHex(spendingKey);
|
||||
final receivingOutputAddress =
|
||||
secKey.getPublic().toTaprootAddress(tweak: false).toAddress(scanData.network);
|
||||
|
||||
late int amount;
|
||||
try {
|
||||
amount = int.parse(value[1].toString());
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
|
||||
final receivedAddressRecord = BitcoinReceivedSPAddressRecord(
|
||||
receivingOutputAddress,
|
||||
labelIndex: 0,
|
||||
isUsed: true,
|
||||
spendKey: secKey,
|
||||
txCount: 1,
|
||||
balance: amount,
|
||||
);
|
||||
|
||||
final unspent = BitcoinUnspent(
|
||||
receivedAddressRecord,
|
||||
txid,
|
||||
amount,
|
||||
int.parse(pos.toString()),
|
||||
);
|
||||
|
||||
txInfo.unspents!.add(unspent);
|
||||
txInfo.amount += unspent.value;
|
||||
});
|
||||
|
||||
scanData.sendPort.send({txInfo.id: txInfo});
|
||||
} catch (_) {}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
syncHeight = tweakHeight;
|
||||
|
||||
if (tweakHeight >= scanData.chainTip || scanData.isSingleScan) {
|
||||
if (tweakHeight >= scanData.chainTip)
|
||||
scanData.sendPort.send(SyncResponse(
|
||||
syncHeight,
|
||||
SyncedTipSyncStatus(scanData.chainTip),
|
||||
));
|
||||
|
||||
if (scanData.isSingleScan) {
|
||||
scanData.sendPort.send(SyncResponse(syncHeight, SyncedSyncStatus()));
|
||||
}
|
||||
|
||||
await tweaksSubscription!.close();
|
||||
await electrumClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
tweaksSubscription?.listen(listenFn);
|
||||
}
|
||||
|
||||
if (tweaksSubscription == null) {
|
||||
return scanData.sendPort.send(
|
||||
SyncResponse(syncHeight, UnsupportedSyncStatus()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> startRefresh(ScanData scanData) async {
|
||||
int syncHeight = scanData.height;
|
||||
int initialSyncHeight = syncHeight;
|
||||
|
@ -2528,26 +2674,18 @@ Future<void> startRefresh(ScanData scanData) async {
|
|||
return false;
|
||||
});
|
||||
|
||||
final receivedAddressRecord = BitcoinSilentPaymentAddressRecord(
|
||||
final receivedAddressRecord = BitcoinReceivedSPAddressRecord(
|
||||
receivingOutputAddress,
|
||||
index: 0,
|
||||
isHidden: false,
|
||||
labelIndex: 0,
|
||||
isUsed: true,
|
||||
network: scanData.network,
|
||||
silentPaymentTweak: t_k,
|
||||
type: SegwitAddresType.p2tr,
|
||||
spendKey: scanData.silentAddress.b_spend.tweakAdd(
|
||||
BigintUtils.fromBytes(BytesUtils.fromHexString(t_k)),
|
||||
),
|
||||
txCount: 1,
|
||||
balance: amount!,
|
||||
);
|
||||
|
||||
final unspent = BitcoinSilentPaymentsUnspent(
|
||||
receivedAddressRecord,
|
||||
txid,
|
||||
amount!,
|
||||
pos!,
|
||||
silentPaymentTweak: t_k,
|
||||
silentPaymentLabel: label == "None" ? null : label,
|
||||
);
|
||||
final unspent = BitcoinUnspent(receivedAddressRecord, txid, amount!, pos!);
|
||||
|
||||
txInfo.unspents!.add(unspent);
|
||||
txInfo.amount += unspent.value;
|
||||
|
|
|
@ -33,8 +33,7 @@ const List<BitcoinAddressType> BITCOIN_CASH_ADDRESS_TYPES = [
|
|||
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||
ElectrumWalletAddressesBase(
|
||||
WalletInfo walletInfo, {
|
||||
required this.mainHd,
|
||||
required this.sideHd,
|
||||
required this.bip32,
|
||||
required this.network,
|
||||
required this.isHardwareWallet,
|
||||
List<BitcoinAddressRecord>? initialAddresses,
|
||||
|
@ -43,17 +42,15 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
|
||||
int initialSilentAddressIndex = 0,
|
||||
List<BitcoinAddressRecord>? initialMwebAddresses,
|
||||
Bip32Slip10Secp256k1? masterHd,
|
||||
BitcoinAddressType? initialAddressPageType,
|
||||
|
||||
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
||||
addressesByReceiveType =
|
||||
ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()),
|
||||
receiveAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
|
||||
.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed)
|
||||
.where((addressRecord) => !addressRecord.isChange && !addressRecord.isUsed)
|
||||
.toSet()),
|
||||
changeAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
|
||||
.where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed)
|
||||
.where((addressRecord) => addressRecord.isChange && !addressRecord.isUsed)
|
||||
.toSet()),
|
||||
currentReceiveAddressIndexByType = initialRegularAddressIndex ?? {},
|
||||
currentChangeAddressIndexByType = initialChangeAddressIndex ?? {},
|
||||
|
@ -67,34 +64,26 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
mwebAddresses =
|
||||
ObservableList<BitcoinAddressRecord>.of((initialMwebAddresses ?? []).toSet()),
|
||||
super(walletInfo) {
|
||||
if (masterHd != null) {
|
||||
silentAddress = SilentPaymentOwner.fromPrivateKeys(
|
||||
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privateKey.toHex()),
|
||||
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privateKey.toHex()),
|
||||
b_scan: ECPrivate.fromHex(bip32.derive(SCAN_PATH).privateKey.toHex()),
|
||||
b_spend: ECPrivate.fromHex(bip32.derive(SPEND_PATH).privateKey.toHex()),
|
||||
network: network,
|
||||
);
|
||||
|
||||
if (silentAddresses.length == 0) {
|
||||
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||
silentAddress.toString(),
|
||||
index: 0,
|
||||
isHidden: false,
|
||||
labelIndex: 1,
|
||||
name: "",
|
||||
silentPaymentTweak: null,
|
||||
network: network,
|
||||
type: SilentPaymentsAddresType.p2sp,
|
||||
));
|
||||
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||
silentAddress!.toLabeledSilentPaymentAddress(0).toString(),
|
||||
index: 0,
|
||||
isHidden: true,
|
||||
name: "",
|
||||
silentPaymentTweak: BytesUtils.toHexString(silentAddress!.generateLabel(0)),
|
||||
network: network,
|
||||
labelIndex: 0,
|
||||
labelHex: BytesUtils.toHexString(silentAddress!.generateLabel(0)),
|
||||
type: SilentPaymentsAddresType.p2sp,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
updateAddressesByMatch();
|
||||
}
|
||||
|
@ -112,9 +101,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
// TODO: add this variable in `litecoin_wallet_addresses` and just add a cast in cw_bitcoin to use it
|
||||
final ObservableList<BitcoinAddressRecord> mwebAddresses;
|
||||
final BasedUtxoNetwork network;
|
||||
final Bip32Slip10Secp256k1 mainHd;
|
||||
final Bip32Slip10Secp256k1 sideHd;
|
||||
final bool isHardwareWallet;
|
||||
final Bip32Slip10Secp256k1 bip32;
|
||||
|
||||
@observable
|
||||
SilentPaymentOwner? silentAddress;
|
||||
|
@ -174,11 +161,16 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
return;
|
||||
}
|
||||
if (addressPageType == SilentPaymentsAddresType.p2sp) {
|
||||
final selected = silentAddresses.firstWhere((addressRecord) => addressRecord.address == addr);
|
||||
late BitcoinSilentPaymentAddressRecord selected;
|
||||
try {
|
||||
selected = silentAddresses.firstWhere((addressRecord) => addressRecord.address == addr);
|
||||
} catch (_) {
|
||||
selected = silentAddresses[0];
|
||||
}
|
||||
|
||||
if (selected.silentPaymentTweak != null && silentAddress != null) {
|
||||
if (selected.labelHex != null && silentAddress != null) {
|
||||
activeSilentAddress =
|
||||
silentAddress!.toLabeledSilentPaymentAddress(selected.index).toString();
|
||||
silentAddress!.toLabeledSilentPaymentAddress(selected.labelIndex).toString();
|
||||
} else {
|
||||
activeSilentAddress = silentAddress!.toString();
|
||||
}
|
||||
|
@ -198,7 +190,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}
|
||||
|
||||
@override
|
||||
String get primaryAddress => getAddress(index: 0, hd: mainHd, addressType: addressPageType);
|
||||
String get primaryAddress =>
|
||||
getAddress(account: 0, index: 0, hd: bip32, addressType: addressPageType);
|
||||
|
||||
Map<String, int> currentReceiveAddressIndexByType;
|
||||
|
||||
|
@ -223,7 +216,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
@computed
|
||||
int get totalCountOfReceiveAddresses => addressesByReceiveType.fold(0, (acc, addressRecord) {
|
||||
if (!addressRecord.isHidden) {
|
||||
if (!addressRecord.isChange) {
|
||||
return acc + 1;
|
||||
}
|
||||
return acc;
|
||||
|
@ -231,7 +224,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
@computed
|
||||
int get totalCountOfChangeAddresses => addressesByReceiveType.fold(0, (acc, addressRecord) {
|
||||
if (addressRecord.isHidden) {
|
||||
if (addressRecord.isChange) {
|
||||
return acc + 1;
|
||||
}
|
||||
return acc;
|
||||
|
@ -272,7 +265,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}
|
||||
|
||||
@action
|
||||
Future<BitcoinAddressRecord> getChangeAddress({List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
||||
Future<BitcoinAddressRecord> getChangeAddress(
|
||||
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
||||
updateChangeAddresses();
|
||||
|
||||
if (changeAddresses.isEmpty) {
|
||||
|
@ -297,7 +291,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
final labels = <String, String>{};
|
||||
for (int i = 0; i < silentAddresses.length; i++) {
|
||||
final silentAddressRecord = silentAddresses[i];
|
||||
final silentPaymentTweak = silentAddressRecord.silentPaymentTweak;
|
||||
final silentPaymentTweak = silentAddressRecord.labelHex;
|
||||
|
||||
if (silentPaymentTweak != null &&
|
||||
SilentPaymentAddress.regex.hasMatch(silentAddressRecord.address)) {
|
||||
|
@ -321,12 +315,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
final address = BitcoinSilentPaymentAddressRecord(
|
||||
silentAddress!.toLabeledSilentPaymentAddress(currentSilentAddressIndex).toString(),
|
||||
index: currentSilentAddressIndex,
|
||||
isHidden: false,
|
||||
labelIndex: currentSilentAddressIndex,
|
||||
name: label,
|
||||
silentPaymentTweak:
|
||||
BytesUtils.toHexString(silentAddress!.generateLabel(currentSilentAddressIndex)),
|
||||
network: network,
|
||||
labelHex: BytesUtils.toHexString(silentAddress!.generateLabel(currentSilentAddressIndex)),
|
||||
type: SilentPaymentsAddresType.p2sp,
|
||||
);
|
||||
|
||||
|
@ -337,12 +328,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}
|
||||
|
||||
final newAddressIndex = addressesByReceiveType.fold(
|
||||
0, (int acc, addressRecord) => addressRecord.isHidden == false ? acc + 1 : acc);
|
||||
0, (int acc, addressRecord) => addressRecord.isChange == false ? acc + 1 : acc);
|
||||
|
||||
final address = BitcoinAddressRecord(
|
||||
getAddress(index: newAddressIndex, hd: mainHd, addressType: addressPageType),
|
||||
getAddress(account: 0, index: newAddressIndex, hd: bip32, addressType: addressPageType),
|
||||
index: newAddressIndex,
|
||||
isHidden: false,
|
||||
isChange: false,
|
||||
name: label,
|
||||
type: addressPageType,
|
||||
network: network,
|
||||
|
@ -352,19 +343,32 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
return address;
|
||||
}
|
||||
|
||||
String getAddress({
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType,
|
||||
}) =>
|
||||
'';
|
||||
required BitcoinAddressType addressType,
|
||||
}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
String getAddress({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BitcoinAddressType addressType,
|
||||
}) {
|
||||
return generateAddress(account: account, index: index, hd: hd, addressType: addressType)
|
||||
.toAddress(network);
|
||||
}
|
||||
|
||||
Future<String> getAddressAsync({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType,
|
||||
required BitcoinAddressType addressType,
|
||||
}) async =>
|
||||
getAddress(index: index, hd: hd, addressType: addressType);
|
||||
getAddress(account: account, index: index, hd: hd, addressType: addressType);
|
||||
|
||||
void addBitcoinAddressTypes() {
|
||||
final lastP2wpkh = _addresses
|
||||
|
@ -411,7 +415,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}
|
||||
|
||||
silentAddresses.forEach((addressRecord) {
|
||||
if (addressRecord.type != SilentPaymentsAddresType.p2sp || addressRecord.isHidden) {
|
||||
if (addressRecord.type != SilentPaymentsAddresType.p2sp || addressRecord.isChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -537,7 +541,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
void updateReceiveAddresses() {
|
||||
receiveAddresses.removeRange(0, receiveAddresses.length);
|
||||
final newAddresses =
|
||||
_addresses.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed);
|
||||
_addresses.where((addressRecord) => !addressRecord.isChange && !addressRecord.isUsed);
|
||||
receiveAddresses.addAll(newAddresses);
|
||||
}
|
||||
|
||||
|
@ -545,7 +549,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
void updateChangeAddresses() {
|
||||
changeAddresses.removeRange(0, changeAddresses.length);
|
||||
final newAddresses = _addresses.where((addressRecord) =>
|
||||
addressRecord.isHidden &&
|
||||
addressRecord.isChange &&
|
||||
!addressRecord.isUsed &&
|
||||
// TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type
|
||||
(walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddresType.p2wpkh));
|
||||
|
@ -575,7 +579,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
_addresses.forEach((addr) {
|
||||
if (addr.type == type) {
|
||||
if (addr.isHidden) {
|
||||
if (addr.isChange) {
|
||||
countOfHiddenAddresses += 1;
|
||||
return;
|
||||
}
|
||||
|
@ -605,9 +609,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
for (var i = startIndex; i < count + startIndex; i++) {
|
||||
final address = BitcoinAddressRecord(
|
||||
await getAddressAsync(index: i, hd: _getHd(isHidden), addressType: type ?? addressPageType),
|
||||
await getAddressAsync(
|
||||
account: _getAccount(isHidden),
|
||||
index: i,
|
||||
isHidden: isHidden,
|
||||
hd: bip32,
|
||||
addressType: type ?? addressPageType),
|
||||
index: i,
|
||||
isChange: isHidden,
|
||||
type: type ?? addressPageType,
|
||||
network: network,
|
||||
);
|
||||
|
@ -650,14 +658,24 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
// this would add a ton of startup lag for mweb addresses since we have 1000 of them
|
||||
return;
|
||||
}
|
||||
if (!element.isHidden &&
|
||||
if (!element.isChange &&
|
||||
element.address !=
|
||||
await getAddressAsync(index: element.index, hd: mainHd, addressType: element.type)) {
|
||||
element.isHidden = true;
|
||||
} else if (element.isHidden &&
|
||||
await getAddressAsync(
|
||||
account: 0,
|
||||
index: element.index,
|
||||
hd: bip32,
|
||||
addressType: element.type,
|
||||
)) {
|
||||
element.isChange = true;
|
||||
} else if (element.isChange &&
|
||||
element.address !=
|
||||
await getAddressAsync(index: element.index, hd: sideHd, addressType: element.type)) {
|
||||
element.isHidden = false;
|
||||
await getAddressAsync(
|
||||
account: 1,
|
||||
index: element.index,
|
||||
hd: bip32,
|
||||
addressType: element.type,
|
||||
)) {
|
||||
element.isChange = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -674,12 +692,11 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
return _isAddressByType(addressRecord, addressPageType);
|
||||
}
|
||||
|
||||
Bip32Slip10Secp256k1 _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
|
||||
|
||||
int _getAccount(bool isHidden) => isHidden ? 1 : 0;
|
||||
bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
|
||||
|
||||
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
|
||||
!addr.isHidden && !addr.isUsed && addr.type == type;
|
||||
!addr.isChange && !addr.isUsed && addr.type == type;
|
||||
|
||||
@action
|
||||
void deleteSilentPaymentAddress(String address) {
|
||||
|
|
|
@ -6,7 +6,6 @@ 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/wallet_info.dart';
|
||||
import 'package:cw_core/utils/file.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class ElectrumWalletSnapshot {
|
||||
|
@ -68,7 +67,7 @@ class ElectrumWalletSnapshot {
|
|||
final addressesTmp = data['addresses'] as List? ?? <Object>[];
|
||||
final addresses = addressesTmp
|
||||
.whereType<String>()
|
||||
.map((addr) => BitcoinAddressRecord.fromJSON(addr, network: network))
|
||||
.map((addr) => BitcoinAddressRecord.fromJSON(addr))
|
||||
.toList();
|
||||
|
||||
final silentAddressesTmp = data['silent_addresses'] as List? ?? <Object>[];
|
||||
|
@ -80,7 +79,7 @@ class ElectrumWalletSnapshot {
|
|||
final mwebAddressTmp = data['mweb_addresses'] as List? ?? <Object>[];
|
||||
final mwebAddresses = mwebAddressTmp
|
||||
.whereType<String>()
|
||||
.map((addr) => BitcoinAddressRecord.fromJSON(addr, network: network))
|
||||
.map((addr) => BitcoinAddressRecord.fromJSON(addr))
|
||||
.toList();
|
||||
|
||||
final alwaysScan = data['alwaysScan'] as bool? ?? false;
|
||||
|
|
|
@ -21,7 +21,6 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
|||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -98,8 +97,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
initialMwebAddresses: initialMwebAddresses,
|
||||
mainHd: hd,
|
||||
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||
bip32: bip32,
|
||||
network: network,
|
||||
mwebHd: mwebHd,
|
||||
mwebEnabled: mwebEnabled,
|
||||
|
@ -1025,12 +1023,11 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
witnesses: tx2.inputs.asMap().entries.map((e) {
|
||||
final utxo = unspentCoins
|
||||
.firstWhere((utxo) => utxo.hash == e.value.txId && utxo.vout == e.value.txIndex);
|
||||
final key = generateECPrivate(
|
||||
hd: utxo.bitcoinAddressRecord.isHidden
|
||||
? walletAddresses.sideHd
|
||||
: walletAddresses.mainHd,
|
||||
final key = ECPrivate.fromBip32(
|
||||
bip32: walletAddresses.bip32,
|
||||
account: utxo.bitcoinAddressRecord.isChange ? 1 : 0,
|
||||
index: utxo.bitcoinAddressRecord.index,
|
||||
network: network);
|
||||
);
|
||||
final digest = tx2.getTransactionSegwitDigit(
|
||||
txInIndex: e.key,
|
||||
script: key.getPublic().toP2pkhAddress().toScriptPubKey(),
|
||||
|
@ -1113,10 +1110,17 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
@override
|
||||
Future<String> signMessage(String message, {String? address = null}) async {
|
||||
final index = address != null
|
||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
|
||||
: null;
|
||||
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
|
||||
Bip32Slip10Secp256k1 HD = bip32;
|
||||
|
||||
final record = walletAddresses.allAddresses.firstWhere((element) => element.address == address);
|
||||
|
||||
if (record.isChange) {
|
||||
HD = HD.childKey(Bip32KeyIndex(1));
|
||||
} else {
|
||||
HD = HD.childKey(Bip32KeyIndex(0));
|
||||
}
|
||||
|
||||
HD = HD.childKey(Bip32KeyIndex(record.index));
|
||||
final priv = ECPrivate.fromHex(HD.privateKey.privKey.toHex());
|
||||
|
||||
final privateKey = ECDSAPrivateKey.fromBytes(
|
||||
|
|
|
@ -7,7 +7,6 @@ import 'package:blockchain_utils/blockchain_utils.dart';
|
|||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_mweb/cw_mweb.dart';
|
||||
|
@ -23,8 +22,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
|
|||
with Store {
|
||||
LitecoinWalletAddressesBase(
|
||||
WalletInfo walletInfo, {
|
||||
required super.mainHd,
|
||||
required super.sideHd,
|
||||
required super.bip32,
|
||||
required super.network,
|
||||
required super.isHardwareWallet,
|
||||
required this.mwebHd,
|
||||
|
@ -121,30 +119,34 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
|
|||
await ensureMwebAddressUpToIndexExists(20);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String getAddress({
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType,
|
||||
required BitcoinAddressType addressType,
|
||||
}) {
|
||||
if (addressType == SegwitAddresType.mweb) {
|
||||
return hd == sideHd ? mwebAddrs[0] : mwebAddrs[index + 1];
|
||||
return MwebAddress.fromAddress(address: mwebAddrs[0], network: network);
|
||||
}
|
||||
|
||||
return P2wpkhAddress.fromBip32(account: account, bip32: hd, index: index);
|
||||
}
|
||||
return generateP2WPKHAddress(hd: hd, index: index, network: network);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> getAddressAsync({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType,
|
||||
required BitcoinAddressType addressType,
|
||||
}) async {
|
||||
if (addressType == SegwitAddresType.mweb) {
|
||||
await ensureMwebAddressUpToIndexExists(index);
|
||||
}
|
||||
return getAddress(index: index, hd: hd, addressType: addressType);
|
||||
|
||||
return getAddress(account: account, index: index, hd: hd, addressType: addressType);
|
||||
}
|
||||
|
||||
@action
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
|
||||
ECPrivate generateECPrivate({
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BasedUtxoNetwork network,
|
||||
required int index,
|
||||
}) =>
|
||||
ECPrivate(hd.childKey(Bip32KeyIndex(index)).privateKey);
|
||||
|
||||
String generateP2WPKHAddress({
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BasedUtxoNetwork network,
|
||||
required int index,
|
||||
}) =>
|
||||
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||
.toP2wpkhAddress()
|
||||
.toAddress(network);
|
||||
|
||||
String generateP2SHAddress({
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BasedUtxoNetwork network,
|
||||
required int index,
|
||||
}) =>
|
||||
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||
.toP2wpkhInP2sh()
|
||||
.toAddress(network);
|
||||
|
||||
String generateP2WSHAddress({
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BasedUtxoNetwork network,
|
||||
required int index,
|
||||
}) =>
|
||||
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||
.toP2wshAddress()
|
||||
.toAddress(network);
|
||||
|
||||
String generateP2PKHAddress({
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BasedUtxoNetwork network,
|
||||
required int index,
|
||||
}) =>
|
||||
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||
.toP2pkhAddress()
|
||||
.toAddress(network);
|
||||
|
||||
String generateP2TRAddress({
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
required BasedUtxoNetwork network,
|
||||
required int index,
|
||||
}) =>
|
||||
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||
.toTaprootAddress()
|
||||
.toAddress(network);
|
|
@ -54,8 +54,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
initialAddresses: initialAddresses,
|
||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
mainHd: hd,
|
||||
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||
bip32: bip32,
|
||||
network: network,
|
||||
initialAddressPageType: addressPageType,
|
||||
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||
|
@ -141,7 +140,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
return BitcoinAddressRecord(
|
||||
addr.address,
|
||||
index: addr.index,
|
||||
isHidden: addr.isHidden,
|
||||
isChange: addr.isChange,
|
||||
type: P2pkhAddressType.p2pkh,
|
||||
network: BitcoinCashNetwork.mainnet,
|
||||
);
|
||||
|
@ -149,7 +148,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
return BitcoinAddressRecord(
|
||||
AddressUtils.getCashAddrFormat(addr.address),
|
||||
index: addr.index,
|
||||
isHidden: addr.isHidden,
|
||||
isChange: addr.isChange,
|
||||
type: P2pkhAddressType.p2pkh,
|
||||
network: BitcoinCashNetwork.mainnet,
|
||||
);
|
||||
|
@ -209,13 +208,17 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
@override
|
||||
Future<String> signMessage(String message, {String? address = null}) async {
|
||||
int? index;
|
||||
try {
|
||||
index = address != null
|
||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
|
||||
: null;
|
||||
} catch (_) {}
|
||||
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
|
||||
Bip32Slip10Secp256k1 HD = bip32;
|
||||
|
||||
final record = walletAddresses.allAddresses.firstWhere((element) => element.address == address);
|
||||
|
||||
if (record.isChange) {
|
||||
HD = HD.childKey(Bip32KeyIndex(1));
|
||||
} else {
|
||||
HD = HD.childKey(Bip32KeyIndex(0));
|
||||
}
|
||||
|
||||
HD = HD.childKey(Bip32KeyIndex(record.index));
|
||||
final priv = ECPrivate.fromWif(
|
||||
WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer),
|
||||
netVersion: network.wifNetVer,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
|
@ -12,8 +11,7 @@ class BitcoinCashWalletAddresses = BitcoinCashWalletAddressesBase with _$Bitcoin
|
|||
abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses with Store {
|
||||
BitcoinCashWalletAddressesBase(
|
||||
WalletInfo walletInfo, {
|
||||
required super.mainHd,
|
||||
required super.sideHd,
|
||||
required super.bip32,
|
||||
required super.network,
|
||||
required super.isHardwareWallet,
|
||||
super.initialAddresses,
|
||||
|
@ -23,9 +21,11 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
|||
}) : super(walletInfo);
|
||||
|
||||
@override
|
||||
String getAddress(
|
||||
{required int index,
|
||||
BitcoinBaseAddress generateAddress({
|
||||
required int account,
|
||||
required int index,
|
||||
required Bip32Slip10Secp256k1 hd,
|
||||
BitcoinAddressType? addressType}) =>
|
||||
generateP2PKHAddress(hd: hd, index: index, network: network);
|
||||
required BitcoinAddressType addressType,
|
||||
}) =>
|
||||
P2pkhAddress.fromBip32(account: account, bip32: hd, index: index);
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ class CWBitcoin extends Bitcoin {
|
|||
address: addr.address,
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isHidden))
|
||||
isChange: addr.isChange))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
@ -379,16 +379,16 @@ class CWBitcoin extends Bitcoin {
|
|||
String? address;
|
||||
switch (dInfoCopy.scriptType) {
|
||||
case "p2wpkh":
|
||||
address = generateP2WPKHAddress(hd: hd, network: network, index: 0);
|
||||
address = P2wpkhAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network);
|
||||
break;
|
||||
case "p2pkh":
|
||||
address = generateP2PKHAddress(hd: hd, network: network, index: 0);
|
||||
address = P2pkhAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network);
|
||||
break;
|
||||
case "p2wpkh-p2sh":
|
||||
address = generateP2SHAddress(hd: hd, network: network, index: 0);
|
||||
address = P2shAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network);
|
||||
break;
|
||||
case "p2tr":
|
||||
address = generateP2TRAddress(hd: hd, network: network, index: 0);
|
||||
address = P2trAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
|
@ -526,7 +526,7 @@ class CWBitcoin extends Bitcoin {
|
|||
address: addr.address,
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isHidden))
|
||||
isChange: addr.isChange))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
@ -541,7 +541,7 @@ class CWBitcoin extends Bitcoin {
|
|||
address: addr.address,
|
||||
txCount: addr.txCount,
|
||||
balance: addr.balance,
|
||||
isChange: addr.isHidden))
|
||||
isChange: addr.isChange))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
@ -574,6 +574,11 @@ class CWBitcoin extends Bitcoin {
|
|||
return bitcoinWallet.isTestnet;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> registerSilentPaymentsKey(Object wallet, bool active) async {
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> checkIfMempoolAPIIsEnabled(Object wallet) async {
|
||||
final bitcoinWallet = wallet as ElectrumWallet;
|
||||
|
|
|
@ -48,6 +48,7 @@ class PreferencesKey {
|
|||
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
||||
static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
|
||||
static const silentPaymentsAlwaysScan = 'silentPaymentsAlwaysScan';
|
||||
static const silentPaymentsKeyRegistered = 'silentPaymentsKeyRegistered';
|
||||
static const mwebCardDisplay = 'mwebCardDisplay';
|
||||
static const mwebEnabled = 'mwebEnabled';
|
||||
static const hasEnabledMwebBefore = 'hasEnabledMwebBefore';
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -37,7 +34,6 @@ class AddressList extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _AddressListState extends State<AddressList> {
|
||||
|
||||
bool showHiddenAddresses = false;
|
||||
|
||||
void _toggleHiddenAddresses() {
|
||||
|
@ -131,7 +127,8 @@ class _AddressListState extends State<AddressList> {
|
|||
showTrailingButton: widget.addressListViewModel.showAddManualAddresses,
|
||||
showSearchButton: true,
|
||||
onSearchCallback: updateItems,
|
||||
trailingButtonTap: () => Navigator.of(context).pushNamed(Routes.newSubaddress).then((value) {
|
||||
trailingButtonTap: () =>
|
||||
Navigator.of(context).pushNamed(Routes.newSubaddress).then((value) {
|
||||
updateItems(); // refresh the new address
|
||||
}),
|
||||
trailingIcon: Icon(
|
||||
|
@ -148,7 +145,8 @@ class _AddressListState extends State<AddressList> {
|
|||
cell = Container();
|
||||
} else {
|
||||
cell = Observer(builder: (_) {
|
||||
final isCurrent = item.address == widget.addressListViewModel.address.address && editable;
|
||||
final isCurrent =
|
||||
item.address == widget.addressListViewModel.address.address && editable;
|
||||
final backgroundColor = isCurrent
|
||||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileBackgroundColor
|
||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesBackgroundColor;
|
||||
|
@ -156,17 +154,17 @@ class _AddressListState extends State<AddressList> {
|
|||
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileTextColor
|
||||
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;
|
||||
|
||||
|
||||
return AddressCell.fromItem(
|
||||
item,
|
||||
isCurrent: isCurrent,
|
||||
hasBalance: widget.addressListViewModel.isBalanceAvailable,
|
||||
hasReceived: widget.addressListViewModel.isReceivedAvailable,
|
||||
// hasReceived:
|
||||
backgroundColor: (kDebugMode && item.isHidden) ?
|
||||
Theme.of(context).colorScheme.error :
|
||||
(kDebugMode && item.isManual) ? Theme.of(context).colorScheme.error.withBlue(255) :
|
||||
backgroundColor,
|
||||
backgroundColor: (kDebugMode && item.isHidden)
|
||||
? Theme.of(context).colorScheme.error
|
||||
: (kDebugMode && item.isManual)
|
||||
? Theme.of(context).colorScheme.error.withBlue(255)
|
||||
: backgroundColor,
|
||||
textColor: textColor,
|
||||
onTap: (_) {
|
||||
if (widget.onSelect != null) {
|
||||
|
@ -176,7 +174,9 @@ class _AddressListState extends State<AddressList> {
|
|||
widget.addressListViewModel.setAddress(item);
|
||||
},
|
||||
onEdit: editable
|
||||
? () => Navigator.of(context).pushNamed(Routes.newSubaddress, arguments: item).then((value) {
|
||||
? () => Navigator.of(context)
|
||||
.pushNamed(Routes.newSubaddress, arguments: item)
|
||||
.then((value) {
|
||||
updateItems(); // refresh the new address
|
||||
})
|
||||
: null,
|
||||
|
@ -190,8 +190,8 @@ class _AddressListState extends State<AddressList> {
|
|||
return index != 0
|
||||
? cell
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(30), topRight: Radius.circular(30)),
|
||||
borderRadius:
|
||||
BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30)),
|
||||
child: cell,
|
||||
);
|
||||
},
|
||||
|
@ -202,5 +202,4 @@ class _AddressListState extends State<AddressList> {
|
|||
await widget.addressListViewModel.toggleHideAddress(item);
|
||||
updateItems();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,13 @@ class SilentPaymentsSettingsPage extends BasePage {
|
|||
_silentPaymentsSettingsViewModel.setSilentPaymentsAlwaysScan(value);
|
||||
},
|
||||
),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.silent_payments_register_key,
|
||||
value: _silentPaymentsSettingsViewModel.silentPaymentsAlwaysScan,
|
||||
onValueChange: (_, bool value) {
|
||||
_silentPaymentsSettingsViewModel.setSilentPaymentsAlwaysScan(value);
|
||||
},
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.silent_payments_scanning,
|
||||
handler: (BuildContext context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
|
|
|
@ -114,6 +114,7 @@ abstract class SettingsStoreBase with Store {
|
|||
required this.customBitcoinFeeRate,
|
||||
required this.silentPaymentsCardDisplay,
|
||||
required this.silentPaymentsAlwaysScan,
|
||||
required this.silentPaymentsKeyRegistered,
|
||||
required this.mwebAlwaysScan,
|
||||
required this.mwebCardDisplay,
|
||||
required this.mwebEnabled,
|
||||
|
@ -344,8 +345,8 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
reaction(
|
||||
(_) => bitcoinSeedType,
|
||||
(BitcoinSeedType bitcoinSeedType) => sharedPreferences.setInt(
|
||||
PreferencesKey.bitcoinSeedType, bitcoinSeedType.raw));
|
||||
(BitcoinSeedType bitcoinSeedType) =>
|
||||
sharedPreferences.setInt(PreferencesKey.bitcoinSeedType, bitcoinSeedType.raw));
|
||||
|
||||
reaction(
|
||||
(_) => nanoSeedType,
|
||||
|
@ -428,8 +429,10 @@ abstract class SettingsStoreBase with Store {
|
|||
reaction((_) => useTronGrid,
|
||||
(bool useTronGrid) => _sharedPreferences.setBool(PreferencesKey.useTronGrid, useTronGrid));
|
||||
|
||||
reaction((_) => useMempoolFeeAPI,
|
||||
(bool useMempoolFeeAPI) => _sharedPreferences.setBool(PreferencesKey.useMempoolFeeAPI, useMempoolFeeAPI));
|
||||
reaction(
|
||||
(_) => useMempoolFeeAPI,
|
||||
(bool useMempoolFeeAPI) =>
|
||||
_sharedPreferences.setBool(PreferencesKey.useMempoolFeeAPI, useMempoolFeeAPI));
|
||||
|
||||
reaction((_) => defaultNanoRep,
|
||||
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
|
||||
|
@ -559,6 +562,11 @@ abstract class SettingsStoreBase with Store {
|
|||
(bool silentPaymentsAlwaysScan) => _sharedPreferences.setBool(
|
||||
PreferencesKey.silentPaymentsAlwaysScan, silentPaymentsAlwaysScan));
|
||||
|
||||
reaction(
|
||||
(_) => silentPaymentsKeyRegistered,
|
||||
(bool silentPaymentsKeyRegistered) => _sharedPreferences.setBool(
|
||||
PreferencesKey.silentPaymentsKeyRegistered, silentPaymentsKeyRegistered));
|
||||
|
||||
reaction(
|
||||
(_) => mwebAlwaysScan,
|
||||
(bool mwebAlwaysScan) =>
|
||||
|
@ -790,6 +798,9 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool silentPaymentsAlwaysScan;
|
||||
|
||||
@observable
|
||||
bool silentPaymentsKeyRegistered;
|
||||
|
||||
@observable
|
||||
bool mwebAlwaysScan;
|
||||
|
||||
|
@ -959,6 +970,8 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true;
|
||||
final silentPaymentsAlwaysScan =
|
||||
sharedPreferences.getBool(PreferencesKey.silentPaymentsAlwaysScan) ?? false;
|
||||
final silentPaymentsKeyRegistered =
|
||||
sharedPreferences.getBool(PreferencesKey.silentPaymentsKeyRegistered) ?? false;
|
||||
final mwebAlwaysScan = sharedPreferences.getBool(PreferencesKey.mwebAlwaysScan) ?? false;
|
||||
final mwebCardDisplay = sharedPreferences.getBool(PreferencesKey.mwebCardDisplay) ?? true;
|
||||
final mwebEnabled = sharedPreferences.getBool(PreferencesKey.mwebEnabled) ?? false;
|
||||
|
@ -1230,6 +1243,7 @@ abstract class SettingsStoreBase with Store {
|
|||
customBitcoinFeeRate: customBitcoinFeeRate,
|
||||
silentPaymentsCardDisplay: silentPaymentsCardDisplay,
|
||||
silentPaymentsAlwaysScan: silentPaymentsAlwaysScan,
|
||||
silentPaymentsKeyRegistered: silentPaymentsKeyRegistered,
|
||||
mwebAlwaysScan: mwebAlwaysScan,
|
||||
mwebCardDisplay: mwebCardDisplay,
|
||||
mwebEnabled: mwebEnabled,
|
||||
|
@ -1396,6 +1410,8 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true;
|
||||
silentPaymentsAlwaysScan =
|
||||
sharedPreferences.getBool(PreferencesKey.silentPaymentsAlwaysScan) ?? false;
|
||||
silentPaymentsKeyRegistered =
|
||||
sharedPreferences.getBool(PreferencesKey.silentPaymentsKeyRegistered) ?? false;
|
||||
mwebAlwaysScan = sharedPreferences.getBool(PreferencesKey.mwebAlwaysScan) ?? false;
|
||||
mwebCardDisplay = sharedPreferences.getBool(PreferencesKey.mwebCardDisplay) ?? true;
|
||||
mwebEnabled = sharedPreferences.getBool(PreferencesKey.mwebEnabled) ?? false;
|
||||
|
@ -1658,7 +1674,8 @@ abstract class SettingsStoreBase with Store {
|
|||
deviceName = windowsInfo.productName;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
print('likely digitalProductId is null wait till https://github.com/fluttercommunity/plus_plugins/pull/3188 is merged');
|
||||
print(
|
||||
'likely digitalProductId is null wait till https://github.com/fluttercommunity/plus_plugins/pull/3188 is merged');
|
||||
deviceName = "Windows Device";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,4 +30,10 @@ abstract class SilentPaymentsSettingsViewModelBase with Store {
|
|||
_settingsStore.silentPaymentsAlwaysScan = value;
|
||||
if (value) bitcoin!.setScanningActive(_wallet, true);
|
||||
}
|
||||
|
||||
@action
|
||||
void registerSilentPaymentsKey(bool value) {
|
||||
_settingsStore.silentPaymentsKeyRegistered = value;
|
||||
bitcoin!.registerSilentPaymentsKey(_wallet, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "حدد المدفوعات الصامتة دائمًا المسح الضوئي",
|
||||
"silent_payments_disclaimer": "العناوين الجديدة ليست هويات جديدة. إنها إعادة استخدام هوية موجودة مع ملصق مختلف.",
|
||||
"silent_payments_display_card": "عرض بطاقة المدفوعات الصامتة",
|
||||
"silent_payments_register_key": "سجل عرض مفتاح المسح الأسرع",
|
||||
"silent_payments_scan_from_date": "فحص من التاريخ",
|
||||
"silent_payments_scan_from_date_or_blockheight": "يرجى إدخال ارتفاع الكتلة الذي تريد بدء المسح الضوئي للمدفوعات الصامتة الواردة ، أو استخدام التاريخ بدلاً من ذلك. يمكنك اختيار ما إذا كانت المحفظة تواصل مسح كل كتلة ، أو تتحقق فقط من الارتفاع المحدد.",
|
||||
"silent_payments_scan_from_height": "فحص من ارتفاع الكتلة",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Задайте мълчаливи плащания винаги сканиране",
|
||||
"silent_payments_disclaimer": "Новите адреси не са нови идентичности. Това е повторна употреба на съществуваща идентичност с различен етикет.",
|
||||
"silent_payments_display_card": "Показване на безшумни плащания карта",
|
||||
"silent_payments_register_key": "Регистрирайте ключа за преглед на по -бързото сканиране",
|
||||
"silent_payments_scan_from_date": "Сканиране от дата",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Моля, въведете височината на блока, която искате да започнете да сканирате за входящи безшумни плащания, или вместо това използвайте датата. Можете да изберете дали портфейлът продължава да сканира всеки блок или проверява само определената височина.",
|
||||
"silent_payments_scan_from_height": "Сканиране от височината на блока",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Nastavit tiché platby vždy skenování",
|
||||
"silent_payments_disclaimer": "Nové adresy nejsou nové identity. Je to opětovné použití existující identity s jiným štítkem.",
|
||||
"silent_payments_display_card": "Zobrazit kartu Silent Payments",
|
||||
"silent_payments_register_key": "Zobrazení zaregistrujte klíč pro rychlejší skenování",
|
||||
"silent_payments_scan_from_date": "Skenovat od data",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Zadejte výšku bloku, kterou chcete začít skenovat, zda jsou přicházející tiché platby, nebo místo toho použijte datum. Můžete si vybrat, zda peněženka pokračuje v skenování každého bloku nebo zkontroluje pouze zadanou výšku.",
|
||||
"silent_payments_scan_from_height": "Skenování z výšky bloku",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "Setzen Sie stille Zahlungen immer scannen",
|
||||
"silent_payments_disclaimer": "Neue Adressen sind keine neuen Identitäten. Es ist eine Wiederverwendung einer bestehenden Identität mit einem anderen Etikett.",
|
||||
"silent_payments_display_card": "Zeigen Sie stille Zahlungskarte",
|
||||
"silent_payments_register_key": "Registrieren Sie die Ansichtsschlüssel für schnelleres Scannen",
|
||||
"silent_payments_scan_from_date": "Scan ab Datum",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Bitte geben Sie die Blockhöhe ein, die Sie für eingehende stille Zahlungen scannen möchten, oder verwenden Sie stattdessen das Datum. Sie können wählen, ob die Wallet jeden Block scannt oder nur die angegebene Höhe überprüft.",
|
||||
"silent_payments_scan_from_height": "Scan aus der Blockhöhe scannen",
|
||||
|
|
|
@ -712,6 +712,7 @@
|
|||
"silent_payments_always_scan": "Set Silent Payments always scanning",
|
||||
"silent_payments_disclaimer": "New addresses are not new identities. It is a re-use of an existing identity with a different label.",
|
||||
"silent_payments_display_card": "Show Silent Payments card",
|
||||
"silent_payments_register_key": "Register view key for faster scanning",
|
||||
"silent_payments_scan_from_date": "Scan from date",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Please enter the block height you want to start scanning for incoming Silent Payments or use the date instead. You can choose if the wallet continues scanning every block, or checks only the specified height.",
|
||||
"silent_payments_scan_from_height": "Scan from block height",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "Establecer pagos silenciosos siempre escaneando",
|
||||
"silent_payments_disclaimer": "Las nuevas direcciones no son nuevas identidades. Es una reutilización de una identidad existente con una etiqueta diferente.",
|
||||
"silent_payments_display_card": "Mostrar tarjeta de pagos silenciosos",
|
||||
"silent_payments_register_key": "Clave de vista de registro para escaneo más rápido",
|
||||
"silent_payments_scan_from_date": "Escanear desde la fecha",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Ingresa la altura de bloque que desea comenzar a escanear para pagos silenciosos entrantes, o usa la fecha en su lugar. Puedes elegir si la billetera continúa escaneando cada bloque, o verifica solo la altura especificada.",
|
||||
"silent_payments_scan_from_height": "Escanear desde la altura de bloque específico",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Définir les paiements silencieux toujours à la scanne",
|
||||
"silent_payments_disclaimer": "Les nouvelles adresses ne sont pas de nouvelles identités. Il s'agit d'une réutilisation d'une identité existante avec une étiquette différente.",
|
||||
"silent_payments_display_card": "Afficher la carte de paiement silencieuse",
|
||||
"silent_payments_register_key": "Enregistrez la touche Afficher pour une analyse plus rapide",
|
||||
"silent_payments_scan_from_date": "Analyser à partir de la date",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Veuillez saisir la hauteur du bloc que vous souhaitez commencer à scanner pour les paiements silencieux entrants, ou utilisez la date à la place. Vous pouvez choisir si le portefeuille continue de numériser chaque bloc ou ne vérifie que la hauteur spécifiée.",
|
||||
"silent_payments_scan_from_height": "Scan à partir de la hauteur du bloc",
|
||||
|
|
|
@ -711,6 +711,7 @@
|
|||
"silent_payments_always_scan": "Saita biya na shiru koyaushe",
|
||||
"silent_payments_disclaimer": "Sabbin adiresoshin ba sabon tsari bane. Wannan shine sake amfani da asalin asalin tare da wata alama daban.",
|
||||
"silent_payments_display_card": "Nuna katin silent",
|
||||
"silent_payments_register_key": "Yi rijista mabuɗin don bincika sauri",
|
||||
"silent_payments_scan_from_date": "Scan daga kwanan wata",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Da fatan za a shigar da toshe wurin da kake son fara bincika don biyan silins mai shigowa, ko, yi amfani da kwanan wata. Zaka iya zabar idan walat ɗin ya ci gaba da bincika kowane toshe, ko duba tsinkaye da aka ƙayyade.",
|
||||
"silent_payments_scan_from_height": "Scan daga tsayin daka",
|
||||
|
|
|
@ -711,6 +711,7 @@
|
|||
"silent_payments_always_scan": "मूक भुगतान हमेशा स्कैनिंग सेट करें",
|
||||
"silent_payments_disclaimer": "नए पते नई पहचान नहीं हैं। यह एक अलग लेबल के साथ एक मौजूदा पहचान का पुन: उपयोग है।",
|
||||
"silent_payments_display_card": "मूक भुगतान कार्ड दिखाएं",
|
||||
"silent_payments_register_key": "तेजी से स्कैनिंग के लिए रजिस्टर व्यू कुंजी",
|
||||
"silent_payments_scan_from_date": "तिथि से स्कैन करना",
|
||||
"silent_payments_scan_from_date_or_blockheight": "कृपया उस ब्लॉक ऊंचाई दर्ज करें जिसे आप आने वाले मूक भुगतान के लिए स्कैन करना शुरू करना चाहते हैं, या, इसके बजाय तारीख का उपयोग करें। आप चुन सकते हैं कि क्या वॉलेट हर ब्लॉक को स्कैन करना जारी रखता है, या केवल निर्दिष्ट ऊंचाई की जांच करता है।",
|
||||
"silent_payments_scan_from_height": "ब्लॉक ऊंचाई से स्कैन करें",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Postavite tiho plaćanje uvijek skeniranje",
|
||||
"silent_payments_disclaimer": "Nove adrese nisu novi identiteti. To je ponovna upotreba postojećeg identiteta s drugom oznakom.",
|
||||
"silent_payments_display_card": "Prikaži karticu tihih plaćanja",
|
||||
"silent_payments_register_key": "Registrirajte ključ za brže skeniranje",
|
||||
"silent_payments_scan_from_date": "Skeniranje iz datuma",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Unesite visinu bloka koju želite započeti skeniranje za dolazna tiha plaćanja ili umjesto toga upotrijebite datum. Možete odabrati da li novčanik nastavlja skenirati svaki blok ili provjerava samo navedenu visinu.",
|
||||
"silent_payments_scan_from_height": "Skeniranje s visine bloka",
|
||||
|
|
|
@ -701,6 +701,7 @@
|
|||
"silent_payments_always_scan": "Միացնել Լուռ Վճարումներ մշտական սկանավորումը",
|
||||
"silent_payments_disclaimer": "Նոր հասցեները նոր ինքնություն չեն։ Դա այլ պիտակով գոյություն ունեցող ինքնության վերագործածում է",
|
||||
"silent_payments_display_card": "Ցուցադրել Լուռ Վճարումներ քարտը",
|
||||
"silent_payments_register_key": "Գրանցեք Դիտել ստեղնը `ավելի արագ սկանավորման համար",
|
||||
"silent_payments_scan_from_date": "Սկանավորել ամսաթվից",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Խնդրում ենք մուտքագրել բլոկի բարձրությունը, որտեղից դուք ցանկանում եք սկսել սկանավորել մուտքային Լուռ Վճարումները կամ տեղափոխել ամսաթվի փոխարեն։ Դուք կարող եք ընտրել, արդյոք դրամապանակը շարունակելու է սկանավորել ամեն բլոկ կամ ստուգել միայն սահմանված բարձրությունը",
|
||||
"silent_payments_scan_from_height": "Բլոկի բարձրությունից սկանավորել",
|
||||
|
|
|
@ -712,6 +712,7 @@
|
|||
"silent_payments_always_scan": "Tetapkan pembayaran diam selalu pemindaian",
|
||||
"silent_payments_disclaimer": "Alamat baru bukanlah identitas baru. Ini adalah penggunaan kembali identitas yang ada dengan label yang berbeda.",
|
||||
"silent_payments_display_card": "Tunjukkan kartu pembayaran diam",
|
||||
"silent_payments_register_key": "Daftar Kunci Lihat untuk pemindaian yang lebih cepat",
|
||||
"silent_payments_scan_from_date": "Pindai dari tanggal",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Harap masukkan ketinggian blok yang ingin Anda mulai pemindaian untuk pembayaran diam yang masuk, atau, gunakan tanggal sebagai gantinya. Anda dapat memilih jika dompet terus memindai setiap blok, atau memeriksa hanya ketinggian yang ditentukan.",
|
||||
"silent_payments_scan_from_height": "Pindai dari Tinggi Blok",
|
||||
|
|
|
@ -711,6 +711,7 @@
|
|||
"silent_payments_always_scan": "Impostare i pagamenti silenziosi che scansionano sempre",
|
||||
"silent_payments_disclaimer": "I nuovi indirizzi non sono nuove identità. È un riutilizzo di un'identità esistente con un'etichetta diversa.",
|
||||
"silent_payments_display_card": "Mostra la carta di pagamenti silenziosi",
|
||||
"silent_payments_register_key": "Registra la chiave di visualizzazione per una scansione più veloce",
|
||||
"silent_payments_scan_from_date": "Scansionare dalla data",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Inserisci l'altezza del blocco che si desidera iniziare la scansione per i pagamenti silenziosi in arrivo o, utilizza invece la data. Puoi scegliere se il portafoglio continua a scansionare ogni blocco o controlla solo l'altezza specificata.",
|
||||
"silent_payments_scan_from_height": "Scansione dall'altezza del blocco",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "サイレント決済を常にスキャンします",
|
||||
"silent_payments_disclaimer": "新しいアドレスは新しいアイデンティティではありません。これは、異なるラベルを持つ既存のアイデンティティの再利用です。",
|
||||
"silent_payments_display_card": "サイレントペイメントカードを表示します",
|
||||
"silent_payments_register_key": "登録キーを登録して、より速いスキャンを行います",
|
||||
"silent_payments_scan_from_date": "日付からスキャンします",
|
||||
"silent_payments_scan_from_date_or_blockheight": "着信のサイレント決済のためにスキャンを開始するブロックの高さを入力するか、代わりに日付を使用してください。ウォレットがすべてのブロックをスキャンし続けるか、指定された高さのみをチェックするかどうかを選択できます。",
|
||||
"silent_payments_scan_from_height": "ブロックの高さからスキャンします",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "무음금을 항상 스캔합니다",
|
||||
"silent_payments_disclaimer": "새로운 주소는 새로운 정체성이 아닙니다. 다른 레이블로 기존 신원을 재사용하는 것입니다.",
|
||||
"silent_payments_display_card": "사일런트 지불 카드 표시",
|
||||
"silent_payments_register_key": "더 빠른 스캔을 위해보기 키 등록 키",
|
||||
"silent_payments_scan_from_date": "날짜부터 스캔하십시오",
|
||||
"silent_payments_scan_from_date_or_blockheight": "들어오는 사일런트 결제를 위해 스캔을 시작하려는 블록 높이를 입력하거나 대신 날짜를 사용하십시오. 지갑이 모든 블록을 계속 스캔하는지 여부를 선택하거나 지정된 높이 만 확인할 수 있습니다.",
|
||||
"silent_payments_scan_from_height": "블록 높이에서 스캔하십시오",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "အမြဲတမ်း scanning အမြဲ scanning",
|
||||
"silent_payments_disclaimer": "လိပ်စာအသစ်များသည်အထောက်အထားအသစ်များမဟုတ်ပါ။ ၎င်းသည်ကွဲပြားခြားနားသောတံဆိပ်ဖြင့်ရှိပြီးသားဝိသေသလက်ခဏာကိုပြန်လည်အသုံးပြုခြင်းဖြစ်သည်။",
|
||||
"silent_payments_display_card": "အသံတိတ်ငွေပေးချေမှုကဒ်ကိုပြပါ",
|
||||
"silent_payments_register_key": "ပိုမိုမြန်ဆန်သောစကင်ဖတ်စစ်ဆေးရန်အတွက်ကြည့်ပါ",
|
||||
"silent_payments_scan_from_date": "ရက်စွဲမှစကင်ဖတ်ပါ",
|
||||
"silent_payments_scan_from_date_or_blockheight": "ကျေးဇူးပြု. သင်ဝင်လာသောအသံတိတ်ငွေပေးချေမှုအတွက်သင်စကင်ဖတ်စစ်ဆေးလိုသည့်အမြင့်ကိုဖြည့်ပါ။ သို့မဟုတ်နေ့စွဲကိုသုံးပါ။ Wallet သည်လုပ်ကွက်တိုင်းကိုဆက်လက်စကင်ဖတ်စစ်ဆေးပါကသို့မဟုတ်သတ်မှတ်ထားသောအမြင့်ကိုသာစစ်ဆေးပါကသင်ရွေးချယ်နိုင်သည်။",
|
||||
"silent_payments_scan_from_height": "ပိတ်ပင်တားဆီးမှုအမြင့်ကနေ scan",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Stel stille betalingen in het scannen",
|
||||
"silent_payments_disclaimer": "Nieuwe adressen zijn geen nieuwe identiteiten. Het is een hergebruik van een bestaande identiteit met een ander label.",
|
||||
"silent_payments_display_card": "Toon stille betalingskaart",
|
||||
"silent_payments_register_key": "Registerweergave Key voor sneller scannen",
|
||||
"silent_payments_scan_from_date": "Scan vanaf datum",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Voer de blokhoogte in die u wilt beginnen met scannen op inkomende stille betalingen, of gebruik in plaats daarvan de datum. U kunt kiezen of de portemonnee elk blok blijft scannen of alleen de opgegeven hoogte controleert.",
|
||||
"silent_payments_scan_from_height": "Scan van blokhoogte",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Ustaw ciche płatności zawsze skanowanie",
|
||||
"silent_payments_disclaimer": "Nowe adresy nie są nową tożsamością. Jest to ponowne wykorzystanie istniejącej tożsamości z inną etykietą.",
|
||||
"silent_payments_display_card": "Pokaż kartę Silent Payments",
|
||||
"silent_payments_register_key": "Zarejestruj się Wyświetl Klucz do szybszego skanowania",
|
||||
"silent_payments_scan_from_date": "Skanuj z daty",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Wprowadź wysokość bloku, którą chcesz rozpocząć skanowanie w poszukiwaniu cichej płatności lub zamiast tego skorzystaj z daty. Możesz wybrać, czy portfel kontynuuje skanowanie każdego bloku, lub sprawdza tylko określoną wysokość.",
|
||||
"silent_payments_scan_from_height": "Skanuj z wysokości bloku",
|
||||
|
|
|
@ -711,6 +711,7 @@
|
|||
"silent_payments_always_scan": "Defina pagamentos silenciosos sempre escaneando",
|
||||
"silent_payments_disclaimer": "Novos endereços não são novas identidades. É uma reutilização de uma identidade existente com um rótulo diferente.",
|
||||
"silent_payments_display_card": "Mostrar cartão de pagamento silencioso",
|
||||
"silent_payments_register_key": "Chave de exibição de registro para digitalização mais rápida",
|
||||
"silent_payments_scan_from_date": "Escanear a partir da data",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Por favor, insira a altura do bloco que deseja iniciar o escaneamento para obter pagamentos silenciosos ou use a data. Você pode escolher se a carteira continua escaneando cada bloco ou verifica apenas a altura especificada.",
|
||||
"silent_payments_scan_from_height": "Escanear a partir da altura do bloco",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "Установить молчаливые платежи всегда сканирование",
|
||||
"silent_payments_disclaimer": "Новые адреса не являются новыми личностями. Это повторное использование существующей идентичности с другой этикеткой.",
|
||||
"silent_payments_display_card": "Показать бесшумную платежную карту",
|
||||
"silent_payments_register_key": "Зарегистрируйте ключ просмотра для более быстрого сканирования",
|
||||
"silent_payments_scan_from_date": "Сканирование с даты",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Пожалуйста, введите высоту блока, которую вы хотите начать сканирование для входящих молчаливых платежей, или вместо этого используйте дату. Вы можете выбрать, продолжает ли кошелек сканировать каждый блок или проверять только указанную высоту.",
|
||||
"silent_payments_scan_from_height": "Сканирование с высоты блока",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "ตั้งค่าการชำระเงินแบบเงียบเสมอ",
|
||||
"silent_payments_disclaimer": "ที่อยู่ใหม่ไม่ใช่ตัวตนใหม่ มันเป็นการใช้ซ้ำของตัวตนที่มีอยู่ด้วยฉลากที่แตกต่างกัน",
|
||||
"silent_payments_display_card": "แสดงบัตร Silent Payments",
|
||||
"silent_payments_register_key": "ลงทะเบียนคีย์มุมมองสำหรับการสแกนที่เร็วขึ้น",
|
||||
"silent_payments_scan_from_date": "สแกนตั้งแต่วันที่",
|
||||
"silent_payments_scan_from_date_or_blockheight": "โปรดป้อนความสูงของบล็อกที่คุณต้องการเริ่มการสแกนสำหรับการชำระเงินแบบเงียบ ๆ หรือใช้วันที่แทน คุณสามารถเลือกได้ว่ากระเป๋าเงินยังคงสแกนทุกบล็อกหรือตรวจสอบความสูงที่ระบุเท่านั้น",
|
||||
"silent_payments_scan_from_height": "สแกนจากความสูงของบล็อก",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Itakda ang mga tahimik na pagbabayad na laging nag-scan",
|
||||
"silent_payments_disclaimer": "Ang mga bagong address ay hindi mga bagong pagkakakilanlan. Ito ay isang muling paggamit ng isang umiiral na pagkakakilanlan na may ibang label.",
|
||||
"silent_payments_display_card": "Ipakita ang Silent Payment Card",
|
||||
"silent_payments_register_key": "Magrehistro ng View Key para sa mas mabilis na pag -scan",
|
||||
"silent_payments_scan_from_date": "I-scan mula sa petsa",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Mangyaring ipasok ang block height na gusto mong simulan ang pag-scan para sa papasok na tahimik na pagbabayad, o, gamitin ang petsa sa halip. Maaari kang pumili kung ang wallet ay patuloy na pag-scan sa bawat bloke, o suriin lamang ang tinukoy na taas.",
|
||||
"silent_payments_scan_from_height": "I-scan mula sa block height",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "Sessiz ödemeleri her zaman tarama ayarlayın",
|
||||
"silent_payments_disclaimer": "Yeni adresler yeni kimlikler değildir. Farklı bir etikete sahip mevcut bir kimliğin yeniden kullanımıdır.",
|
||||
"silent_payments_display_card": "Sessiz Ödeme Kartı Göster",
|
||||
"silent_payments_register_key": "Daha hızlı tarama için tuşunu kaydet",
|
||||
"silent_payments_scan_from_date": "Tarihten tarama",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Lütfen gelen sessiz ödemeler için taramaya başlamak istediğiniz blok yüksekliğini girin veya bunun yerine tarihi kullanın. Cüzdanın her bloğu taramaya devam edip etmediğini veya yalnızca belirtilen yüksekliği kontrol edip etmediğini seçebilirsiniz.",
|
||||
"silent_payments_scan_from_height": "Blok yüksekliğinden tarama",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "Встановити мовчазні платежі завжди сканувати",
|
||||
"silent_payments_disclaimer": "Нові адреси - це не нові ідентичності. Це повторне використання існуючої ідентичності з іншою етикеткою.",
|
||||
"silent_payments_display_card": "Покажіть безшумну карту платежів",
|
||||
"silent_payments_register_key": "Зареєструйтесь ключ для більш швидкого сканування",
|
||||
"silent_payments_scan_from_date": "Сканувати з дати",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Введіть висоту блоку, яку ви хочете почати сканувати для вхідних мовчазних платежів, або скористайтеся датою замість цього. Ви можете вибрати, якщо гаманець продовжує сканувати кожен блок, або перевіряє лише вказану висоту.",
|
||||
"silent_payments_scan_from_height": "Сканування від висоти блоку",
|
||||
|
|
|
@ -711,6 +711,7 @@
|
|||
"silent_payments_always_scan": "خاموش ادائیگی ہمیشہ اسکیننگ کریں",
|
||||
"silent_payments_disclaimer": "نئے پتے نئی شناخت نہیں ہیں۔ یہ ایک مختلف لیبل کے ساتھ موجودہ شناخت کا دوبارہ استعمال ہے۔",
|
||||
"silent_payments_display_card": "خاموش ادائیگی کارڈ دکھائیں",
|
||||
"silent_payments_register_key": "تیزی سے اسکیننگ کے لئے کلید کو رجسٹر کریں",
|
||||
"silent_payments_scan_from_date": "تاریخ سے اسکین کریں",
|
||||
"silent_payments_scan_from_date_or_blockheight": "براہ کرم بلاک اونچائی میں داخل ہوں جس سے آپ آنے والی خاموش ادائیگیوں کے لئے اسکیننگ شروع کرنا چاہتے ہیں ، یا اس کے بجائے تاریخ کا استعمال کریں۔ آپ یہ منتخب کرسکتے ہیں کہ اگر پرس ہر بلاک کو اسکیننگ جاری رکھے ہوئے ہے ، یا صرف مخصوص اونچائی کی جانچ پڑتال کرتا ہے۔",
|
||||
"silent_payments_scan_from_height": "بلاک اونچائی سے اسکین کریں",
|
||||
|
|
|
@ -702,6 +702,7 @@
|
|||
"silent_payments_always_scan": "Đặt Thanh toán im lặng luôn quét",
|
||||
"silent_payments_disclaimer": "Địa chỉ mới không phải là danh tính mới. Đây là việc tái sử dụng một danh tính hiện có với nhãn khác.",
|
||||
"silent_payments_display_card": "Hiển thị thẻ Thanh toán im lặng",
|
||||
"silent_payments_register_key": "Đăng ký khóa xem để quét nhanh hơn",
|
||||
"silent_payments_scan_from_date": "Quét từ ngày",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Vui lòng nhập chiều cao khối bạn muốn bắt đầu quét cho các thanh toán im lặng đến, hoặc, sử dụng ngày thay thế. Bạn có thể chọn nếu ví tiếp tục quét mỗi khối, hoặc chỉ kiểm tra chiều cao đã chỉ định.",
|
||||
"silent_payments_scan_from_height": "Quét từ chiều cao khối",
|
||||
|
|
|
@ -710,6 +710,7 @@
|
|||
"silent_payments_always_scan": "Ṣeto awọn sisanwo ipalọlọ nigbagbogbo n ṣatunṣe",
|
||||
"silent_payments_disclaimer": "Awọn adirẹsi tuntun kii ṣe awọn idanimọ tuntun. O jẹ yiyan ti idanimọ ti o wa pẹlu aami oriṣiriṣi.",
|
||||
"silent_payments_display_card": "Ṣafihan kaadi isanwo ti o dakẹ",
|
||||
"silent_payments_register_key": "Forukọsilẹ Wo bọtini Window fun Cranding yiyara",
|
||||
"silent_payments_scan_from_date": "Scan lati ọjọ",
|
||||
"silent_payments_scan_from_date_or_blockheight": "Jọwọ tẹ giga idibo ti o fẹ bẹrẹ ọlọjẹ fun awọn sisanwo ipalọlọ, tabi, lo ọjọ dipo. O le yan ti apamọwọ naa tẹsiwaju nṣapẹẹrẹ gbogbo bulọọki, tabi ṣayẹwo nikan giga ti o sọ tẹlẹ.",
|
||||
"silent_payments_scan_from_height": "Scan lati Iga Iga",
|
||||
|
|
|
@ -709,6 +709,7 @@
|
|||
"silent_payments_always_scan": "设置无声付款总是扫描",
|
||||
"silent_payments_disclaimer": "新地址不是新的身份。这是重复使用具有不同标签的现有身份。",
|
||||
"silent_payments_display_card": "显示无声支付卡",
|
||||
"silent_payments_register_key": "注册查看密钥以进行更快的扫描",
|
||||
"silent_payments_scan_from_date": "从日期开始扫描",
|
||||
"silent_payments_scan_from_date_or_blockheight": "请输入您要开始扫描输入静音付款的块高度,或者使用日期。您可以选择钱包是否继续扫描每个块,或仅检查指定的高度。",
|
||||
"silent_payments_scan_from_height": "从块高度扫描",
|
||||
|
|
|
@ -102,7 +102,6 @@ import 'package:blockchain_utils/blockchain_utils.dart';
|
|||
import 'package:bip39/bip39.dart' as bip39;
|
||||
""";
|
||||
const bitcoinCWHeaders = """
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||
import 'package:cw_bitcoin/electrum.dart';
|
||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||
|
@ -216,6 +215,7 @@ abstract class Bitcoin {
|
|||
int getEstimatedFeeWithFeeRate(Object wallet, int feeRate, int? amount,
|
||||
{int? outputsCount, int? size});
|
||||
int feeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size});
|
||||
Future<void> registerSilentPaymentsKey(Object wallet, bool active);
|
||||
Future<bool> checkIfMempoolAPIIsEnabled(Object wallet);
|
||||
Future<int> getHeightByDate({required DateTime date, bool? bitcoinMempoolAPIEnabled});
|
||||
int getLitecoinHeightByDate({required DateTime date});
|
||||
|
|
Loading…
Reference in a new issue