From 3c881466521249ca332952e781ff8077e6b1bdc5 Mon Sep 17 00:00:00 2001 From: Rafael Saes Date: Tue, 27 Feb 2024 11:40:56 -0300 Subject: [PATCH] feat: scanning and adding addresses working with getTweaks, add btc SP address type --- cw_bitcoin/lib/bitcoin_address_record.dart | 148 +++-- .../lib/bitcoin_receive_page_option.dart | 2 +- cw_bitcoin/lib/bitcoin_unspent.dart | 6 +- cw_bitcoin/lib/bitcoin_wallet.dart | 22 +- cw_bitcoin/lib/electrum.dart | 4 +- cw_bitcoin/lib/electrum_wallet.dart | 509 +++++++----------- cw_bitcoin/lib/electrum_wallet_addresses.dart | 63 +-- cw_bitcoin/lib/electrum_wallet_snapshot.dart | 4 +- cw_bitcoin/pubspec.lock | 11 +- cw_bitcoin/pubspec.yaml | 2 +- cw_bitcoin_cash/pubspec.yaml | 2 +- cw_core/lib/sync_status.dart | 5 + lib/bitcoin/cw_bitcoin.dart | 6 +- lib/core/sync_status_title.dart | 4 + model_generator.sh | 1 + res/values/strings_ar.arb | 7 +- res/values/strings_bg.arb | 7 +- res/values/strings_cs.arb | 7 +- res/values/strings_de.arb | 7 +- res/values/strings_en.arb | 7 +- res/values/strings_es.arb | 7 +- res/values/strings_fr.arb | 7 +- res/values/strings_ha.arb | 7 +- res/values/strings_hi.arb | 7 +- res/values/strings_hr.arb | 7 +- res/values/strings_id.arb | 7 +- res/values/strings_it.arb | 7 +- res/values/strings_ja.arb | 7 +- res/values/strings_ko.arb | 7 +- res/values/strings_my.arb | 7 +- res/values/strings_nl.arb | 7 +- res/values/strings_pl.arb | 7 +- res/values/strings_pt.arb | 7 +- res/values/strings_ru.arb | 7 +- res/values/strings_th.arb | 7 +- res/values/strings_tl.arb | 7 +- res/values/strings_tr.arb | 7 +- res/values/strings_uk.arb | 7 +- res/values/strings_ur.arb | 7 +- res/values/strings_yo.arb | 7 +- res/values/strings_zh.arb | 7 +- tool/configure.dart | 2 +- 42 files changed, 491 insertions(+), 482 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index 2c40ba34c..afd7c34e1 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -4,8 +4,8 @@ import 'package:bitbox/bitbox.dart' as bitbox; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_bitcoin/script_hash.dart' as sh; -class BitcoinAddressRecord { - BitcoinAddressRecord( +abstract class BaseBitcoinAddressRecord { + BaseBitcoinAddressRecord( this.address, { required this.index, this.isHidden = false, @@ -14,14 +14,61 @@ class BitcoinAddressRecord { String name = '', bool isUsed = false, required this.type, - String? scriptHash, required this.network, - this.silentPaymentTweak, }) : _txCount = txCount, _balance = balance, _name = name, - _isUsed = isUsed, - scriptHash = + _isUsed = isUsed; + + @override + bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address; + + final String address; + bool isHidden; + final int index; + int _txCount; + int _balance; + String _name; + bool _isUsed; + BasedUtxoNetwork? network; + + int get txCount => _txCount; + + String get name => _name; + + int get balance => _balance; + + set txCount(int value) => _txCount = value; + + set balance(int value) => _balance = value; + + bool get isUsed => _isUsed; + + void setAsUsed() => _isUsed = true; + void setNewName(String label) => _name = label; + + int get hashCode => address.hashCode; + + String get cashAddr => bitbox.Address.toCashAddress(address); + + BitcoinAddressType type; + + String toJSON(); +} + +class BitcoinAddressRecord extends BaseBitcoinAddressRecord { + BitcoinAddressRecord( + super.address, { + required super.index, + super.isHidden = false, + super.txCount = 0, + super.balance = 0, + super.name = '', + super.isUsed = false, + required super.type, + String? scriptHash, + required super.network, + }) : scriptHash = scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null); factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) { @@ -43,51 +90,17 @@ class BitcoinAddressRecord { network: (decoded['network'] as String?) == null ? network : BasedUtxoNetwork.fromName(decoded['network'] as String), - silentPaymentTweak: decoded['silentPaymentTweak'] as String?, ); } - @override - bool operator ==(Object o) => o is BitcoinAddressRecord && address == o.address; - - final String address; - bool isHidden; - final int index; - int _txCount; - int _balance; - String _name; - bool _isUsed; String? scriptHash; - BasedUtxoNetwork? network; - final String? silentPaymentTweak; - - int get txCount => _txCount; - - String get name => _name; - - int get balance => _balance; - - set txCount(int value) => _txCount = value; - - set balance(int value) => _balance = value; - - bool get isUsed => _isUsed; - - void setAsUsed() => _isUsed = true; - void setNewName(String label) => _name = label; - - @override - int get hashCode => address.hashCode; - - String get cashAddr => bitbox.Address.toCashAddress(address); - - BitcoinAddressType type; String updateScriptHash(BasedUtxoNetwork network) { scriptHash = sh.scriptHash(address, network: network); return scriptHash!; } + @override String toJSON() => json.encode({ 'address': address, 'index': index, @@ -99,6 +112,59 @@ class BitcoinAddressRecord { 'type': type.toString(), 'scriptHash': scriptHash, 'network': network?.value, + }); +} + +class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord { + BitcoinSilentPaymentAddressRecord( + super.address, { + required super.index, + super.isHidden = false, + super.txCount = 0, + super.balance = 0, + super.name = '', + super.isUsed = false, + required super.type, + required this.silentPaymentTweak, + required super.network, + }); + + factory BitcoinSilentPaymentAddressRecord.fromJSON(String jsonSource, + {BasedUtxoNetwork? network}) { + final decoded = json.decode(jsonSource) as Map; + + return BitcoinSilentPaymentAddressRecord( + decoded['address'] as String, + index: decoded['index'] as int, + isHidden: decoded['isHidden'] as bool? ?? false, + isUsed: decoded['isUsed'] as bool? ?? false, + txCount: decoded['txCount'] as int? ?? 0, + name: decoded['name'] as String? ?? '', + balance: decoded['balance'] as int? ?? 0, + type: decoded['type'] != null && decoded['type'] != '' + ? BitcoinAddressType.values + .firstWhere((type) => type.toString() == decoded['type'] as String) + : SegwitAddresType.p2wpkh, + network: (decoded['network'] as String?) == null + ? network + : BasedUtxoNetwork.fromName(decoded['network'] as String), + silentPaymentTweak: decoded['silentPaymentTweak'] as String, + ); + } + + final String silentPaymentTweak; + + @override + String toJSON() => json.encode({ + 'address': address, + 'index': index, + 'isHidden': isHidden, + 'isUsed': isUsed, + 'txCount': txCount, + 'name': name, + 'balance': balance, + 'type': type.toString(), + 'network': network?.value, 'silentPaymentTweak': silentPaymentTweak, }); } diff --git a/cw_bitcoin/lib/bitcoin_receive_page_option.dart b/cw_bitcoin/lib/bitcoin_receive_page_option.dart index b14753ffc..cd471ef28 100644 --- a/cw_bitcoin/lib/bitcoin_receive_page_option.dart +++ b/cw_bitcoin/lib/bitcoin_receive_page_option.dart @@ -19,12 +19,12 @@ class BitcoinReceivePageOption implements ReceivePageOption { } static const all = [ + BitcoinReceivePageOption.silent_payments, BitcoinReceivePageOption.p2wpkh, BitcoinReceivePageOption.p2sh, BitcoinReceivePageOption.p2tr, BitcoinReceivePageOption.p2wsh, BitcoinReceivePageOption.p2pkh, - BitcoinReceivePageOption.silent_payments, ]; BitcoinAddressType toType() { diff --git a/cw_bitcoin/lib/bitcoin_unspent.dart b/cw_bitcoin/lib/bitcoin_unspent.dart index 131f47ab6..ce3c0da16 100644 --- a/cw_bitcoin/lib/bitcoin_unspent.dart +++ b/cw_bitcoin/lib/bitcoin_unspent.dart @@ -3,12 +3,12 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_core/unspent_transaction_output.dart'; class BitcoinUnspent extends Unspent { - BitcoinUnspent(BitcoinAddressRecord addressRecord, String hash, int value, int vout, + BitcoinUnspent(BaseBitcoinAddressRecord addressRecord, String hash, int value, int vout, {this.silentPaymentTweak, this.type}) : bitcoinAddressRecord = addressRecord, super(addressRecord.address, hash, value, vout, null); - factory BitcoinUnspent.fromJSON(BitcoinAddressRecord address, Map json) => + factory BitcoinUnspent.fromJSON(BaseBitcoinAddressRecord address, Map json) => BitcoinUnspent( address, json['tx_hash'] as String, @@ -32,7 +32,7 @@ class BitcoinUnspent extends Unspent { return json; } - final BitcoinAddressRecord bitcoinAddressRecord; + final BaseBitcoinAddressRecord bitcoinAddressRecord; String? silentPaymentTweak; BitcoinAddressType? type; } diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index dfd7c8fe5..f24142493 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -30,7 +30,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { ElectrumBalance? initialBalance, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, - List? initialSilentAddresses, + List? initialSilentAddresses, int initialSilentAddressIndex = 0, SilentPaymentOwner? silentAddress, }) : super( @@ -59,9 +59,19 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"), network: networkParam ?? network, ); + hasSilentPaymentsScanning = addressPageType == SilentPaymentsAddresType.p2sp.toString(); + autorun((_) { this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress; }); + + reaction((_) => walletAddresses.addressPageType, (BitcoinAddressType addressPageType) { + final prev = hasSilentPaymentsScanning; + hasSilentPaymentsScanning = addressPageType == SilentPaymentsAddresType.p2sp; + if (prev != hasSilentPaymentsScanning) { + startSync(); + } + }); } static Future create({ @@ -72,7 +82,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { String? addressPageType, BasedUtxoNetwork? network, List? initialAddresses, - List? initialSilentAddresses, + List? initialSilentAddresses, ElectrumBalance? initialBalance, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, @@ -88,11 +98,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialSilentAddresses: initialSilentAddresses, initialSilentAddressIndex: initialSilentAddressIndex, silentAddress: await SilentPaymentOwner.fromPrivateKeys( - scanPrivkey: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( + b_scan: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( seedBytes, network: network == BitcoinNetwork.testnet ? bitcoin.testnet : bitcoin.bitcoin, ).derivePath(SCAN_PATH).privKey!), - spendPrivkey: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( + b_spend: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( seedBytes, network: network == BitcoinNetwork.testnet ? bitcoin.testnet : bitcoin.bitcoin, ).derivePath(SPEND_PATH).privKey!), @@ -125,11 +135,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialSilentAddresses: snp.silentAddresses, initialSilentAddressIndex: snp.silentAddressIndex, silentAddress: await SilentPaymentOwner.fromPrivateKeys( - scanPrivkey: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( + b_scan: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( seedBytes, network: snp.network == BitcoinNetwork.testnet ? bitcoin.testnet : bitcoin.bitcoin, ).derivePath(SCAN_PATH).privKey!), - spendPrivkey: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( + b_spend: ECPrivate.fromHex(bitcoin.HDWallet.fromSeed( seedBytes, network: snp.network == BitcoinNetwork.testnet ? bitcoin.testnet : bitcoin.bitcoin, ).derivePath(SPEND_PATH).privKey!), diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart index 27a43ddcb..236dddaa2 100644 --- a/cw_bitcoin/lib/electrum.dart +++ b/cw_bitcoin/lib/electrum.dart @@ -279,8 +279,8 @@ class ElectrumClient { Future> getHeader({required int height}) async => await call(method: 'blockchain.block.get_header', params: [height]) as Map; - Future> getTweaks({required int height}) async => - await call(method: 'blockchain.block.tweaks', params: [height]) as Map; + Future> getTweaks({required int height}) async => + await callWithTimeout(method: 'blockchain.block.tweaks', params: [height]) as List; Future estimatefee({required int p}) => call(method: 'blockchain.estimatefee', params: [p]).then((dynamic result) { diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index f875a1b1f..bd63c4097 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -35,6 +35,7 @@ import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/utils/file.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:flutter/foundation.dart'; import 'package:hex/hex.dart'; import 'package:hive/hive.dart'; @@ -116,7 +117,7 @@ abstract class ElectrumWalletBase @observable SyncStatus syncStatus; - List get scriptHashes => walletAddresses.addressesByReceiveType + List get scriptHashes => walletAddresses.allAddresses .map((addr) => scriptHash(addr.address, network: network)) .toList(); @@ -136,6 +137,11 @@ abstract class ElectrumWalletBase @override bool? isTestnet; + @observable + bool hasSilentPaymentsScanning = false; + @observable + bool nodeSupportsSilentPayments = true; + @override BitcoinWalletKeys get keys => BitcoinWalletKeys(wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!); @@ -186,6 +192,11 @@ abstract class ElectrumWalletBase )); await for (var message in receivePort) { + if (message is bool) { + nodeSupportsSilentPayments = message; + syncStatus = UnsupportedSyncStatus(); + } + if (message is BitcoinUnspent) { if (!unspentCoins.any((utx) => utx.hash.contains(message.hash) && @@ -225,11 +236,18 @@ abstract class ElectrumWalletBase @override Future startSync() async { try { - await _setInitialHeight(); - } catch (_) {} + if (hasSilentPaymentsScanning) { + try { + await _setInitialHeight(); + } catch (_) {} - try { - rescan(height: walletInfo.restoreHeight); + final currentChainTip = await electrumClient.getCurrentBlockChainTip(); + if ((currentChainTip ?? 0) > walletInfo.restoreHeight) { + _setListeners(walletInfo.restoreHeight, chainTip: currentChainTip); + } + } else { + syncStatus = AttemptingSyncStatus(); + } await updateTransactions(); _subscribeForUpdates(); @@ -240,7 +258,9 @@ abstract class ElectrumWalletBase Timer.periodic( const Duration(minutes: 1), (timer) async => _feeRates = await electrumClient.feeRates()); + // if (!hasSilentPaymentsScanning) { syncStatus = SyncedSyncStatus(); + // } } catch (e, stacktrace) { print(stacktrace); print(e.toString()); @@ -260,12 +280,6 @@ abstract class ElectrumWalletBase } }; syncStatus = ConnectedSyncStatus(); - - final currentChainTip = await electrumClient.getCurrentBlockChainTip(); - - if ((currentChainTip ?? 0) > walletInfo.restoreHeight) { - _setListeners(walletInfo.restoreHeight, chainTip: currentChainTip); - } } catch (e) { print(e.toString()); syncStatus = FailedSyncStatus(); @@ -278,13 +292,18 @@ abstract class ElectrumWalletBase List outputAddresses, List outputs, BitcoinTransactionCredentials transactionCredentials, - {int? inputsCount}) async { + {int? inputsCount, + bool? hasSilentPayment}) async { final utxos = []; List privateKeys = []; var leftAmount = credentialsAmount; var allInputsAmount = 0; + List vinOutpoints = []; + List inputPrivKeyInfos = []; + List inputPubKeys = []; + for (int i = 0; i < unspentCoins.length; i++) { final utx = unspentCoins[i]; @@ -292,124 +311,6 @@ abstract class ElectrumWalletBase allInputsAmount += utx.value; leftAmount = leftAmount - utx.value; - if (utx.bitcoinAddressRecord.silentPaymentTweak != null) { - // final d = ECPrivate.fromHex(walletAddresses.primarySilentAddress!.spendPrivkey.toHex()) - // .tweakAdd(utx.bitcoinAddressRecord.silentPaymentTweak!)!; - - // inputPrivKeys.add(bitcoin.PrivateKeyInfo(d, true)); - // address = bitcoin.P2trAddress(address: utx.address, networkType: networkType); - // keyPairs.add(bitcoin.ECPair.fromPrivateKey(d.toCompressedHex().fromHex, - // compressed: true, network: networkType)); - // scriptType = bitcoin.AddressType.p2tr; - // script = bitcoin.P2trAddress(pubkey: d.publicKey.toHex(), networkType: networkType) - // .scriptPubkey - // .toBytes(); - } - - final address = _addressTypeFromStr(utx.address, network); - final privkey = generateECPrivate( - hd: utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, - index: utx.bitcoinAddressRecord.index, - network: network); - - privateKeys.add(privkey); - - utxos.add( - UtxoWithAddress( - utxo: BitcoinUtxo( - txHash: utx.hash, - value: BigInt.from(utx.value), - vout: utx.vout, - scriptType: _getScriptType(address), - ), - ownerDetails: - UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: address), - ), - ); - - bool amountIsAcquired = !sendAll && leftAmount <= 0; - if ((inputsCount == null && amountIsAcquired) || inputsCount == i + 1) { - break; - } - } - } - - if (inputs.isEmpty) { - throw BitcoinTransactionNoInputsException(); - } - - final allAmountFee = transactionCredentials.feeRate != null - ? feeAmountWithFeeRate(transactionCredentials.feeRate!, inputs.length, outputs.length) - : feeAmountForPriority(transactionCredentials.priority!, inputs.length, outputs.length); - - final allAmount = allInputsAmount - allAmountFee; - - var credentialsAmount = 0; - var amount = 0; - var fee = 0; - - if (hasMultiDestination) { - if (outputs.any((item) => item.sendAll || item.formattedCryptoAmount! <= 0)) { - throw BitcoinTransactionWrongBalanceException(currency); - } - - credentialsAmount = outputs.fold(0, (acc, value) => acc + value.formattedCryptoAmount!); - - if (allAmount - credentialsAmount < minAmount) { - throw BitcoinTransactionWrongBalanceException(currency); - } - - amount = credentialsAmount; - - if (transactionCredentials.feeRate != null) { - fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate!, amount, - outputsCount: outputs.length + 1); - } else { - fee = calculateEstimatedFee(transactionCredentials.priority, amount, - outputsCount: outputs.length + 1); - } - } else { - final output = outputs.first; - credentialsAmount = !output.sendAll ? output.formattedCryptoAmount! : 0; - - if (credentialsAmount > allAmount) { - throw BitcoinTransactionWrongBalanceException(currency); - } - - amount = output.sendAll || allAmount - credentialsAmount < minAmount - ? allAmount - : credentialsAmount; - - if (output.sendAll || amount == allAmount) { - fee = allAmountFee; - } else if (transactionCredentials.feeRate != null) { - fee = calculateEstimatedFeeWithFeeRate(transactionCredentials.feeRate!, amount); - } else { - fee = calculateEstimatedFee(transactionCredentials.priority, amount); - } - } - - if (fee == 0) { - throw BitcoinTransactionWrongBalanceException(currency); - } - - final totalAmount = amount + fee; - - if (totalAmount > balance[currency]!.confirmed || totalAmount > allInputsAmount) { - throw BitcoinTransactionWrongBalanceException(currency); - } - - final txb = bitcoin.TransactionBuilder(network: networkType); - final changeAddress = await walletAddresses.getChangeAddress(); - var leftAmount = totalAmount; - var totalInputAmount = 0; - - inputs.clear(); - - for (final utx in unspentCoins) { - if (utx.isSending) { - leftAmount = leftAmount - utx.value; - final address = _addressTypeFromStr(utx.address, network); final privkey = generateECPrivate( hd: utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, @@ -417,6 +318,9 @@ abstract class ElectrumWalletBase network: network); privateKeys.add(privkey); + inputPrivKeyInfos.add(ECPrivateInfo(privkey, address.type == SegwitAddresType.p2tr)); + inputPubKeys.add(privkey.getPublic()); + vinOutpoints.add(Outpoint(txid: utx.hash, index: utx.vout)); utxos.add( UtxoWithAddress( @@ -453,6 +357,45 @@ abstract class ElectrumWalletBase } } + if (hasSilentPayment == true) { + List silentPaymentDestinations = []; + + for (final out in outputs) { + final address = out.address; + final amount = out.value; + + if (address is SilentPaymentAddress) { + final silentPaymentDestination = + SilentPaymentDestination.fromAddress(address.toAddress(network), amount.toInt()); + silentPaymentDestinations.add(silentPaymentDestination); + } + } + + final spb = SilentPaymentBuilder(pubkeys: inputPubKeys, outpoints: vinOutpoints); + final sendingOutputs = spb.createOutputs(inputPrivKeyInfos, silentPaymentDestinations); + + var outputsAdded = []; + + for (var i = 0; i < outputs.length; i++) { + final out = outputs[i]; + + final silentOutputs = sendingOutputs[out.address.toAddress(network)]; + if (silentOutputs != null) { + final silentOutput = + silentOutputs.firstWhereOrNull((element) => !outputsAdded.contains(element)); + + if (silentOutput != null) { + outputs[i] = BitcoinOutput( + address: silentOutput.address, + value: BigInt.from(silentOutput.amount), + ); + + outputsAdded.add(silentOutput); + } + } + } + } + final estimatedSize = BitcoinTransactionBuilder.estimateTransactionSize( utxos: utxos, outputs: outputs, network: network); @@ -497,25 +440,31 @@ abstract class ElectrumWalletBase return _estimateTxFeeAndInputsToUse( credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials, - inputsCount: utxos.length + 1); + inputsCount: utxos.length + 1, hasSilentPayment: hasSilentPayment); } } - if (SilentPaymentAddress.regex.hasMatch(outputAddress)) { - // final outpointsHash = SilentPayment.hashOutpoints(outpoints); - // final generatedOutputs = SilentPayment.generateMultipleRecipientPubkeys(inputPrivKeys, - // outpointsHash, SilentPaymentDestination.fromAddress(outputAddress, outputAmount!)); + return EstimatedTxResult(utxos: utxos, privateKeys: privateKeys, fee: fee, amount: amount); + } - // generatedOutputs.forEach((recipientSilentAddress, generatedOutput) { - // generatedOutput.forEach((output) { - // outputs.add(BitcoinOutputDetails( - // address: P2trAddress( - // program: ECPublic.fromHex(output.$1.toHex()).toTapPoint(), - // networkType: networkType), - // value: BigInt.from(output.$2), - // )); - // }); - // }); + @override + Future createTransaction(Object credentials) async { + try { + final outputs = []; + final outputAddresses = []; + final transactionCredentials = credentials as BitcoinTransactionCredentials; + final hasMultiDestination = transactionCredentials.outputs.length > 1; + final sendAll = !hasMultiDestination && transactionCredentials.outputs.first.sendAll; + + var credentialsAmount = 0; + bool hasSilentPayment = false; + + for (final out in transactionCredentials.outputs) { + final outputAddress = out.isParsedAddress ? out.extractedAddress! : out.address; + final address = _addressTypeFromStr(outputAddress, network); + + if (address is SilentPaymentAddress) { + hasSilentPayment = true; } outputAddresses.add(address); @@ -542,7 +491,8 @@ abstract class ElectrumWalletBase } final estimatedTx = await _estimateTxFeeAndInputsToUse( - credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials); + credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials, + hasSilentPayment: hasSilentPayment); final txb = BitcoinTransactionBuilder( utxos: estimatedTx.utxos, @@ -749,7 +699,7 @@ abstract class ElectrumWalletBase final coinInfoList = unspentCoinsInfo.values.where((element) => element.walletId.contains(id) && element.hash.contains(coin.hash) && - element.address.contains(coin.address)); + element.vout == coin.vout); if (coinInfoList.isNotEmpty) { final coinInfo = coinInfoList.first; @@ -916,7 +866,7 @@ abstract class ElectrumWalletBase final Map historiesWithDetails = {}; final history = await electrumClient - .getHistory(addressRecord.scriptHash ?? addressRecord.updateScriptHash(network)); + .getHistory(addressRecord.scriptHash ?? addressRecord.updateScriptHash(network)!); if (history.isNotEmpty) { addressRecord.setAsUsed(); @@ -1037,7 +987,7 @@ abstract class ElectrumWalletBase element.bitcoinAddressRecord.address == info.address && element.value == info.value) { if (info.isFrozen) totalFrozen += element.value; - if (element.bitcoinAddressRecord.silentPaymentTweak != null) { + if (element.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) { totalConfirmed += element.value; } } @@ -1208,18 +1158,29 @@ Future startRefresh(ScanData scanData) async { final electrumClient = scanData.electrumClient; if (!electrumClient.isConnected) { final node = scanData.node; + print(node); await electrumClient.connectToUri(Uri.parse(node)); } - final tweaks = await electrumClient.getTweaks(height: syncHeight); + + List? tweaks; + try { + tweaks = await electrumClient.getTweaks(height: syncHeight); + } catch (e) { + if (e is RequestFailedTimeoutException) { + return scanData.sendPort.send(false); + } + } + + if (tweaks == null) { + return scanData.sendPort.send(false); + } for (var i = 0; i < tweaks.length; i++) { try { // final txid = tweaks.keys.toList()[i]; - final details = tweaks.values.toList()[i]; - print(["details", details]); - final output_pubkeys = (details["output_pubkeys"] as List); - - // print(["Scanning tx:", txid]); + final details = tweaks[i] as Map; + final output_pubkeys = (details["output_pubkeys"] as List); + final tweak = details["tweak"].toString(); // TODO: if tx already scanned & stored skip // if (scanData.transactionHistoryIds.contains(txid)) { @@ -1228,12 +1189,14 @@ Future startRefresh(ScanData scanData) async { // continue; // } - final result = SilentPayment.scanTweak( + final spb = SilentPaymentBuilder(receiverTweak: tweak); + final result = spb.scanOutputs( scanData.primarySilentAddress.b_scan, scanData.primarySilentAddress.B_spend, - details["tweak"] as String, - output_pubkeys.map((e) => BytesUtils.fromHexString(e)).toList(), - labels: scanData.labels, + output_pubkeys + .map((p) => ECPublic.fromBytes(BytesUtils.fromHexString(p.toString()).sublist(2))) + .toList(), + precomputedLabels: scanData.labels, ); if (result.isEmpty) { @@ -1241,113 +1204,102 @@ Future startRefresh(ScanData scanData) async { continue; } - if (result.length > 1) { - print("MULTIPLE UNSPENT COINS FOUND!"); - } else { - print("UNSPENT COIN FOUND!"); - } + result.forEach((key, value) async { + final t_k = value[0]; + final address = + ECPublic.fromHex(key).toTaprootAddress(tweak: false).toAddress(scanData.network); - // result.forEach((key, value) async { - // final outpoint = output_pubkeys[key]; + final listUnspent = + await electrumClient.getListUnspentWithAddress(address, scanData.network); - // if (outpoint == null) { - // return; - // } + BitcoinUnspent? info; + await Future.forEach>(listUnspent, (unspent) async { + try { + final addressRecord = BitcoinSilentPaymentAddressRecord( + address, + index: 0, + isHidden: true, + isUsed: true, + network: scanData.network, + silentPaymentTweak: t_k, + type: SegwitAddresType.p2tr, + ); + info = BitcoinUnspent.fromJSON(addressRecord, unspent); + } catch (_) {} + }); - // final tweak = value[0]; - // String? label; - // if (value.length > 1) label = value[1]; + // final tweak = value[0]; + // String? label; + // if (value.length > 1) label = value[1]; - // final txInfo = ElectrumTransactionInfo( - // WalletType.bitcoin, - // id: txid, - // height: syncHeight, - // amount: outpoint.value!, - // fee: 0, - // direction: TransactionDirection.incoming, - // isPending: false, - // date: DateTime.fromMillisecondsSinceEpoch((blockJson["timestamp"] as int) * 1000), - // confirmations: currentChainTip - syncHeight, - // to: bitcoin.SilentPaymentAddress.createLabeledSilentPaymentAddress( - // scanData.primarySilentAddress.scanPubkey, - // scanData.primarySilentAddress.spendPubkey, - // label != null ? label.fromHex : "0".fromHex, - // hrp: scanData.primarySilentAddress.hrp, - // version: scanData.primarySilentAddress.version) - // .toString(), - // unspent: null, - // ); + final tx = info!; + final txInfo = ElectrumTransactionInfo( + WalletType.bitcoin, + id: tx.hash, + height: syncHeight, + amount: tx.value, + fee: 0, + direction: TransactionDirection.incoming, + isPending: false, + date: DateTime.now(), + confirmations: currentChainTip - syncHeight, + to: scanData.primarySilentAddress.toString(), + unspent: tx, + ); - // final status = json.decode((await http - // .get(Uri.parse("https://blockstream.info/testnet/api/tx/$txid/outspends"))) - // .body) as List; + // final status = json.decode((await http + // .get(Uri.parse("https://blockstream.info/testnet/api/tx/$txid/outspends"))) + // .body) as List; - // bool spent = false; - // for (final s in status) { - // if ((s["spent"] as bool) == true) { - // spent = true; + // bool spent = false; + // for (final s in status) { + // if ((s["spent"] as bool) == true) { + // spent = true; - // scanData.sendPort.send({txid: txInfo}); + // scanData.sendPort.send({txid: txInfo}); - // final sentTxId = s["txid"] as String; - // final sentTx = json.decode( - // (await http.get(Uri.parse("https://blockstream.info/testnet/api/tx/$sentTxId"))) - // .body); + // final sentTxId = s["txid"] as String; + // final sentTx = json.decode( + // (await http.get(Uri.parse("https://blockstream.info/testnet/api/tx/$sentTxId"))) + // .body); - // int amount = 0; - // for (final out in (sentTx["vout"] as List)) { - // amount += out["value"] as int; - // } + // int amount = 0; + // for (final out in (sentTx["vout"] as List)) { + // amount += out["value"] as int; + // } - // final height = s["status"]["block_height"] as int; + // final height = s["status"]["block_height"] as int; - // scanData.sendPort.send({ - // sentTxId: ElectrumTransactionInfo( - // WalletType.bitcoin, - // id: sentTxId, - // height: height, - // amount: amount, - // fee: 0, - // direction: TransactionDirection.outgoing, - // isPending: false, - // date: DateTime.fromMillisecondsSinceEpoch( - // (s["status"]["block_time"] as int) * 1000), - // confirmations: currentChainTip - height, - // ) - // }); - // } - // } + // scanData.sendPort.send({ + // sentTxId: ElectrumTransactionInfo( + // WalletType.bitcoin, + // id: sentTxId, + // height: height, + // amount: amount, + // fee: 0, + // direction: TransactionDirection.outgoing, + // isPending: false, + // date: DateTime.fromMillisecondsSinceEpoch( + // (s["status"]["block_time"] as int) * 1000), + // confirmations: currentChainTip - height, + // ) + // }); + // } + // } - // if (spent) { - // return; - // } + // if (spent) { + // return; + // } - // final unspent = BitcoinUnspent( - // BitcoinAddressRecord( - // bitcoin.P2trAddress(program: key, networkType: scanData.network).address, - // index: 0, - // isHidden: true, - // isUsed: true, - // silentAddressLabel: null, - // silentPaymentTweak: tweak, - // type: bitcoin.AddressType.p2tr, - // ), - // txid, - // outpoint.value!, - // outpoint.index, - // silentPaymentTweak: tweak, - // type: bitcoin.AddressType.p2tr, - // ); + // found utxo for tx, send unspent coin to main isolate + // scanData.sendPort.send(txInfo); - // // found utxo for tx, send unspent coin to main isolate - // scanData.sendPort.send(unspent); - - // // also send tx data for tx history - // txInfo.unspent = unspent; - // scanData.sendPort.send({txid: txInfo}); - // }); + // also send tx data for tx history + scanData.sendPort.send({txInfo.id: txInfo}); + }); } catch (_) {} } + // break; // Finished scanning block, add 1 to height and continue to next block in loop syncHeight += 1; @@ -1383,6 +1335,8 @@ BitcoinBaseAddress _addressTypeFromStr(String address, BasedUtxoNetwork network) return P2wshAddress.fromAddress(address: address, network: network); } else if (P2trAddress.regex.hasMatch(address)) { return P2trAddress.fromAddress(address: address, network: network); + } else if (SilentPaymentAddress.regex.hasMatch(address)) { + return SilentPaymentAddress.fromAddress(address); } else { return P2wpkhAddress.fromAddress(address: address, network: network); } @@ -1397,59 +1351,8 @@ BitcoinAddressType _getScriptType(BitcoinBaseAddress type) { return SegwitAddresType.p2wsh; } else if (type is P2trAddress) { return SegwitAddresType.p2tr; - } else { - return SegwitAddresType.p2wpkh; - } -} - -class EstimateTxParams { - EstimateTxParams( - {required this.amount, - required this.feeRate, - required this.priority, - required this.outputsCount, - required this.size}); - - final int amount; - final int feeRate; - final TransactionPriority priority; - final int outputsCount; - final int size; -} - -class EstimatedTxResult { - EstimatedTxResult( - {required this.utxos, required this.privateKeys, required this.fee, required this.amount}); - - final List utxos; - final List privateKeys; - final int fee; - final int amount; -} - -BitcoinBaseAddress _addressTypeFromStr(String address, BasedUtxoNetwork network) { - if (P2pkhAddress.regex.hasMatch(address)) { - return P2pkhAddress.fromAddress(address: address, network: network); - } else if (P2shAddress.regex.hasMatch(address)) { - return P2shAddress.fromAddress(address: address, network: network); - } else if (P2wshAddress.regex.hasMatch(address)) { - return P2wshAddress.fromAddress(address: address, network: network); - } else if (P2trAddress.regex.hasMatch(address)) { - return P2trAddress.fromAddress(address: address, network: network); - } else { - return P2wpkhAddress.fromAddress(address: address, network: network); - } -} - -BitcoinAddressType _getScriptType(BitcoinBaseAddress type) { - if (type is P2pkhAddress) { - return P2pkhAddressType.p2pkh; - } else if (type is P2shAddress) { - return P2shAddressType.p2wpkhInP2sh; - } else if (type is P2wshAddress) { - return SegwitAddresType.p2wsh; - } else if (type is P2trAddress) { - return SegwitAddresType.p2tr; + } else if (type is SilentPaymentsAddresType) { + return SilentPaymentsAddresType.p2sp; } else { return SegwitAddresType.p2wpkh; } diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index bd6781ea8..ec2a27498 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -1,6 +1,7 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitbox/bitbox.dart' as bitbox; +import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; @@ -28,7 +29,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { List? initialAddresses, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, - List? initialSilentAddresses, + List? initialSilentAddresses, int initialSilentAddressIndex = 0, SilentPaymentOwner? silentAddress, }) : _addresses = ObservableList.of((initialAddresses ?? []).toSet()), @@ -46,9 +47,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { _addressPageType = walletInfo.addressPageType != null ? BitcoinAddressType.fromValue(walletInfo.addressPageType!) : SegwitAddresType.p2wpkh, - silentAddresses = ObservableList.of((initialSilentAddresses ?? []) - .where((addressRecord) => addressRecord.silentPaymentTweak != null) - .toSet()), + silentAddresses = ObservableList.of( + (initialSilentAddresses ?? []).toSet()), currentSilentAddressIndex = initialSilentAddressIndex, super(walletInfo) { updateAddressesByMatch(); @@ -59,15 +59,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { static const gap = 20; static String toCashAddr(String address) => bitbox.Address.toCashAddress(address); - static String toLegacy(String address) => bitbox.Address.toLegacyAddress(address); final ObservableList _addresses; - // Matched by addressPageType - late ObservableList addressesByReceiveType; + late ObservableList addressesByReceiveType; final ObservableList receiveAddresses; final ObservableList changeAddresses; - final ObservableList silentAddresses; + final ObservableList silentAddresses; final BasedUtxoNetwork network; final bitcoin.HDWallet mainHd; final bitcoin.HDWallet sideHd; @@ -101,23 +99,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { final typeMatchingReceiveAddresses = receiveAddresses.where(_isAddressPageTypeMatch); - if ((isEnabledAutoGenerateSubaddress && receiveAddresses.isEmpty) || - typeMatchingReceiveAddresses.isEmpty) { - receiveAddress = generateNewAddress().address; - } else { - final previousAddressMatchesType = - previousAddressRecord != null && previousAddressRecord!.type == addressPageType; - - if (previousAddressMatchesType && - typeMatchingReceiveAddresses.first.address != addressesByReceiveType.first.address) { - receiveAddress = previousAddressRecord!.address; - } else { - receiveAddress = typeMatchingReceiveAddresses.first.address; - } - final receiveAddress = receiveAddresses.first.address; - - final typeMatchingReceiveAddresses = receiveAddresses.where(_isAddressPageTypeMatch); - if ((isEnabledAutoGenerateSubaddress && receiveAddresses.isEmpty) || typeMatchingReceiveAddresses.isEmpty) { receiveAddress = generateNewAddress().address; @@ -239,38 +220,36 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } Map get labels { + final G = ECPublic.fromBytes(BigintUtils.toBytes(Curves.generatorSecp256k1.x, length: 32)); final labels = {}; for (int i = 0; i < silentAddresses.length; i++) { final silentAddressRecord = silentAddresses[i]; - final silentAddress = - SilentPaymentDestination.fromAddress(silentAddressRecord.address, 0).B_spend.toHex(); - - if (silentAddressRecord.silentPaymentTweak != null) - labels[silentAddress] = silentAddressRecord.silentPaymentTweak!; + final silentPaymentTweak = silentAddressRecord.silentPaymentTweak; + labels[G + .tweakMul(BigintUtils.fromBytes(BytesUtils.fromHexString(silentPaymentTweak))) + .toHex()] = silentPaymentTweak; } return labels; } - BitcoinAddressRecord generateNewAddress({String label = ''}) { + @action + BaseBitcoinAddressRecord generateNewAddress({String label = ''}) { if (addressPageType == SilentPaymentsAddresType.p2sp) { currentSilentAddressIndex += 1; - final tweak = BigInt.from(currentSilentAddressIndex); - - final address = BitcoinAddressRecord( - SilentPaymentAddress.createLabeledSilentPaymentAddress( - primarySilentAddress!.B_scan, primarySilentAddress!.B_spend, tweak, - hrp: primarySilentAddress!.hrp, version: primarySilentAddress!.version) - .toString(), + final address = BitcoinSilentPaymentAddressRecord( + primarySilentAddress!.toLabeledSilentPaymentAddress(currentSilentAddressIndex).toString(), index: currentSilentAddressIndex, isHidden: false, name: label, - silentPaymentTweak: tweak.toString(), + silentPaymentTweak: + BytesUtils.toHexString(primarySilentAddress!.generateLabel(currentSilentAddressIndex)), network: network, type: SilentPaymentsAddresType.p2sp, ); silentAddresses.add(address); + updateAddressesByMatch(); return address; } @@ -321,6 +300,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @action void updateAddressesByMatch() { + if (addressPageType == SilentPaymentsAddresType.p2sp) { + addressesByReceiveType.clear(); + addressesByReceiveType.addAll(silentAddresses); + return; + } + addressesByReceiveType.clear(); addressesByReceiveType.addAll(_addresses.where(_isAddressPageTypeMatch).toList()); } diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart index ceb603f9f..9f71d0bd8 100644 --- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart +++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart @@ -30,7 +30,7 @@ class ElectrumWalletSnapshot { String mnemonic; List addresses; - List silentAddresses; + List silentAddresses; ElectrumBalance balance; Map regularAddressIndex; Map changeAddressIndex; @@ -52,7 +52,7 @@ class ElectrumWalletSnapshot { final silentAddressesTmp = data['silent_addresses'] as List? ?? []; final silentAddresses = silentAddressesTmp .whereType() - .map((addr) => BitcoinAddressRecord.fromJSON(addr, network: network)) + .map((addr) => BitcoinSilentPaymentAddressRecord.fromJSON(addr, network: network)) .toList(); final balance = ElectrumBalance.fromJSON(data['balance'] as String) ?? diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index aff28df6e..c7750f1af 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -80,7 +80,7 @@ packages: description: path: "." ref: cake-update-v2 - resolved-ref: e4686da77cace5400697de69f7885020297cb900 + resolved-ref: "43b80bcf0ef6e7224603a6b8874b61efec3c6a4c" url: "https://github.com/cake-tech/bitcoin_base.git" source: git version: "4.0.0" @@ -93,6 +93,15 @@ packages: url: "https://github.com/cake-tech/bitcoin_flutter.git" source: git version: "2.1.0" + blockchain_utils: + dependency: "direct main" + description: + path: "." + ref: cake-update-v1 + resolved-ref: "6a0b891db4d90c647ebf5fc3a9132e614c70e1c6" + url: "https://github.com/cake-tech/blockchain_utils" + source: git + version: "1.6.0" boolean_selector: dependency: transitive description: diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 13a0e2688..bfa6c72e6 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: ref: cake-update-v2 blockchain_utils: git: - url: https://github.com/rafael-xmr/blockchain_utils + url: https://github.com/cake-tech/blockchain_utils ref: cake-update-v1 dev_dependencies: diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index fd7ed5a0f..a96768150 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: ref: cake-update-v2 blockchain_utils: git: - url: https://github.com/rafael-xmr/blockchain_utils + url: https://github.com/cake-tech/blockchain_utils ref: cake-update-v1 dev_dependencies: diff --git a/cw_core/lib/sync_status.dart b/cw_core/lib/sync_status.dart index afddc7c7a..f562e7ce3 100644 --- a/cw_core/lib/sync_status.dart +++ b/cw_core/lib/sync_status.dart @@ -58,6 +58,11 @@ class ConnectedSyncStatus extends SyncStatus { double progress() => 0.0; } +class UnsupportedSyncStatus extends SyncStatus { + @override + double progress() => 1.0; +} + class LostConnectionSyncStatus extends SyncStatus { @override double progress() => 1.0; diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index fb470a58f..1ce79352c 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -101,7 +101,7 @@ class CWBitcoin extends Bitcoin { List getAddresses(Object wallet) { final bitcoinWallet = wallet as ElectrumWallet; return bitcoinWallet.walletAddresses.addressesByReceiveType - .map((BitcoinAddressRecord addr) => addr.address) + .map((BaseBitcoinAddressRecord addr) => addr.address) .toList(); } @@ -110,7 +110,7 @@ class CWBitcoin extends Bitcoin { List getSubAddresses(Object wallet) { final electrumWallet = wallet as ElectrumWallet; return electrumWallet.walletAddresses.addressesByReceiveType - .map((BitcoinAddressRecord addr) => ElectrumSubAddress( + .map((BaseBitcoinAddressRecord addr) => ElectrumSubAddress( id: addr.index, name: addr.name, address: electrumWallet.type == WalletType.bitcoinCash ? addr.cashAddr : addr.address, @@ -195,7 +195,7 @@ class CWBitcoin extends Bitcoin { @override List getBitcoinReceivePageOptions() => BitcoinReceivePageOption.all; - List getSilentAddresses(Object wallet) { + List getSilentAddresses(Object wallet) { final bitcoinWallet = wallet as ElectrumWallet; return bitcoinWallet.walletAddresses.silentAddresses; } diff --git a/lib/core/sync_status_title.dart b/lib/core/sync_status_title.dart index 226b97f50..23bfb0db2 100644 --- a/lib/core/sync_status_title.dart +++ b/lib/core/sync_status_title.dart @@ -36,5 +36,9 @@ String syncStatusTitle(SyncStatus syncStatus) { return S.current.sync_status_failed_connect; } + if (syncStatus is UnsupportedSyncStatus) { + return S.current.sync_status_unsupported; + } + return ''; } diff --git a/model_generator.sh b/model_generator.sh index fa1ea6fac..062dcf0e2 100755 --- a/model_generator.sh +++ b/model_generator.sh @@ -5,6 +5,7 @@ cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --de cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. +cd cw_solana; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. cd cw_polygon; flutter pub get; cd .. cd cw_ethereum; flutter pub get; cd .. flutter packages pub run build_runner build --delete-conflicting-outputs diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 02024fe1a..835f1909e 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "بدء المزامنة", "sync_status_syncronized": "متزامن", "sync_status_syncronizing": "يتم المزامنة", + "sync_status_unsupported": "عقدة غير مدعومة", "syncing_wallet_alert_content": "قد لا يكتمل رصيدك وقائمة المعاملات الخاصة بك حتى تظهر عبارة “SYNCHRONIZED“ في الأعلى. انقر / اضغط لمعرفة المزيد.", "syncing_wallet_alert_title": "محفظتك تتم مزامنتها", "template": "قالب", @@ -733,6 +734,7 @@ "view_key_private": "مفتاح العرض (خاص)", "view_key_public": "مفتاح العرض (عام)", "view_transaction_on": "عرض العملية على", + "waitFewSecondForTxUpdate": "ﺕﻼﻣﺎﻌﻤﻟﺍ ﻞﺠﺳ ﻲﻓ ﺔﻠﻣﺎﻌﻤﻟﺍ ﺲﻜﻌﻨﺗ ﻰﺘﺣ ﻥﺍﻮﺛ ﻊﻀﺒﻟ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ", "wallet_keys": "سييد المحفظة / المفاتيح", "wallet_list_create_new_wallet": "إنشاء محفظة جديدة", "wallet_list_edit_wallet": "تحرير المحفظة", @@ -783,6 +785,5 @@ "you_pay": "انت تدفع", "you_will_get": "حول الى", "you_will_send": "تحويل من", - "yy": "YY", - "waitFewSecondForTxUpdate": "ﺕﻼﻣﺎﻌﻤﻟﺍ ﻞﺠﺳ ﻲﻓ ﺔﻠﻣﺎﻌﻤﻟﺍ ﺲﻜﻌﻨﺗ ﻰﺘﺣ ﻥﺍﻮﺛ ﻊﻀﺒﻟ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 807592f91..db73a2e15 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ", "sync_status_syncronized": "СИНХРОНИЗИРАНО", "sync_status_syncronizing": "СИНХРОНИЗИРАНЕ", + "sync_status_unsupported": "Неподдържан възел", "syncing_wallet_alert_content": "Списъкът ви с баланс и транзакции може да не е пълен, докато в горната част не пише „СИНХРОНИЗИРАН“. Кликнете/докоснете, за да научите повече.", "syncing_wallet_alert_title": "Вашият портфейл се синхронизира", "template": "Шаблон", @@ -733,6 +734,7 @@ "view_key_private": "View key (таен)", "view_key_public": "View key (публичен)", "view_transaction_on": "Вижте транзакция на ", + "waitFewSecondForTxUpdate": "Моля, изчакайте няколко секунди, докато транзакцията се отрази в историята на транзакциите", "wallet_keys": "Seed/keys на портфейла", "wallet_list_create_new_wallet": "Създаване на нов портфейл", "wallet_list_edit_wallet": "Редактиране на портфейла", @@ -783,6 +785,5 @@ "you_pay": "Вие плащате", "you_will_get": "Обръщане в", "you_will_send": "Обръщане от", - "yy": "гг", - "waitFewSecondForTxUpdate": "Моля, изчакайте няколко секунди, докато транзакцията се отрази в историята на транзакциите" -} + "yy": "гг" +} \ No newline at end of file diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 74d7298da..0f2242b33 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE", "sync_status_syncronized": "SYNCHRONIZOVÁNO", "sync_status_syncronizing": "SYNCHRONIZUJI", + "sync_status_unsupported": "Nepodporovaný uzel", "syncing_wallet_alert_content": "Váš seznam zůstatků a transakcí nemusí být úplný, dokud nebude nahoře uvedeno „SYNCHRONIZOVANÉ“. Kliknutím/klepnutím se dozvíte více.", "syncing_wallet_alert_title": "Vaše peněženka se synchronizuje", "template": "Šablona", @@ -733,6 +734,7 @@ "view_key_private": "Klíč pro zobrazení (soukromý)", "view_key_public": "Klíč pro zobrazení (veřejný)", "view_transaction_on": "Zobrazit transakci na ", + "waitFewSecondForTxUpdate": "Počkejte několik sekund, než se transakce projeví v historii transakcí", "wallet_keys": "Seed/klíče peněženky", "wallet_list_create_new_wallet": "Vytvořit novou peněženku", "wallet_list_edit_wallet": "Upravit peněženku", @@ -783,6 +785,5 @@ "you_pay": "Zaplatíte", "you_will_get": "Směnit na", "you_will_send": "Směnit z", - "yy": "YY", - "waitFewSecondForTxUpdate": "Počkejte několik sekund, než se transakce projeví v historii transakcí" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index d71f68fd4..d21d57a98 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "STARTE SYNCHRONISIERUNG", "sync_status_syncronized": "SYNCHRONISIERT", "sync_status_syncronizing": "SYNCHRONISIERE", + "sync_status_unsupported": "Nicht unterstützter Knoten", "syncing_wallet_alert_content": "Ihr Kontostand und Ihre Transaktionsliste sind möglicherweise erst vollständig, wenn oben „SYNCHRONISIERT“ steht. Klicken/tippen Sie, um mehr zu erfahren.", "syncing_wallet_alert_title": "Ihr Wallet wird synchronisiert", "template": "Vorlage", @@ -735,6 +736,7 @@ "view_key_private": "View Key (geheim)", "view_key_public": "View Key (öffentlich)", "view_transaction_on": "Anzeigen der Transaktion auf ", + "waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird", "waiting_payment_confirmation": "Warte auf Zahlungsbestätigung", "wallet_keys": "Wallet-Seed/-Schlüssel", "wallet_list_create_new_wallet": "Neue Wallet erstellen", @@ -786,6 +788,5 @@ "you_pay": "Sie bezahlen", "you_will_get": "Konvertieren zu", "you_will_send": "Konvertieren von", - "yy": "YY", - "waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index d943ed4cd..c3acebf6d 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "STARTING SYNC", "sync_status_syncronized": "SYNCHRONIZED", "sync_status_syncronizing": "SYNCHRONIZING", + "sync_status_unsupported": "UNSUPPORTED NODE", "syncing_wallet_alert_content": "Your balance and transaction list may not be complete until it says “SYNCHRONIZED” at the top. Click/tap to learn more.", "syncing_wallet_alert_title": "Your wallet is syncing", "template": "Template", @@ -733,6 +734,7 @@ "view_key_private": "View key (private)", "view_key_public": "View key (public)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Kindly wait for a few seconds for transaction to reflect in transactions history", "wallet_keys": "Wallet seed/keys", "wallet_list_create_new_wallet": "Create New Wallet", "wallet_list_edit_wallet": "Edit wallet", @@ -783,6 +785,5 @@ "you_pay": "You Pay", "you_will_get": "Convert to", "you_will_send": "Convert from", - "yy": "YY", - "waitFewSecondForTxUpdate": "Kindly wait for a few seconds for transaction to reflect in transactions history" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 9cea08be4..d2fd93dff 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR", "sync_status_syncronized": "SINCRONIZADO", "sync_status_syncronizing": "SINCRONIZANDO", + "sync_status_unsupported": "Nodo no compatible", "syncing_wallet_alert_content": "Es posible que su lista de saldo y transacciones no esté completa hasta que diga \"SINCRONIZADO\" en la parte superior. Haga clic/toque para obtener más información.", "syncing_wallet_alert_title": "Tu billetera se está sincronizando", "template": "Plantilla", @@ -734,6 +735,7 @@ "view_key_private": "View clave (privado)", "view_key_public": "View clave (público)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Espere unos segundos para que la transacción se refleje en el historial de transacciones.", "wallet_keys": "Billetera semilla/claves", "wallet_list_create_new_wallet": "Crear nueva billetera", "wallet_list_edit_wallet": "Editar billetera", @@ -784,6 +786,5 @@ "you_pay": "Tú pagas", "you_will_get": "Convertir a", "you_will_send": "Convertir de", - "yy": "YY", - "waitFewSecondForTxUpdate": "Espere unos segundos para que la transacción se refleje en el historial de transacciones." -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index ac2d944db..61f15497c 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "DÉBUT DE SYNCHRO", "sync_status_syncronized": "SYNCHRONISÉ", "sync_status_syncronizing": "SYNCHRONISATION EN COURS", + "sync_status_unsupported": "Nœud non pris en charge", "syncing_wallet_alert_content": "Votre solde et votre liste de transactions peuvent ne pas être à jour tant que la mention « SYNCHRONISÉ » n'apparaît en haut de l'écran. Cliquez/appuyez pour en savoir plus.", "syncing_wallet_alert_title": "Votre portefeuille (wallet) est en cours de synchronisation", "template": "Modèle", @@ -733,6 +734,7 @@ "view_key_private": "Clef d'audit (view key) (privée)", "view_key_public": "Clef d'audit (view key) (publique)", "view_transaction_on": "Voir la Transaction sur ", + "waitFewSecondForTxUpdate": "Veuillez attendre quelques secondes pour que la transaction soit reflétée dans l'historique des transactions.", "wallet_keys": "Phrase secrète (seed)/Clefs du portefeuille (wallet)", "wallet_list_create_new_wallet": "Créer un Nouveau Portefeuille (Wallet)", "wallet_list_edit_wallet": "Modifier le portefeuille", @@ -783,6 +785,5 @@ "you_pay": "Vous payez", "you_will_get": "Convertir vers", "you_will_send": "Convertir depuis", - "yy": "AA", - "waitFewSecondForTxUpdate": "Veuillez attendre quelques secondes pour que la transaction soit reflétée dans l'historique des transactions." -} + "yy": "AA" +} \ No newline at end of file diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 557e6951e..7b71df853 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -637,6 +637,7 @@ "sync_status_starting_sync": "KWAFI", "sync_status_syncronized": "KYAU", "sync_status_syncronizing": "KWAFI", + "sync_status_unsupported": "Ba a Taimako ba", "syncing_wallet_alert_content": "Ma'aunin ku da lissafin ma'amala bazai cika ba har sai an ce \"SYNCHRONIZED\" a saman. Danna/matsa don ƙarin koyo.", "syncing_wallet_alert_title": "Walat ɗin ku yana aiki tare", "template": "Samfura", @@ -735,6 +736,7 @@ "view_key_private": "Duba maɓallin (maɓallin kalmar sirri)", "view_key_public": "Maɓallin Duba (maɓallin jama'a)", "view_transaction_on": "Dubo aikace-aikacen akan", + "waitFewSecondForTxUpdate": "Da fatan za a jira ƴan daƙiƙa don ciniki don yin tunani a tarihin ma'amala", "wallet_keys": "Iri/maɓalli na walat", "wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet", "wallet_list_edit_wallet": "Gyara walat", @@ -785,6 +787,5 @@ "you_pay": "Ka Bayar", "you_will_get": "Maida zuwa", "you_will_send": "Maida daga", - "yy": "YY", - "waitFewSecondForTxUpdate": "Da fatan za a jira ƴan daƙiƙa don ciniki don yin tunani a tarihin ma'amala" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 12383e2fb..b90bb40d7 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -637,6 +637,7 @@ "sync_status_starting_sync": "सिताज़ा करना", "sync_status_syncronized": "सिंक्रनाइज़", "sync_status_syncronizing": "सिंक्रनाइज़ करने", + "sync_status_unsupported": "असमर्थित नोड", "syncing_wallet_alert_content": "आपकी शेष राशि और लेनदेन सूची तब तक पूरी नहीं हो सकती जब तक कि शीर्ष पर \"सिंक्रनाइज़्ड\" न लिखा हो। अधिक जानने के लिए क्लिक/टैप करें।", "syncing_wallet_alert_title": "आपका वॉलेट सिंक हो रहा है", "template": "खाका", @@ -735,6 +736,7 @@ "view_key_private": "कुंजी देखें(निजी)", "view_key_public": "कुंजी देखें (जनता)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "लेन-देन इतिहास में लेन-देन प्रतिबिंबित होने के लिए कृपया कुछ सेकंड प्रतीक्षा करें", "wallet_keys": "बटुआ बीज / चाबियाँ", "wallet_list_create_new_wallet": "नया बटुआ बनाएँ", "wallet_list_edit_wallet": "बटुआ संपादित करें", @@ -785,6 +787,5 @@ "you_pay": "आप भुगतान करते हैं", "you_will_get": "में बदलें", "you_will_send": "से रूपांतरित करें", - "yy": "वाईवाई", - "waitFewSecondForTxUpdate": "लेन-देन इतिहास में लेन-देन प्रतिबिंबित होने के लिए कृपया कुछ सेकंड प्रतीक्षा करें" -} + "yy": "वाईवाई" +} \ No newline at end of file diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index ac351b03e..8d9cce183 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "ZAPOČINJEMO SINKRONIZIRANJE", "sync_status_syncronized": "SINKRONIZIRANO", "sync_status_syncronizing": "SINKRONIZIRANJE", + "sync_status_unsupported": "Nepodržani čvor", "syncing_wallet_alert_content": "Vaš saldo i popis transakcija možda neće biti potpuni sve dok na vrhu ne piše \"SINKRONIZIRANO\". Kliknite/dodirnite da biste saznali više.", "syncing_wallet_alert_title": "Vaš novčanik se sinkronizira", "template": "Predložak", @@ -733,6 +734,7 @@ "view_key_private": "View key (privatni)", "view_key_public": "View key (javni)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Pričekajte nekoliko sekundi da se transakcija prikaže u povijesti transakcija", "wallet_keys": "Pristupni izraz/ključ novčanika", "wallet_list_create_new_wallet": "Izradi novi novčanik", "wallet_list_edit_wallet": "Uredi novčanik", @@ -783,6 +785,5 @@ "you_pay": "Vi plaćate", "you_will_get": "Razmijeni u", "you_will_send": "Razmijeni iz", - "yy": "GG", - "waitFewSecondForTxUpdate": "Pričekajte nekoliko sekundi da se transakcija prikaže u povijesti transakcija" -} + "yy": "GG" +} \ No newline at end of file diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 2756fcca0..53c344668 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -638,6 +638,7 @@ "sync_status_starting_sync": "MULAI SINKRONISASI", "sync_status_syncronized": "SUDAH TERSINKRONISASI", "sync_status_syncronizing": "SEDANG SINKRONISASI", + "sync_status_unsupported": "Node yang tidak didukung", "syncing_wallet_alert_content": "Saldo dan daftar transaksi Anda mungkin belum lengkap sampai tertulis “SYNCHRONIZED” di bagian atas. Klik/ketuk untuk mempelajari lebih lanjut.", "syncing_wallet_alert_title": "Dompet Anda sedang disinkronkan", "template": "Template", @@ -736,6 +737,7 @@ "view_key_private": "Kunci tampilan (privat)", "view_key_public": "Kunci tampilan (publik)", "view_transaction_on": "Lihat Transaksi di ", + "waitFewSecondForTxUpdate": "Mohon tunggu beberapa detik hingga transaksi terlihat di riwayat transaksi", "wallet_keys": "Seed/kunci dompet", "wallet_list_create_new_wallet": "Buat Dompet Baru", "wallet_list_edit_wallet": "Edit dompet", @@ -786,6 +788,5 @@ "you_pay": "Anda Membayar", "you_will_get": "Konversi ke", "you_will_send": "Konversi dari", - "yy": "YY", - "waitFewSecondForTxUpdate": "Mohon tunggu beberapa detik hingga transaksi terlihat di riwayat transaksi" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 83597d4c9..7b9b8d9fc 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -637,6 +637,7 @@ "sync_status_starting_sync": "INIZIO SINC", "sync_status_syncronized": "SINCRONIZZATO", "sync_status_syncronizing": "SINCRONIZZAZIONE", + "sync_status_unsupported": "Nodo non supportato", "syncing_wallet_alert_content": "Il saldo e l'elenco delle transazioni potrebbero non essere completi fino a quando non viene visualizzato \"SYNCHRONIZED\" in alto. Clicca/tocca per saperne di più.", "syncing_wallet_alert_title": "Il tuo portafoglio si sta sincronizzando", "template": "Modello", @@ -735,6 +736,7 @@ "view_key_private": "Chiave di visualizzazione (privata)", "view_key_public": "Chiave di visualizzazione (pubblica)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Attendi qualche secondo affinché la transazione venga riflessa nella cronologia delle transazioni", "waiting_payment_confirmation": "In attesa di conferma del pagamento", "wallet_keys": "Seme Portafoglio /chiavi", "wallet_list_create_new_wallet": "Crea Nuovo Portafoglio", @@ -786,6 +788,5 @@ "you_pay": "Tu paghi", "you_will_get": "Converti a", "you_will_send": "Conveti da", - "yy": "YY", - "waitFewSecondForTxUpdate": "Attendi qualche secondo affinché la transazione venga riflessa nella cronologia delle transazioni" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index eb74091a9..1e6006a5c 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "同期の開始", "sync_status_syncronized": "同期された", "sync_status_syncronizing": "同期", + "sync_status_unsupported": "サポートされていないノード", "syncing_wallet_alert_content": "上部に「同期済み」と表示されるまで、残高と取引リストが完了していない可能性があります。詳細については、クリック/タップしてください。", "syncing_wallet_alert_title": "ウォレットは同期中です", "template": "テンプレート", @@ -734,6 +735,7 @@ "view_key_private": "ビューキー (プライベート)", "view_key_public": "ビューキー (パブリック)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "取引履歴に取引が反映されるまで数秒お待ちください。", "wallet_keys": "ウォレットシード/キー", "wallet_list_create_new_wallet": "新しいウォレットを作成", "wallet_list_edit_wallet": "ウォレットを編集する", @@ -784,6 +786,5 @@ "you_pay": "あなたが支払う", "you_will_get": "に変換", "you_will_send": "から変換", - "yy": "YY", - "waitFewSecondForTxUpdate": "取引履歴に取引が反映されるまで数秒お待ちください。" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 9a8bf4883..3171b6748 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "동기화 시작", "sync_status_syncronized": "동기화", "sync_status_syncronizing": "동기화", + "sync_status_unsupported": "지원되지 않은 노드", "syncing_wallet_alert_content": "상단에 \"동기화됨\"이라고 표시될 때까지 잔액 및 거래 목록이 완전하지 않을 수 있습니다. 자세히 알아보려면 클릭/탭하세요.", "syncing_wallet_alert_title": "지갑 동기화 중", "template": "주형", @@ -734,6 +735,7 @@ "view_key_private": "키보기(은밀한)", "view_key_public": "키보기 (공공의)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "거래 내역에 거래가 반영될 때까지 몇 초 정도 기다려 주세요.", "wallet_keys": "지갑 시드 / 키", "wallet_list_create_new_wallet": "새 월렛 만들기", "wallet_list_edit_wallet": "지갑 수정", @@ -785,6 +787,5 @@ "you_will_get": "로 변환하다", "you_will_send": "다음에서 변환", "YY": "YY", - "yy": "YY", - "waitFewSecondForTxUpdate": "거래 내역에 거래가 반영될 때까지 몇 초 정도 기다려 주세요." -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 711c3c884..2eacf4180 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "စင့်ခ်လုပ်ခြင်း။", "sync_status_syncronized": "ထပ်တူပြုထားသည်။", "sync_status_syncronizing": "ထပ်တူပြုခြင်း။", + "sync_status_unsupported": "node မထောက်ပံ့ node ကို", "syncing_wallet_alert_content": "သင်၏လက်ကျန်နှင့် ငွေပေးငွေယူစာရင်းသည် ထိပ်တွင် \"Synchronizeed\" ဟုပြောသည်အထိ မပြီးမြောက်နိုင်ပါ။ ပိုမိုလေ့လာရန် နှိပ်/နှိပ်ပါ။", "syncing_wallet_alert_title": "သင့်ပိုက်ဆံအိတ်ကို စင့်ခ်လုပ်နေပါသည်။", "template": "ပုံစံခွက်", @@ -733,6 +734,7 @@ "view_key_private": "သော့ကိုကြည့်ရန် (သီးသန့်)", "view_key_public": "သော့ကိုကြည့်ရန် (အများပြည်သူ)", "view_transaction_on": "ငွေလွှဲခြင်းကို ဖွင့်ကြည့်ပါ။", + "waitFewSecondForTxUpdate": "ငွေပေးငွေယူ မှတ်တမ်းတွင် ရောင်ပြန်ဟပ်ရန် စက္ကန့်အနည်းငယ်စောင့်ပါ။", "wallet_keys": "ပိုက်ဆံအိတ် အစေ့/သော့များ", "wallet_list_create_new_wallet": "Wallet အသစ်ဖန်တီးပါ။", "wallet_list_edit_wallet": "ပိုက်ဆံအိတ်ကို တည်းဖြတ်ပါ။", @@ -783,6 +785,5 @@ "you_pay": "သင်ပေးချေပါ။", "you_will_get": "သို့ပြောင်းပါ။", "you_will_send": "မှပြောင်းပါ။", - "yy": "YY", - "waitFewSecondForTxUpdate": "ငွေပေးငွေယူ မှတ်တမ်းတွင် ရောင်ပြန်ဟပ်ရန် စက္ကန့်အနည်းငယ်စောင့်ပါ။" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 7527eb10f..115151748 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "BEGINNEN MET SYNCHRONISEREN", "sync_status_syncronized": "SYNCHRONIZED", "sync_status_syncronizing": "SYNCHRONISEREN", + "sync_status_unsupported": "Niet ondersteund knooppunt", "syncing_wallet_alert_content": "Uw saldo- en transactielijst is mogelijk pas compleet als er bovenaan 'GESYNCHRONISEERD' staat. Klik/tik voor meer informatie.", "syncing_wallet_alert_title": "Uw portemonnee wordt gesynchroniseerd", "template": "Sjabloon", @@ -733,6 +734,7 @@ "view_key_private": "Bekijk sleutel (privaat)", "view_key_public": "Bekijk sleutel (openbaar)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Wacht een paar seconden totdat de transactie wordt weergegeven in de transactiegeschiedenis", "waiting_payment_confirmation": "In afwachting van betalingsbevestiging", "wallet_keys": "Portemonnee zaad/sleutels", "wallet_list_create_new_wallet": "Maak een nieuwe portemonnee", @@ -784,6 +786,5 @@ "you_pay": "U betaalt", "you_will_get": "Converteren naar", "you_will_send": "Converteren van", - "yy": "JJ", - "waitFewSecondForTxUpdate": "Wacht een paar seconden totdat de transactie wordt weergegeven in de transactiegeschiedenis" -} + "yy": "JJ" +} \ No newline at end of file diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index e93e56f74..0e84e5c87 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "ROZPOCZĘCIE SYNCHRONIZACJI", "sync_status_syncronized": "ZSYNCHRONIZOWANO", "sync_status_syncronizing": "SYNCHRONIZACJA", + "sync_status_unsupported": "Nieobsługiwany węzeł", "syncing_wallet_alert_content": "Twoje saldo i lista transakcji mogą nie być kompletne, dopóki u góry nie pojawi się napis „SYNCHRONIZOWANY”. Kliknij/stuknij, aby dowiedzieć się więcej.", "syncing_wallet_alert_title": "Twój portfel się synchronizuje", "template": "Szablon", @@ -733,6 +734,7 @@ "view_key_private": "Prywatny Klucz Wglądu", "view_key_public": "Publiczny Klucz Wglądu", "view_transaction_on": "Zobacz transakcje na ", + "waitFewSecondForTxUpdate": "Poczekaj kilka sekund, aż transakcja zostanie odzwierciedlona w historii transakcji", "wallet_keys": "Klucze portfela", "wallet_list_create_new_wallet": "Utwórz nowy portfel", "wallet_list_edit_wallet": "Edytuj portfel", @@ -783,6 +785,5 @@ "you_pay": "Płacisz", "you_will_get": "Konwertuj na", "you_will_send": "Konwertuj z", - "yy": "RR", - "waitFewSecondForTxUpdate": "Poczekaj kilka sekund, aż transakcja zostanie odzwierciedlona w historii transakcji" -} + "yy": "RR" +} \ No newline at end of file diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index a7c1ff7e5..73a2988ff 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -637,6 +637,7 @@ "sync_status_starting_sync": "INICIANDO SINCRONIZAÇÃO", "sync_status_syncronized": "SINCRONIZADO", "sync_status_syncronizing": "SINCRONIZANDO", + "sync_status_unsupported": "Nó não suportado", "syncing_wallet_alert_content": "Seu saldo e lista de transações podem não estar completos até que diga “SYNCHRONIZED” no topo. Clique/toque para saber mais.", "syncing_wallet_alert_title": "Sua carteira está sincronizando", "template": "Modelo", @@ -735,6 +736,7 @@ "view_key_private": "Chave de visualização (privada)", "view_key_public": "Chave de visualização (pública)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Aguarde alguns segundos para que a transação seja refletida no histórico de transações", "waiting_payment_confirmation": "Aguardando confirmação de pagamento", "wallet_keys": "Semente/chaves da carteira", "wallet_list_create_new_wallet": "Criar nova carteira", @@ -786,6 +788,5 @@ "you_pay": "Você paga", "you_will_get": "Converter para", "you_will_send": "Converter de", - "yy": "aa", - "waitFewSecondForTxUpdate": "Aguarde alguns segundos para que a transação seja refletida no histórico de transações" -} + "yy": "aa" +} \ No newline at end of file diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index d339d2670..0ce75cc87 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "НАЧАЛО СИНХРОНИЗАЦИИ", "sync_status_syncronized": "СИНХРОНИЗИРОВАН", "sync_status_syncronizing": "СИНХРОНИЗАЦИЯ", + "sync_status_unsupported": "Неподдерживаемый узел", "syncing_wallet_alert_content": "Ваш баланс и список транзакций могут быть неполными, пока вверху не будет написано «СИНХРОНИЗИРОВАНО». Щелкните/коснитесь, чтобы узнать больше.", "syncing_wallet_alert_title": "Ваш кошелек синхронизируется", "template": "Шаблон", @@ -734,6 +735,7 @@ "view_key_private": "Приватный ключ просмотра", "view_key_public": "Публичный ключ просмотра", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Пожалуйста, подождите несколько секунд, чтобы транзакция отразилась в истории транзакций.", "wallet_keys": "Мнемоническая фраза/ключи кошелька", "wallet_list_create_new_wallet": "Создать новый кошелёк", "wallet_list_edit_wallet": "Изменить кошелек", @@ -784,6 +786,5 @@ "you_pay": "Вы платите", "you_will_get": "Конвертировать в", "you_will_send": "Конвертировать из", - "yy": "ГГ", - "waitFewSecondForTxUpdate": "Пожалуйста, подождите несколько секунд, чтобы транзакция отразилась в истории транзакций." -} + "yy": "ГГ" +} \ No newline at end of file diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index a4bb58d7d..f165b7e35 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "กำลังเริ่มซิงโครไนซ์", "sync_status_syncronized": "ซิงโครไนซ์แล้ว", "sync_status_syncronizing": "กำลังซิงโครไนซ์", + "sync_status_unsupported": "โหนดที่ไม่ได้รับการสนับสนุน", "syncing_wallet_alert_content": "รายการยอดเงินและธุรกรรมของคุณอาจไม่สมบูรณ์จนกว่าจะมีข้อความว่า “ซิงโครไนซ์” ที่ด้านบน คลิก/แตะเพื่อเรียนรู้เพิ่มเติม่", "syncing_wallet_alert_title": "กระเป๋าสตางค์ของคุณกำลังซิงค์", "template": "แบบฟอร์ม", @@ -733,6 +734,7 @@ "view_key_private": "คีย์มุมมอง (ส่วนตัว)", "view_key_public": "คีย์มุมมอง (สาธารณะ)", "view_transaction_on": "ดูการทำธุรกรรมบน ", + "waitFewSecondForTxUpdate": "กรุณารอสักครู่เพื่อให้ธุรกรรมปรากฏในประวัติการทำธุรกรรม", "wallet_keys": "ซีดของกระเป๋า/คีย์", "wallet_list_create_new_wallet": "สร้างกระเป๋าใหม่", "wallet_list_edit_wallet": "แก้ไขกระเป๋าสตางค์", @@ -783,6 +785,5 @@ "you_pay": "คุณจ่าย", "you_will_get": "แปลงเป็น", "you_will_send": "แปลงจาก", - "yy": "ปี", - "waitFewSecondForTxUpdate": "กรุณารอสักครู่เพื่อให้ธุรกรรมปรากฏในประวัติการทำธุรกรรม" -} + "yy": "ปี" +} \ No newline at end of file diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 2e9520dce..b87794f2e 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "Simula sa pag -sync", "sync_status_syncronized": "Naka -synchronize", "sync_status_syncronizing": "Pag -synchronize", + "sync_status_unsupported": "Hindi suportadong node", "syncing_wallet_alert_content": "Ang iyong balanse at listahan ng transaksyon ay maaaring hindi kumpleto hanggang sa sabihin nito na \"naka -synchronize\" sa tuktok. Mag -click/tap upang malaman ang higit pa.", "syncing_wallet_alert_title": "Ang iyong pitaka ay nag -sync", "template": "Template", @@ -733,6 +734,7 @@ "view_key_private": "Tingnan ang Key (Pribado)", "view_key_public": "Tingnan ang Key (Publiko)", "view_transaction_on": "Tingnan ang transaksyon sa", + "waitFewSecondForTxUpdate": "Mangyaring maghintay ng ilang segundo para makita ang transaksyon sa history ng mga transaksyon", "wallet_keys": "Mga buto/susi ng pitaka", "wallet_list_create_new_wallet": "Lumikha ng bagong pitaka", "wallet_list_edit_wallet": "I -edit ang Wallet", @@ -783,6 +785,5 @@ "you_pay": "Magbabayad ka", "you_will_get": "Mag -convert sa", "you_will_send": "I -convert mula sa", - "yy": "YY", - "waitFewSecondForTxUpdate": "Mangyaring maghintay ng ilang segundo para makita ang transaksyon sa history ng mga transaksyon" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 75148b2ca..80f9ced27 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "SENKRONİZE BAŞLATILIYOR", "sync_status_syncronized": "SENKRONİZE EDİLDİ", "sync_status_syncronizing": "SENKRONİZE EDİLİYOR", + "sync_status_unsupported": "Desteklenmeyen düğüm", "syncing_wallet_alert_content": "Bakiyeniz ve işlem listeniz, en üstte \"SENKRONİZE EDİLDİ\" yazana kadar tamamlanmamış olabilir. Daha fazla bilgi edinmek için tıklayın/dokunun.", "syncing_wallet_alert_title": "Cüzdanınız senkronize ediliyor", "template": "Şablon", @@ -733,6 +734,7 @@ "view_key_private": "İzleme anahtarı (özel)", "view_key_public": "İzleme anahtarı (genel)", "view_transaction_on": "İşlemi şurada görüntüle ", + "waitFewSecondForTxUpdate": "İşlemin işlem geçmişine yansıması için lütfen birkaç saniye bekleyin", "wallet_keys": "Cüzdan tohumu/anahtarları", "wallet_list_create_new_wallet": "Yeni Cüzdan Oluştur", "wallet_list_edit_wallet": "Cüzdanı düzenle", @@ -783,6 +785,5 @@ "you_pay": "Şu kadar ödeyeceksin: ", "you_will_get": "Biçimine dönüştür:", "you_will_send": "Biçiminden dönüştür:", - "yy": "YY", - "waitFewSecondForTxUpdate": "İşlemin işlem geçmişine yansıması için lütfen birkaç saniye bekleyin" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index a461d10a5..0363c4f48 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "ПОЧАТОК СИНХРОНІЗАЦІЇ", "sync_status_syncronized": "СИНХРОНІЗОВАНИЙ", "sync_status_syncronizing": "СИНХРОНІЗАЦІЯ", + "sync_status_unsupported": "Непідтримуваний вузол", "syncing_wallet_alert_content": "Ваш баланс та список транзакцій може бути неповним, доки вгорі не буде написано «СИНХРОНІЗОВАНО». Натисніть/торкніться, щоб дізнатися більше.", "syncing_wallet_alert_title": "Ваш гаманець синхронізується", "template": "Шаблон", @@ -734,6 +735,7 @@ "view_key_private": "Приватний ключ перегляду", "view_key_public": "Публічний ключ перегляду", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "Будь ласка, зачекайте кілька секунд, поки транзакція відобразиться в історії транзакцій", "wallet_keys": "Мнемонічна фраза/ключі гаманця", "wallet_list_create_new_wallet": "Створити новий гаманець", "wallet_list_edit_wallet": "Редагувати гаманець", @@ -784,6 +786,5 @@ "you_pay": "Ви платите", "you_will_get": "Конвертувати в", "you_will_send": "Конвертувати з", - "yy": "YY", - "waitFewSecondForTxUpdate": "Будь ласка, зачекайте кілька секунд, поки транзакція відобразиться в історії транзакцій" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 7ba95a3c5..ed1cdef11 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -637,6 +637,7 @@ "sync_status_starting_sync": "مطابقت پذیری شروع کر رہا ہے۔", "sync_status_syncronized": "مطابقت پذیر", "sync_status_syncronizing": "مطابقت پذیری", + "sync_status_unsupported": "غیر تعاون یافتہ نوڈ", "syncing_wallet_alert_content": "آپ کے بیلنس اور لین دین کی فہرست اس وقت تک مکمل نہیں ہو سکتی جب تک کہ یہ سب سے اوپر \"SYNCRONIZED\" نہ کہے۔ مزید جاننے کے لیے کلک/تھپتھپائیں۔", "syncing_wallet_alert_title": "آپ کا بٹوہ مطابقت پذیر ہو رہا ہے۔", "template": "سانچے", @@ -735,6 +736,7 @@ "view_key_private": "کلید دیکھیں (نجی)", "view_key_public": "کلید دیکھیں (عوامی)", "view_transaction_on": "لین دین دیکھیں آن", + "waitFewSecondForTxUpdate": "۔ﮟﯾﺮﮐ ﺭﺎﻈﺘﻧﺍ ﺎﮐ ﮉﻨﮑﯿﺳ ﺪﻨﭼ ﻡﺮﮐ ﮦﺍﺮﺑ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﯽﺳﺎﮑﻋ ﯽﮐ ﻦﯾﺩ ﻦﯿﻟ ﮟﯿﻣ ﺦﯾﺭﺎﺗ ﯽﮐ ﻦ", "wallet_keys": "بٹوے کے بیج / چابیاں", "wallet_list_create_new_wallet": "نیا والیٹ بنائیں", "wallet_list_edit_wallet": "بٹوے میں ترمیم کریں۔", @@ -785,6 +787,5 @@ "you_pay": "تم ادا کرو", "you_will_get": "میں تبدیل کریں۔", "you_will_send": "سے تبدیل کریں۔", - "yy": "YY", - "waitFewSecondForTxUpdate": "۔ﮟﯾﺮﮐ ﺭﺎﻈﺘﻧﺍ ﺎﮐ ﮉﻨﮑﯿﺳ ﺪﻨﭼ ﻡﺮﮐ ﮦﺍﺮﺑ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﯽﺳﺎﮑﻋ ﯽﮐ ﻦﯾﺩ ﻦﯿﻟ ﮟﯿﻣ ﺦﯾﺭﺎﺗ ﯽﮐ ﻦ" -} + "yy": "YY" +} \ No newline at end of file diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 13af65480..824e87bb8 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -636,6 +636,7 @@ "sync_status_starting_sync": "Ń BẸ̀RẸ̀ RẸ́", "sync_status_syncronized": "TI MÚDỌ́GBA", "sync_status_syncronizing": "Ń MÚDỌ́GBA", + "sync_status_unsupported": "Ile-igbimọ ti ko ni atilẹyin", "syncing_wallet_alert_content": "Iwontunws.funfun rẹ ati atokọ idunadura le ma pari titi ti yoo fi sọ “SYNCHRONIZED” ni oke. Tẹ/tẹ ni kia kia lati ni imọ siwaju sii.", "syncing_wallet_alert_title": "Apamọwọ rẹ n muṣiṣẹpọ", "template": "Àwòṣe", @@ -734,6 +735,7 @@ "view_key_private": "Kọ́kọ́rọ́ ìwò (àdáni)", "view_key_public": "Kọ́kọ́rọ́ ìwò (kò àdáni)", "view_transaction_on": "Wo pàṣípààrọ̀ lórí ", + "waitFewSecondForTxUpdate": "Fi inurere duro fun awọn iṣeju diẹ fun idunadura lati ṣe afihan ninu itan-akọọlẹ iṣowo", "wallet_keys": "Hóró/kọ́kọ́rọ́ àpamọ́wọ́", "wallet_list_create_new_wallet": "Ṣe àpamọ́wọ́ títun", "wallet_list_edit_wallet": "Ṣatunkọ apamọwọ", @@ -784,6 +786,5 @@ "you_pay": "Ẹ sàn", "you_will_get": "Ṣe pàṣípààrọ̀ sí", "you_will_send": "Ṣe pàṣípààrọ̀ láti", - "yy": "Ọd", - "waitFewSecondForTxUpdate": "Fi inurere duro fun awọn iṣeju diẹ fun idunadura lati ṣe afihan ninu itan-akọọlẹ iṣowo" -} + "yy": "Ọd" +} \ No newline at end of file diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 9c8298134..7b53264b6 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -635,6 +635,7 @@ "sync_status_starting_sync": "开始同步", "sync_status_syncronized": "已同步", "sync_status_syncronizing": "正在同步", + "sync_status_unsupported": "不支持的节点", "syncing_wallet_alert_content": "您的余额和交易列表可能不完整,直到顶部显示“已同步”。单击/点击以了解更多信息。", "syncing_wallet_alert_title": "您的钱包正在同步", "template": "模板", @@ -733,6 +734,7 @@ "view_key_private": "View 密钥(私钥)", "view_key_public": "View 密钥(公钥)", "view_transaction_on": "View Transaction on ", + "waitFewSecondForTxUpdate": "请等待几秒钟,交易才会反映在交易历史记录中", "wallet_keys": "钱包种子/密钥", "wallet_list_create_new_wallet": "创建新钱包", "wallet_list_edit_wallet": "编辑钱包", @@ -783,6 +785,5 @@ "you_pay": "你付钱", "you_will_get": "转换到", "you_will_send": "转换自", - "yy": "YY", - "waitFewSecondForTxUpdate": "请等待几秒钟,交易才会反映在交易历史记录中" -} + "yy": "YY" +} \ No newline at end of file diff --git a/tool/configure.dart b/tool/configure.dart index bf89743ef..2dd772bbe 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -125,7 +125,7 @@ abstract class Bitcoin { List getAddresses(Object wallet); String getAddress(Object wallet); - List getSilentAddresses(Object wallet); + List getSilentAddresses(Object wallet); List getSubAddresses(Object wallet);