From 3a391f10a37e4f8726fb6d374fe3aa217a78a1b7 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 20 Sep 2024 14:24:25 +0000 Subject: [PATCH] Sp enhancements (#1672) * fix: enhance regex, fix multiline * feat: improve scan msg, fix missing txs, use date api * feat: node fixes, enhance send modal, TX list tag & filter, refactors * fix: continuous scanning * fix: missing close * fix: resubscribe tweaks * feat: use mempool api setting toggle * handle any failure of height API and fallback to the old method [skip ci] --------- Co-authored-by: OmarHatem --- cw_bitcoin/lib/address_to_output_script.dart | 14 -- cw_bitcoin/lib/bitcoin_address_record.dart | 7 +- cw_bitcoin/lib/electrum.dart | 58 ++--- cw_bitcoin/lib/electrum_transaction_info.dart | 32 ++- cw_bitcoin/lib/electrum_wallet.dart | 201 +++++++++------- cw_bitcoin/lib/litecoin_wallet.dart | 2 +- .../lib/pending_bitcoin_transaction.dart | 13 + cw_bitcoin/lib/script_hash.dart | 19 -- cw_bitcoin/pubspec.lock | 4 +- cw_bitcoin/pubspec.yaml | 2 +- cw_bitcoin_cash/pubspec.yaml | 2 +- cw_core/lib/get_height_by_date.dart | 11 +- cw_core/lib/pending_transaction.dart | 8 + cw_core/lib/sync_status.dart | 8 + cw_nano/pubspec.lock | 4 +- lib/bitcoin/cw_bitcoin.dart | 48 +++- lib/core/address_validator.dart | 123 +++++----- lib/core/sync_status_title.dart | 6 +- lib/entities/parse_address_from_domain.dart | 5 +- .../dashboard/pages/transactions_page.dart | 12 +- .../dashboard/widgets/transaction_raw.dart | 126 ++++++---- lib/src/screens/rescan/rescan_page.dart | 1 + lib/src/screens/send/send_page.dart | 50 ++-- .../send/widgets/confirm_sending_alert.dart | 223 +++++++++++------- lib/src/screens/settings/privacy_page.dart | 26 +- lib/src/widgets/blockchain_height_widget.dart | 14 +- .../dashboard/transaction_filter_store.dart | 59 +++-- .../dashboard/dashboard_view_model.dart | 14 +- lib/view_model/rescan_view_model.dart | 4 + lib/view_model/send/output.dart | 19 +- lib/view_model/send/send_view_model.dart | 11 +- pubspec_base.yaml | 4 +- res/values/strings_ar.arb | 9 +- res/values/strings_bg.arb | 9 +- res/values/strings_cs.arb | 9 +- res/values/strings_de.arb | 9 +- res/values/strings_en.arb | 9 +- res/values/strings_es.arb | 9 +- res/values/strings_fr.arb | 9 +- res/values/strings_ha.arb | 9 +- res/values/strings_hi.arb | 9 +- res/values/strings_hr.arb | 9 +- res/values/strings_hy.arb | 9 +- res/values/strings_id.arb | 9 +- res/values/strings_it.arb | 9 +- res/values/strings_ja.arb | 9 +- res/values/strings_ko.arb | 9 +- res/values/strings_my.arb | 9 +- res/values/strings_nl.arb | 9 +- res/values/strings_pl.arb | 9 +- res/values/strings_pt.arb | 13 +- res/values/strings_ru.arb | 9 +- res/values/strings_th.arb | 9 +- res/values/strings_tl.arb | 9 +- res/values/strings_tr.arb | 9 +- res/values/strings_uk.arb | 9 +- res/values/strings_ur.arb | 9 +- res/values/strings_vi.arb | 19 +- res/values/strings_yo.arb | 9 +- res/values/strings_zh.arb | 9 +- tool/configure.dart | 7 +- 61 files changed, 872 insertions(+), 531 deletions(-) delete mode 100644 cw_bitcoin/lib/address_to_output_script.dart delete mode 100644 cw_bitcoin/lib/script_hash.dart diff --git a/cw_bitcoin/lib/address_to_output_script.dart b/cw_bitcoin/lib/address_to_output_script.dart deleted file mode 100644 index 892f7a0d6..000000000 --- a/cw_bitcoin/lib/address_to_output_script.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:typed_data'; -import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin; - -List addressToOutputScript(String address, bitcoin.BasedUtxoNetwork network) { - try { - if (network == bitcoin.BitcoinCashNetwork.mainnet) { - return bitcoin.BitcoinCashAddress(address).baseAddress.toScriptPubKey().toBytes(); - } - return bitcoin.addressToOutputScript(address: address, network: network); - } catch (err) { - print(err); - return Uint8List(0); - } -} diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index bf36e6fb9..7e4b5f58f 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'package:bitcoin_base/bitcoin_base.dart'; -import 'package:cw_bitcoin/script_hash.dart' as sh; abstract class BaseBitcoinAddressRecord { BaseBitcoinAddressRecord( @@ -65,8 +64,8 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { required super.type, String? scriptHash, required super.network, - }) : scriptHash = - scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null); + }) : scriptHash = scriptHash ?? + (network != null ? BitcoinAddressUtils.scriptHash(address, network: network) : null); factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) { final decoded = json.decode(jsonSource) as Map; @@ -92,7 +91,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { String getScriptHash(BasedUtxoNetwork network) { if (scriptHash != null) return scriptHash!; - scriptHash = sh.scriptHash(address, network: network); + scriptHash = BitcoinAddressUtils.scriptHash(address, network: network); return scriptHash!; } diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart index 8dfb8e01f..d8cca5b16 100644 --- a/cw_bitcoin/lib/electrum.dart +++ b/cw_bitcoin/lib/electrum.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart'; -import 'package:cw_bitcoin/script_hash.dart'; import 'package:flutter/foundation.dart'; import 'package:rxdart/rxdart.dart'; @@ -48,6 +47,7 @@ class ElectrumClient { final Map _tasks; Map get tasks => _tasks; final Map _errors; + ConnectionStatus _connectionStatus = ConnectionStatus.disconnected; bool _isConnected; Timer? _aliveTimer; String unterminatedString; @@ -57,11 +57,13 @@ class ElectrumClient { Future connectToUri(Uri uri, {bool? useSSL}) async { this.uri = uri; - this.useSSL = useSSL; - await connect(host: uri.host, port: uri.port, useSSL: useSSL); + if (useSSL != null) { + this.useSSL = useSSL; + } + await connect(host: uri.host, port: uri.port); } - Future connect({required String host, required int port, bool? useSSL}) async { + Future connect({required String host, required int port}) async { _setConnectionStatus(ConnectionStatus.connecting); try { @@ -80,15 +82,26 @@ class ElectrumClient { onBadCertificate: (_) => true, ); } - } catch (_) { - _setConnectionStatus(ConnectionStatus.failed); + } catch (e) { + if (e is HandshakeException) { + useSSL = !(useSSL ?? false); + } + + if (_connectionStatus != ConnectionStatus.connecting) { + _setConnectionStatus(ConnectionStatus.failed); + } + return; } if (socket == null) { - _setConnectionStatus(ConnectionStatus.failed); + if (_connectionStatus != ConnectionStatus.connecting) { + _setConnectionStatus(ConnectionStatus.failed); + } + return; } + _setConnectionStatus(ConnectionStatus.connected); socket!.listen( @@ -118,7 +131,7 @@ class ElectrumClient { socket?.destroy(); _setConnectionStatus(ConnectionStatus.disconnected); } - } catch(e) { + } catch (e) { print(e.toString()); } }, @@ -217,25 +230,6 @@ class ElectrumClient { return []; }); - Future>> getListUnspentWithAddress( - String address, BasedUtxoNetwork network) => - call( - method: 'blockchain.scripthash.listunspent', - params: [scriptHash(address, network: network)]).then((dynamic result) { - if (result is List) { - return result.map((dynamic val) { - if (val is Map) { - val['address'] = address; - return val; - } - - return {}; - }).toList(); - } - - return []; - }); - Future>> getListUnspent(String scriptHash) => call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]) .then((dynamic result) { @@ -272,16 +266,12 @@ class ElectrumClient { try { final result = await callWithTimeout( method: 'blockchain.transaction.get', params: [hash, verbose], timeout: 10000); - if (result is Map) { - return result; - } + return result; } on RequestFailedTimeoutException catch (_) { return {}; } catch (e) { - print("getTransaction: ${e.toString()}"); return {}; } - return {}; } Future> getTransactionVerbose({required String hash}) => @@ -326,9 +316,8 @@ class ElectrumClient { await call(method: 'blockchain.block.get_header', params: [height]) as Map; BehaviorSubject? tweaksSubscribe({required int height, required int count}) { - _id += 1; return subscribe( - id: 'blockchain.tweaks.subscribe:${height + count}', + id: 'blockchain.tweaks.subscribe', method: 'blockchain.tweaks.subscribe', params: [height, count, false], ); @@ -539,6 +528,7 @@ class ElectrumClient { void _setConnectionStatus(ConnectionStatus status) { onConnectionStatusChange?.call(status); + _connectionStatus = status; _isConnected = status == ConnectionStatus.connected; } diff --git a/cw_bitcoin/lib/electrum_transaction_info.dart b/cw_bitcoin/lib/electrum_transaction_info.dart index ebd90ff2b..8b52b7aca 100644 --- a/cw_bitcoin/lib/electrum_transaction_info.dart +++ b/cw_bitcoin/lib/electrum_transaction_info.dart @@ -23,20 +23,24 @@ class ElectrumTransactionBundle { class ElectrumTransactionInfo extends TransactionInfo { List? unspents; + bool isReceivedSilentPayment; - ElectrumTransactionInfo(this.type, - {required String id, - int? height, - required int amount, - int? fee, - List? inputAddresses, - List? outputAddresses, - required TransactionDirection direction, - required bool isPending, - required DateTime date, - required int confirmations, - String? to, - this.unspents}) { + ElectrumTransactionInfo( + this.type, { + required String id, + int? height, + required int amount, + int? fee, + List? inputAddresses, + List? outputAddresses, + required TransactionDirection direction, + required bool isPending, + required DateTime date, + required int confirmations, + String? to, + this.unspents, + this.isReceivedSilentPayment = false, + }) { this.id = id; this.height = height; this.amount = amount; @@ -202,6 +206,7 @@ class ElectrumTransactionInfo extends TransactionInfo { .map((unspent) => BitcoinSilentPaymentsUnspent.fromJSON(null, unspent as Map)) .toList(), + isReceivedSilentPayment: data['isReceivedSilentPayment'] as bool? ?? false, ); } @@ -252,6 +257,7 @@ class ElectrumTransactionInfo extends TransactionInfo { m['unspents'] = unspents?.map((e) => e.toJson()).toList() ?? []; m['inputAddresses'] = inputAddresses; m['outputAddresses'] = outputAddresses; + m['isReceivedSilentPayment'] = isReceivedSilentPayment; return m; } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index fe8782adb..5eb4bd85c 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -24,7 +24,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/script_hash.dart'; import 'package:cw_bitcoin/utils.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/node.dart'; @@ -51,8 +50,6 @@ part 'electrum_wallet.g.dart'; class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet; -const int TWEAKS_COUNT = 25; - abstract class ElectrumWalletBase extends WalletBase with Store, WalletKeysFile { @@ -166,12 +163,12 @@ abstract class ElectrumWalletBase Set get addressesSet => walletAddresses.allAddresses.map((addr) => addr.address).toSet(); List get scriptHashes => walletAddresses.addressesByReceiveType - .map((addr) => scriptHash(addr.address, network: network)) + .map((addr) => (addr as BitcoinAddressRecord).getScriptHash(network)) .toList(); List get publicScriptHashes => walletAddresses.allAddresses .where((addr) => !addr.isHidden) - .map((addr) => scriptHash(addr.address, network: network)) + .map((addr) => addr.getScriptHash(network)) .toList(); String get xpub => accountHD.publicKey.toExtended; @@ -212,7 +209,7 @@ abstract class ElectrumWalletBase silentPaymentsScanningActive = active; if (active) { - syncStatus = StartingScanSyncStatus(); + syncStatus = AttemptingScanSyncStatus(); final tip = await getUpdatedChainTip(); @@ -290,12 +287,7 @@ abstract class ElectrumWalletBase } @action - Future _setListeners( - int height, { - int? chainTipParam, - bool? doSingleScan, - bool? usingSupportedNode, - }) async { + Future _setListeners(int height, {int? chainTipParam, bool? doSingleScan}) async { final chainTip = chainTipParam ?? await getUpdatedChainTip(); if (chainTip == height) { @@ -303,7 +295,7 @@ abstract class ElectrumWalletBase return; } - syncStatus = StartingScanSyncStatus(); + syncStatus = AttemptingScanSyncStatus(); if (_isolate != null) { final runningIsolate = await _isolate!; @@ -550,7 +542,8 @@ abstract class ElectrumWalletBase electrumClient.onConnectionStatusChange = _onConnectionStatusChange; await electrumClient.connectToUri(node.uri, useSSL: node.useSSL); - } catch (e) { + } catch (e, stacktrace) { + print(stacktrace); print(e.toString()); syncStatus = FailedSyncStatus(); } @@ -592,7 +585,7 @@ abstract class ElectrumWalletBase allInputsAmount += utx.value; leftAmount = leftAmount - utx.value; - final address = addressTypeFromStr(utx.address, network); + final address = RegexUtils.addressTypeFromStr(utx.address, network); ECPrivate? privkey; bool? isSilentPayment = false; @@ -796,10 +789,11 @@ abstract class ElectrumWalletBase } final changeAddress = await walletAddresses.getChangeAddress(); - final address = addressTypeFromStr(changeAddress, network); + final address = RegexUtils.addressTypeFromStr(changeAddress, network); outputs.add(BitcoinOutput( address: address, value: BigInt.from(amountLeftForChangeAndFee), + isChange: true, )); int estimatedSize; @@ -833,8 +827,12 @@ abstract class ElectrumWalletBase if (!_isBelowDust(amountLeftForChange)) { // Here, lastOutput already is change, return the amount left without the fee to the user's address. - outputs[outputs.length - 1] = - BitcoinOutput(address: lastOutput.address, value: BigInt.from(amountLeftForChange)); + outputs[outputs.length - 1] = BitcoinOutput( + address: lastOutput.address, + value: BigInt.from(amountLeftForChange), + isSilentPayment: lastOutput.isSilentPayment, + isChange: true, + ); } else { // If has change that is lower than dust, will end up with tx rejected by network rules, so estimate again without the added change outputs.removeLast(); @@ -938,18 +936,27 @@ abstract class ElectrumWalletBase credentialsAmount += outputAmount; - final address = - addressTypeFromStr(out.isParsedAddress ? out.extractedAddress! : out.address, network); + final address = RegexUtils.addressTypeFromStr( + out.isParsedAddress ? out.extractedAddress! : out.address, network); + final isSilentPayment = address is SilentPaymentAddress; - if (address is SilentPaymentAddress) { + if (isSilentPayment) { hasSilentPayment = true; } if (sendAll) { // The value will be changed after estimating the Tx size and deducting the fee from the total to be sent - outputs.add(BitcoinOutput(address: address, value: BigInt.from(0))); + outputs.add(BitcoinOutput( + address: address, + value: BigInt.from(0), + isSilentPayment: isSilentPayment, + )); } else { - outputs.add(BitcoinOutput(address: address, value: BigInt.from(outputAmount))); + outputs.add(BitcoinOutput( + address: address, + value: BigInt.from(outputAmount), + isSilentPayment: isSilentPayment, + )); } } @@ -1089,7 +1096,8 @@ abstract class ElectrumWalletBase }); } - unspentCoins.removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash)); + unspentCoins + .removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash)); await updateBalance(); }); @@ -1237,12 +1245,7 @@ abstract class ElectrumWalletBase @action @override - Future rescan({ - required int height, - int? chainTip, - ScanData? scanData, - bool? doSingleScan, - }) async { + Future rescan({required int height, bool? doSingleScan}) async { silentPaymentsScanningActive = true; _setListeners(height, doSingleScan: doSingleScan); } @@ -1460,7 +1463,7 @@ abstract class ElectrumWalletBase final addressRecord = walletAddresses.allAddresses.firstWhere((element) => element.address == address); - final btcAddress = addressTypeFromStr(addressRecord.address, network); + final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network); final privkey = generateECPrivate( hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, index: addressRecord.index, @@ -1501,7 +1504,7 @@ abstract class ElectrumWalletBase } final address = addressFromOutputScript(out.scriptPubKey, network); - final btcAddress = addressTypeFromStr(address, network); + final btcAddress = RegexUtils.addressTypeFromStr(address, network); outputs.add(BitcoinOutput(address: btcAddress, value: BigInt.from(out.amount.toInt()))); } @@ -1597,8 +1600,6 @@ abstract class ElectrumWalletBase Future getTransactionExpanded( {required String hash, int? height}) async { String transactionHex; - // TODO: time is not always available, and calculating it from height is not always accurate. - // Add settings to choose API provider and use and http server instead of electrum for this. int? time; int? confirmations; @@ -1606,6 +1607,29 @@ abstract class ElectrumWalletBase if (verboseTransaction.isEmpty) { transactionHex = await electrumClient.getTransactionHex(hash: hash); + + if (height != null && await checkIfMempoolAPIIsEnabled()) { + final blockHash = await http.get( + Uri.parse( + "http://mempool.cakewallet.com:8999/api/v1/block-height/$height", + ), + ); + + if (blockHash.statusCode == 200 && + blockHash.body.isNotEmpty && + jsonDecode(blockHash.body) != null) { + final blockResponse = await http.get( + Uri.parse( + "http://mempool.cakewallet.com:8999/api/v1/block/${blockHash.body}", + ), + ); + if (blockResponse.statusCode == 200 && + blockResponse.body.isNotEmpty && + jsonDecode(blockResponse.body)['timestamp'] != null) { + time = int.parse(jsonDecode(blockResponse.body)['timestamp'].toString()); + } + } + } } else { transactionHex = verboseTransaction['hex'] as String; time = verboseTransaction['time'] as int?; @@ -1860,7 +1884,7 @@ abstract class ElectrumWalletBase final balanceFutures = >>[]; for (var i = 0; i < addresses.length; i++) { final addressRecord = addresses[i]; - final sh = scriptHash(addressRecord.address, network: network); + final sh = addressRecord.getScriptHash(network); final balanceFuture = electrumClient.getBalance(sh); balanceFutures.add(balanceFuture); } @@ -1900,7 +1924,10 @@ abstract class ElectrumWalletBase } return ElectrumBalance( - confirmed: totalConfirmed, unconfirmed: totalUnconfirmed, frozen: totalFrozen); + confirmed: totalConfirmed, + unconfirmed: totalUnconfirmed, + frozen: totalFrozen, + ); } Future updateBalance() async { @@ -1968,7 +1995,7 @@ abstract class ElectrumWalletBase List possibleRecoverIds = [0, 1]; - final baseAddress = addressTypeFromStr(address, network); + final baseAddress = RegexUtils.addressTypeFromStr(address, network); for (int recoveryId in possibleRecoverIds) { final pubKey = sig.recoverPublicKey(messageHash, Curves.generatorSecp256k1, recoveryId); @@ -2061,7 +2088,8 @@ abstract class ElectrumWalletBase _isTryingToConnect = true; Timer(Duration(seconds: 5), () { - if (this.syncStatus is NotConnectedSyncStatus || this.syncStatus is LostConnectionSyncStatus) { + if (this.syncStatus is NotConnectedSyncStatus || + this.syncStatus is LostConnectionSyncStatus) { this.electrumClient.connectToUri( node!.uri, useSSL: node!.useSSL ?? false, @@ -2192,21 +2220,22 @@ Future startRefresh(ScanData scanData) async { BehaviorSubject? tweaksSubscription = null; - final syncingStatus = scanData.isSingleScan - ? SyncingSyncStatus(1, 0) - : SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, syncHeight); - - // Initial status UI update, send how many blocks left to scan - scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus)); - final electrumClient = scanData.electrumClient; await electrumClient.connectToUri( scanData.node?.uri ?? Uri.parse("tcp://electrs.cakewallet.com:50001"), useSSL: scanData.node?.useSSL ?? false, ); + int getCountPerRequest(int syncHeight) { + if (scanData.isSingleScan) { + return 1; + } + + final amountLeft = scanData.chainTip - syncHeight + 1; + return amountLeft; + } + if (tweaksSubscription == null) { - final count = scanData.isSingleScan ? 1 : TWEAKS_COUNT; final receiver = Receiver( scanData.silentAddress.b_scan.toHex(), scanData.silentAddress.B_spend.toHex(), @@ -2215,16 +2244,45 @@ Future startRefresh(ScanData scanData) async { scanData.labelIndexes.length, ); - tweaksSubscription = await electrumClient.tweaksSubscribe(height: syncHeight, count: count); - tweaksSubscription?.listen((t) async { - final tweaks = t as Map; + // Initial status UI update, send how many blocks in total to scan + final initialCount = getCountPerRequest(syncHeight); + scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight))); - if (tweaks["message"] != null) { + tweaksSubscription = await electrumClient.tweaksSubscribe( + height: syncHeight, + count: initialCount, + ); + + Future listenFn(t) async { + final tweaks = t as Map; + final msg = tweaks["message"]; + // success or error msg + final noData = msg != null; + + if (noData) { // re-subscribe to continue receiving messages, starting from the next unscanned height - electrumClient.tweaksSubscribe(height: syncHeight + 1, count: count); + final nextHeight = syncHeight + 1; + final nextCount = getCountPerRequest(nextHeight); + + if (nextCount > 0) { + tweaksSubscription?.close(); + + final nextTweaksSubscription = electrumClient.tweaksSubscribe( + height: nextHeight, + count: nextCount, + ); + nextTweaksSubscription?.listen(listenFn); + } + 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); @@ -2264,6 +2322,7 @@ Future startRefresh(ScanData scanData) async { : DateTime.now(), confirmations: scanData.chainTip - tweakHeight + 1, unspents: [], + isReceivedSilentPayment: true, ); addToWallet.forEach((label, value) { @@ -2318,16 +2377,6 @@ Future startRefresh(ScanData scanData) async { } catch (_) {} syncHeight = tweakHeight; - scanData.sendPort.send( - SyncResponse( - syncHeight, - SyncingSyncStatus.fromHeightValues( - scanData.chainTip, - initialSyncHeight, - syncHeight, - ), - ), - ); if (tweakHeight >= scanData.chainTip || scanData.isSingleScan) { if (tweakHeight >= scanData.chainTip) @@ -2343,7 +2392,9 @@ Future startRefresh(ScanData scanData) async { await tweaksSubscription!.close(); await electrumClient.close(); } - }); + } + + tweaksSubscription?.listen(listenFn); } if (tweaksSubscription == null) { @@ -2373,6 +2424,7 @@ class EstimatedTxResult { final int fee; final int amount; final bool spendsSilentPayment; + // final bool sendsToSilentPayment; final bool hasChange; final bool isSendAll; final String? memo; @@ -2386,31 +2438,6 @@ class PublicKeyWithDerivationPath { final String publicKey; } -BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network) { - if (network is BitcoinCashNetwork) { - if (!address.startsWith("bitcoincash:") && - (address.startsWith("q") || address.startsWith("p"))) { - address = "bitcoincash:$address"; - } - - return BitcoinCashAddress(address).baseAddress; - } - - 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 if (SilentPaymentAddress.regex.hasMatch(address)) { - return SilentPaymentAddress.fromAddress(address); - } else { - return P2wpkhAddress.fromAddress(address: address, network: network); - } -} - BitcoinAddressType _getScriptType(BitcoinBaseAddress type) { if (type is P2pkhAddress) { return P2pkhAddressType.p2pkh; diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index 12a43dbe6..2e4683ae6 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -301,7 +301,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { List possibleRecoverIds = [0, 1]; - final baseAddress = addressTypeFromStr(address, network); + final baseAddress = RegexUtils.addressTypeFromStr(address, network); for (int recoveryId in possibleRecoverIds) { final pubKey = sig.recoverPublicKey(messageHash, Curves.generatorSecp256k1, recoveryId); diff --git a/cw_bitcoin/lib/pending_bitcoin_transaction.dart b/cw_bitcoin/lib/pending_bitcoin_transaction.dart index 6a4cd1741..26ed3a4be 100644 --- a/cw_bitcoin/lib/pending_bitcoin_transaction.dart +++ b/cw_bitcoin/lib/pending_bitcoin_transaction.dart @@ -47,6 +47,19 @@ class PendingBitcoinTransaction with PendingTransaction { @override int? get outputCount => _tx.outputs.length; + List get outputs => _tx.outputs; + + bool get hasSilentPayment => _tx.hasSilentPayment; + + PendingChange? get change { + try { + final change = _tx.outputs.firstWhere((out) => out.isChange); + return PendingChange(change.scriptPubKey.toAddress(), BtcUtils.fromSatoshi(change.amount)); + } catch (_) { + return null; + } + } + final List _listeners; @override diff --git a/cw_bitcoin/lib/script_hash.dart b/cw_bitcoin/lib/script_hash.dart deleted file mode 100644 index 2130fcbbe..000000000 --- a/cw_bitcoin/lib/script_hash.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:crypto/crypto.dart'; -import 'package:cw_bitcoin/address_to_output_script.dart'; -import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin; - -String scriptHash(String address, {required bitcoin.BasedUtxoNetwork network}) { - final outputScript = addressToOutputScript(address, network); - final parts = sha256.convert(outputScript).toString().split(''); - var res = ''; - - for (var i = parts.length - 1; i >= 0; i--) { - final char = parts[i]; - i--; - final nextChar = parts[i]; - res += nextChar; - res += char; - } - - return res; -} diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 301b2aeff..a2478af3c 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -70,8 +70,8 @@ packages: dependency: "direct overridden" description: path: "." - ref: cake-update-v5 - resolved-ref: ff2b10eb27b0254ce4518d054332d97d77d9b380 + ref: cake-update-v7 + resolved-ref: bc49e3b1cba601828f8ddc3d016188d8c2499088 url: "https://github.com/cake-tech/bitcoin_base" source: git version: "4.7.0" diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index d085d98e3..d3fe2ee4e 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -57,7 +57,7 @@ dependency_overrides: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v5 + ref: cake-update-v7 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index 64bd38b1d..a3b113d9f 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -42,7 +42,7 @@ dependency_overrides: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v5 + ref: cake-update-v7 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart index 204f03d62..10a2aeab5 100644 --- a/cw_core/lib/get_height_by_date.dart +++ b/cw_core/lib/get_height_by_date.dart @@ -267,6 +267,16 @@ const bitcoinDates = { "2023-01": 769810, }; +Future getBitcoinHeightByDateAPI({required DateTime date}) async { + final response = await http.get( + Uri.parse( + "http://mempool.cakewallet.com:8999/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}", + ), + ); + + return jsonDecode(response.body)['height'] as int; +} + int getBitcoinHeightByDate({required DateTime date}) { String dateKey = '${date.year}-${date.month.toString().padLeft(2, '0')}'; final closestKey = bitcoinDates.keys @@ -377,4 +387,3 @@ int getWowneroHeightByDate({required DateTime date}) { return wowDates[closestKey] ?? 0; } - diff --git a/cw_core/lib/pending_transaction.dart b/cw_core/lib/pending_transaction.dart index 642db9c2c..0a6103a5f 100644 --- a/cw_core/lib/pending_transaction.dart +++ b/cw_core/lib/pending_transaction.dart @@ -1,3 +1,10 @@ +class PendingChange { + final String address; + final String amount; + + PendingChange(this.address, this.amount); +} + mixin PendingTransaction { String get id; String get amountFormatted; @@ -5,6 +12,7 @@ mixin PendingTransaction { String? feeRate; String get hex; int? get outputCount => null; + PendingChange? change; Future commit(); } diff --git a/cw_core/lib/sync_status.dart b/cw_core/lib/sync_status.dart index ea015340c..788309d8c 100644 --- a/cw_core/lib/sync_status.dart +++ b/cw_core/lib/sync_status.dart @@ -4,6 +4,9 @@ abstract class SyncStatus { } class StartingScanSyncStatus extends SyncStatus { + StartingScanSyncStatus(this.beginHeight); + + final int beginHeight; @override double progress() => 0.0; } @@ -59,6 +62,11 @@ class AttemptingSyncStatus extends SyncStatus { double progress() => 0.0; } +class AttemptingScanSyncStatus extends SyncStatus { + @override + double progress() => 0.0; +} + class FailedSyncStatus extends NotConnectedSyncStatus {} class ConnectingSyncStatus extends SyncStatus { diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock index ef9de14f9..e641024f7 100644 --- a/cw_nano/pubspec.lock +++ b/cw_nano/pubspec.lock @@ -117,10 +117,10 @@ packages: dependency: "direct overridden" description: name: build_runner_core - sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e" + sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" url: "https://pub.dev" source: hosted - version: "7.2.7+1" + version: "7.2.7" built_collection: dependency: transitive description: diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index c016c1f2a..2ca74822a 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -361,7 +361,7 @@ class CWBitcoin extends Bitcoin { continue; } - final sh = scriptHash(address, network: network); + final sh = BitcoinAddressUtils.scriptHash(address, network: network); final history = await electrumClient.getHistory(sh); final balance = await electrumClient.getBalance(sh); @@ -522,7 +522,20 @@ class CWBitcoin extends Bitcoin { } @override - int getHeightByDate({required DateTime date}) => getBitcoinHeightByDate(date: date); + Future checkIfMempoolAPIIsEnabled(Object wallet) async { + final bitcoinWallet = wallet as ElectrumWallet; + return await bitcoinWallet.checkIfMempoolAPIIsEnabled(); + } + + @override + Future getHeightByDate({required DateTime date, bool? bitcoinMempoolAPIEnabled}) async { + if (bitcoinMempoolAPIEnabled ?? false) { + try { + return await getBitcoinHeightByDateAPI(date: date); + } catch (_) {} + } + return await getBitcoinHeightByDate(date: date); + } @override Future rescan(Object wallet, {required int height, bool? doSingleScan}) async { @@ -547,4 +560,35 @@ class CWBitcoin extends Bitcoin { final bitcoinWallet = wallet as ElectrumWallet; await bitcoinWallet.updateFeeRates(); } + + @override + List updateOutputs(PendingTransaction pendingTransaction, List outputs) { + final pendingTx = pendingTransaction as PendingBitcoinTransaction; + + if (!pendingTx.hasSilentPayment) { + return outputs; + } + + final updatedOutputs = outputs.map((output) { + + try { + final pendingOut = pendingTx!.outputs[outputs.indexOf(output)]; + final updatedOutput = output; + + updatedOutput.stealthAddress = P2trAddress.fromScriptPubkey(script: pendingOut.scriptPubKey) + .toAddress(BitcoinNetwork.mainnet); + return updatedOutput; + } catch (_) {} + + return output; + }).toList(); + + return updatedOutputs; + } + + @override + bool txIsReceivedSilentPayment(TransactionInfo txInfo) { + final tx = txInfo as ElectrumTransactionInfo; + return tx.isReceivedSilentPayment; + } } diff --git a/lib/core/address_validator.dart b/lib/core/address_validator.dart index 92a735481..42e55d2b7 100644 --- a/lib/core/address_validator.dart +++ b/lib/core/address_validator.dart @@ -5,32 +5,40 @@ import 'package:cake_wallet/solana/solana.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/erc20_token.dart'; +const BEFORE_REGEX = '(^|\s)'; +const AFTER_REGEX = '(\$|\s)'; + class AddressValidator extends TextValidator { AddressValidator({required CryptoCurrency type}) : super( errorMessage: S.current.error_text_address, useAdditionalValidation: type == CryptoCurrency.btc - ? (String txt) => validateAddress(address: txt, network: BitcoinNetwork.mainnet) + ? (String txt) => BitcoinAddressUtils.validateAddress( + address: txt, + network: BitcoinNetwork.mainnet, + ) : null, pattern: getPattern(type), length: getLength(type)); static String getPattern(CryptoCurrency type) { + var pattern = ""; if (type is Erc20Token) { - return '0x[0-9a-zA-Z]'; + pattern = '0x[0-9a-zA-Z]'; } switch (type) { case CryptoCurrency.xmr: - return '^4[0-9a-zA-Z]{94}\$|^8[0-9a-zA-Z]{94}\$|^[0-9a-zA-Z]{106}\$'; + pattern = '4[0-9a-zA-Z]{94}|8[0-9a-zA-Z]{94}|[0-9a-zA-Z]{106}'; case CryptoCurrency.ada: - return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$' - '|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$'; + pattern = '[0-9a-zA-Z]{59}|[0-9a-zA-Z]{92}|[0-9a-zA-Z]{104}' + '|[0-9a-zA-Z]{105}|addr1[0-9a-zA-Z]{98}'; case CryptoCurrency.btc: - return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$|^${SilentPaymentAddress.regex.pattern}\$'; + pattern = + '${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}'; case CryptoCurrency.nano: - return '[0-9a-zA-Z_]'; + pattern = '[0-9a-zA-Z_]'; case CryptoCurrency.banano: - return '[0-9a-zA-Z_]'; + pattern = '[0-9a-zA-Z_]'; case CryptoCurrency.usdc: case CryptoCurrency.usdcpoly: case CryptoCurrency.usdtPoly: @@ -66,11 +74,11 @@ class AddressValidator extends TextValidator { case CryptoCurrency.dydx: case CryptoCurrency.steth: case CryptoCurrency.shib: - return '0x[0-9a-zA-Z]'; + pattern = '0x[0-9a-zA-Z]'; case CryptoCurrency.xrp: - return '^[0-9a-zA-Z]{34}\$|^X[0-9a-zA-Z]{46}\$'; + pattern = '[0-9a-zA-Z]{34}|X[0-9a-zA-Z]{46}'; case CryptoCurrency.xhv: - return '^hvx|hvi|hvs[0-9a-zA-Z]'; + pattern = 'hvx|hvi|hvs[0-9a-zA-Z]'; case CryptoCurrency.xag: case CryptoCurrency.xau: case CryptoCurrency.xaud: @@ -92,40 +100,43 @@ class AddressValidator extends TextValidator { case CryptoCurrency.dash: case CryptoCurrency.eos: case CryptoCurrency.wow: - return '[0-9a-zA-Z]'; + pattern = '[0-9a-zA-Z]'; case CryptoCurrency.bch: - return '^(?!bitcoincash:)[0-9a-zA-Z]*\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{41}\$|^(?!bitcoincash:)q|p[0-9a-zA-Z]{42}\$|^bitcoincash:q|p[0-9a-zA-Z]{41}\$|^bitcoincash:q|p[0-9a-zA-Z]{42}\$'; + pattern = + '(?!bitcoincash:)[0-9a-zA-Z]*|(?!bitcoincash:)q|p[0-9a-zA-Z]{41}|(?!bitcoincash:)q|p[0-9a-zA-Z]{42}|bitcoincash:q|p[0-9a-zA-Z]{41}|bitcoincash:q|p[0-9a-zA-Z]{42}'; case CryptoCurrency.bnb: - return '[0-9a-zA-Z]'; + pattern = '[0-9a-zA-Z]'; case CryptoCurrency.ltc: - return '^(?!(ltc|LTC)1)[0-9a-zA-Z]*\$|(^LTC1[A-Z0-9]*\$)|(^ltc1[a-z0-9]*\$)'; + pattern = '(?!(ltc|LTC)1)[0-9a-zA-Z]*|(LTC1[A-Z0-9]*)|(ltc1[a-z0-9]*)'; case CryptoCurrency.hbar: - return '[0-9a-zA-Z.]'; + pattern = '[0-9a-zA-Z.]'; case CryptoCurrency.zaddr: - return '^zs[0-9a-zA-Z]{75}'; + pattern = 'zs[0-9a-zA-Z]{75}'; case CryptoCurrency.zec: - return '^t1[0-9a-zA-Z]{33}\$|^t3[0-9a-zA-Z]{33}\$'; + pattern = 't1[0-9a-zA-Z]{33}|t3[0-9a-zA-Z]{33}'; case CryptoCurrency.dcr: - return 'D[ksecS]([0-9a-zA-Z])+'; + pattern = 'D[ksecS]([0-9a-zA-Z])+'; case CryptoCurrency.rvn: - return '[Rr]([1-9a-km-zA-HJ-NP-Z]){33}'; + pattern = '[Rr]([1-9a-km-zA-HJ-NP-Z]){33}'; case CryptoCurrency.near: - return '[0-9a-f]{64}'; + pattern = '[0-9a-f]{64}'; case CryptoCurrency.rune: - return 'thor1[0-9a-z]{38}'; + pattern = 'thor1[0-9a-z]{38}'; case CryptoCurrency.scrt: - return 'secret1[0-9a-z]{38}'; + pattern = 'secret1[0-9a-z]{38}'; case CryptoCurrency.stx: - return 'S[MP][0-9a-zA-Z]+'; + pattern = 'S[MP][0-9a-zA-Z]+'; case CryptoCurrency.kmd: - return 'R[0-9a-zA-Z]{33}'; + pattern = 'R[0-9a-zA-Z]{33}'; case CryptoCurrency.pivx: - return 'D([1-9a-km-zA-HJ-NP-Z]){33}'; + pattern = 'D([1-9a-km-zA-HJ-NP-Z]){33}'; case CryptoCurrency.btcln: - return '^(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)'; + pattern = '(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)'; default: - return '[0-9a-zA-Z]'; + pattern = '[0-9a-zA-Z]'; } + + return '$BEFORE_REGEX$pattern$AFTER_REGEX'; } static List? getLength(CryptoCurrency type) { @@ -266,56 +277,54 @@ class AddressValidator extends TextValidator { } static String? getAddressFromStringPattern(CryptoCurrency type) { + String? pattern = null; + switch (type) { case CryptoCurrency.xmr: case CryptoCurrency.wow: - return '([^0-9a-zA-Z]|^)4[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)' - '|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)' - '|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)'; + pattern = '4[0-9a-zA-Z]{94}' + '|8[0-9a-zA-Z]{94}' + '|[0-9a-zA-Z]{106}'; case CryptoCurrency.btc: - return '([^0-9a-zA-Z]|^)([1mn][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2pkhAddress type - '|([^0-9a-zA-Z]|^)([23][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2shAddress type - '|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{25,39})([^0-9a-zA-Z]|\$)' //P2wpkhAddress type - '|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type - '|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)' //P2trAddress type - '|${SilentPaymentAddress.regex.pattern}\$'; - + pattern = + '${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}'; case CryptoCurrency.ltc: - return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)' - '|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)' - '|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)'; + pattern = '^L[a-zA-Z0-9]{26,33}' + '|[LM][a-km-zA-HJ-NP-Z1-9]{26,33}' + '|ltc[a-zA-Z0-9]{26,45}'; case CryptoCurrency.eth: - return '0x[0-9a-zA-Z]{42}'; + pattern = '0x[0-9a-zA-Z]{42}'; case CryptoCurrency.maticpoly: - return '0x[0-9a-zA-Z]{42}'; + pattern = '0x[0-9a-zA-Z]{42}'; case CryptoCurrency.nano: - return 'nano_[0-9a-zA-Z]{60}'; + pattern = 'nano_[0-9a-zA-Z]{60}'; case CryptoCurrency.banano: - return 'ban_[0-9a-zA-Z]{60}'; + pattern = 'ban_[0-9a-zA-Z]{60}'; case CryptoCurrency.bch: - return 'bitcoincash:q[0-9a-zA-Z]{41}([^0-9a-zA-Z]|\$)' - '|bitcoincash:q[0-9a-zA-Z]{42}([^0-9a-zA-Z]|\$)' - '|([^0-9a-zA-Z]|^)q[0-9a-zA-Z]{41}([^0-9a-zA-Z]|\$)' - '|([^0-9a-zA-Z]|^)q[0-9a-zA-Z]{42}([^0-9a-zA-Z]|\$)'; + pattern = '(bitcoincash:)?q[0-9a-zA-Z]{41,42}'; case CryptoCurrency.sol: - return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)'; + pattern = '[1-9A-HJ-NP-Za-km-z]{43,44}'; case CryptoCurrency.trx: - return '(T|t)[1-9A-HJ-NP-Za-km-z]{33}'; + pattern = '(T|t)[1-9A-HJ-NP-Za-km-z]{33}'; default: if (type.tag == CryptoCurrency.eth.title) { - return '0x[0-9a-zA-Z]{42}'; + pattern = '0x[0-9a-zA-Z]{42}'; } if (type.tag == CryptoCurrency.maticpoly.tag) { - return '0x[0-9a-zA-Z]{42}'; + pattern = '0x[0-9a-zA-Z]{42}'; } if (type.tag == CryptoCurrency.sol.title) { - return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)'; + pattern = '[1-9A-HJ-NP-Za-km-z]{43,44}'; } if (type.tag == CryptoCurrency.trx.title) { - return '(T|t)[1-9A-HJ-NP-Za-km-z]{33}'; + pattern = '(T|t)[1-9A-HJ-NP-Za-km-z]{33}'; } - - return null; } + + if (pattern != null) { + return "$BEFORE_REGEX$pattern$AFTER_REGEX"; + } + + return null; } } diff --git a/lib/core/sync_status_title.dart b/lib/core/sync_status_title.dart index 465211f23..4582f7b1f 100644 --- a/lib/core/sync_status_title.dart +++ b/lib/core/sync_status_title.dart @@ -53,7 +53,11 @@ String syncStatusTitle(SyncStatus syncStatus) { } if (syncStatus is StartingScanSyncStatus) { - return S.current.sync_status_starting_scan; + return S.current.sync_status_starting_scan(syncStatus.beginHeight.toString()); + } + + if (syncStatus is AttemptingScanSyncStatus) { + return S.current.sync_status_attempting_scan; } return ''; diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index c95ce9847..481db5620 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -51,7 +51,7 @@ class AddressResolver { throw Exception('Unexpected token: $type for getAddressFromStringPattern'); } - final match = RegExp(addressPattern).firstMatch(raw); + final match = RegExp(addressPattern, multiLine: true).firstMatch(raw); return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_|ban_'), (Match match) { String group = match.group(0)!; @@ -213,8 +213,7 @@ class AddressResolver { await NostrProfileHandler.processRelays(context, nostrProfile!, text); if (nostrUserData != null) { - String? addressFromBio = extractAddressByType( - raw: nostrUserData.about, type: currency); + String? addressFromBio = extractAddressByType(raw: nostrUserData.about, type: currency); if (addressFromBio != null) { return ParsedAddress.nostrAddress( address: addressFromBio, diff --git a/lib/src/screens/dashboard/pages/transactions_page.dart b/lib/src/screens/dashboard/pages/transactions_page.dart index 7c0e9cad4..a9a1213ce 100644 --- a/lib/src/screens/dashboard/pages/transactions_page.dart +++ b/lib/src/screens/dashboard/pages/transactions_page.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/anonpay_transaction_row.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/order_row.dart'; import 'package:cake_wallet/themes/extensions/placeholder_theme.dart'; @@ -52,7 +53,7 @@ class TransactionsPage extends StatelessWidget { try { final uri = Uri.parse( "https://guides.cakewallet.com/docs/FAQ/why_are_my_funds_not_appearing/"); - launchUrl(uri, mode: LaunchMode.externalApplication); + launchUrl(uri, mode: LaunchMode.externalApplication); } catch (_) {} }, title: S.of(context).syncing_wallet_alert_title, @@ -84,7 +85,7 @@ class TransactionsPage extends StatelessWidget { final transaction = item.transaction; final transactionType = dashboardViewModel.type == WalletType.ethereum && - transaction.evmSignatureName == 'approval' + transaction.evmSignatureName == 'approval' ? ' (${transaction.evmSignatureName})' : ''; @@ -100,8 +101,11 @@ class TransactionsPage extends StatelessWidget { ? '' : item.formattedFiatAmount, isPending: transaction.isPending, - title: item.formattedTitle + - item.formattedStatus + ' $transactionType', + title: + item.formattedTitle + item.formattedStatus + ' $transactionType', + isReceivedSilentPayment: + dashboardViewModel.type == WalletType.bitcoin && + bitcoin!.txIsReceivedSilentPayment(transaction), ), ); } diff --git a/lib/src/screens/dashboard/widgets/transaction_raw.dart b/lib/src/screens/dashboard/widgets/transaction_raw.dart index 3a95b9f2e..88866fa25 100644 --- a/lib/src/screens/dashboard/widgets/transaction_raw.dart +++ b/lib/src/screens/dashboard/widgets/transaction_raw.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:flutter/material.dart'; import 'package:cw_core/transaction_direction.dart'; @@ -5,14 +6,16 @@ import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; class TransactionRow extends StatelessWidget { - TransactionRow( - {required this.direction, - required this.formattedDate, - required this.formattedAmount, - required this.formattedFiatAmount, - required this.isPending, - required this.title, - required this.onTap}); + TransactionRow({ + required this.direction, + required this.formattedDate, + required this.formattedAmount, + required this.formattedFiatAmount, + required this.isPending, + required this.isReceivedSilentPayment, + required this.title, + required this.onTap, + }); final VoidCallback onTap; final TransactionDirection direction; @@ -20,6 +23,7 @@ class TransactionRow extends StatelessWidget { final String formattedAmount; final String formattedFiatAmount; final bool isPending; + final bool isReceivedSilentPayment; final String title; @override @@ -38,50 +42,80 @@ class TransactionRow extends StatelessWidget { width: 36, decoration: BoxDecoration( shape: BoxShape.circle, - color: Theme.of(context).extension()!.rowsColor - ), - child: Image.asset( - direction == TransactionDirection.incoming - ? 'assets/images/down_arrow.png' - : 'assets/images/up_arrow.png'), + color: Theme.of(context).extension()!.rowsColor), + child: Image.asset(direction == TransactionDirection.incoming + ? 'assets/images/down_arrow.png' + : 'assets/images/up_arrow.png'), ), SizedBox(width: 12), Expanded( child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(title, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Theme.of(context).extension()!.textColor)), - Text(formattedAmount, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Theme.of(context).extension()!.textColor)) - ]), - SizedBox(height: 5), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(formattedDate, - style: TextStyle( - fontSize: 14, - color: Theme.of(context).extension()!.dateSectionRowColor)), - Text(formattedFiatAmount, - style: TextStyle( - fontSize: 14, - color: Theme.of(context).extension()!.dateSectionRowColor)) - ]) - ], - ) - ) + mainAxisSize: MainAxisSize.min, + children: [ + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Row( + children: [ + Text(title, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.textColor, + )), + if (isReceivedSilentPayment) TxTag(tag: S.of(context).silent_payment), + ], + ), + Text(formattedAmount, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.textColor)) + ]), + SizedBox(height: 5), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text(formattedDate, + style: TextStyle( + fontSize: 14, + color: + Theme.of(context).extension()!.dateSectionRowColor)), + Text(formattedFiatAmount, + style: TextStyle( + fontSize: 14, + color: + Theme.of(context).extension()!.dateSectionRowColor)) + ]) + ], + )) ], ), )); } } + +// A tag to add context to a transaction +// example use: differ silent payments from regular txs +class TxTag extends StatelessWidget { + TxTag({required this.tag}); + + final String tag; + + @override + Widget build(BuildContext context) { + return Container( + height: 17, + padding: EdgeInsets.only(left: 6, right: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.5)), + color: Theme.of(context).extension()!.rowsColor, + ), + alignment: Alignment.center, + child: Text( + tag.toLowerCase(), + style: TextStyle( + color: Theme.of(context).extension()!.textColor, + fontSize: 9, + fontWeight: FontWeight.w600, + ), + ), + ); + } +} diff --git a/lib/src/screens/rescan/rescan_page.dart b/lib/src/screens/rescan/rescan_page.dart index b66c94878..58e7a44f6 100644 --- a/lib/src/screens/rescan/rescan_page.dart +++ b/lib/src/screens/rescan/rescan_page.dart @@ -37,6 +37,7 @@ class RescanPage extends BasePage { toggleSingleScan: () => _rescanViewModel.doSingleScan = !_rescanViewModel.doSingleScan, walletType: _rescanViewModel.wallet.type, + bitcoinMempoolAPIEnabled: _rescanViewModel.isBitcoinMempoolAPIEnabled, )), Observer( builder: (_) => LoadingPrimaryButton( diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index be2e6cb02..3e906048d 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -68,11 +68,11 @@ class SendPage extends BasePage { @override Function(BuildContext)? get pushToNextWidget => (context) { - FocusScopeNode currentFocus = FocusScope.of(context); - if (!currentFocus.hasPrimaryFocus) { - currentFocus.focusedChild?.unfocus(); - } - }; + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.focusedChild?.unfocus(); + } + }; @override Widget? leading(BuildContext context) { @@ -212,26 +212,25 @@ class SendPage extends BasePage { final count = sendViewModel.outputs.length; return count > 1 - ? Semantics ( - label: 'Page Indicator', - hint: 'Swipe to change receiver', - excludeSemantics: true, - child: - SmoothPageIndicator( - controller: controller, - count: count, - effect: ScrollingDotsEffect( - spacing: 6.0, - radius: 6.0, - dotWidth: 6.0, - dotHeight: 6.0, - dotColor: Theme.of(context) - .extension()! - .indicatorDotColor, - activeDotColor: Theme.of(context) - .extension()! - .templateBackgroundColor), - )) + ? Semantics( + label: 'Page Indicator', + hint: 'Swipe to change receiver', + excludeSemantics: true, + child: SmoothPageIndicator( + controller: controller, + count: count, + effect: ScrollingDotsEffect( + spacing: 6.0, + radius: 6.0, + dotWidth: 6.0, + dotHeight: 6.0, + dotColor: Theme.of(context) + .extension()! + .indicatorDotColor, + activeDotColor: Theme.of(context) + .extension()! + .templateBackgroundColor), + )) : Offstage(); }, ), @@ -478,6 +477,7 @@ class SendPage extends BasePage { feeValue: sendViewModel.pendingTransaction!.feeFormatted, feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted, outputs: sendViewModel.outputs, + change: sendViewModel.pendingTransaction!.change, rightButtonText: S.of(_dialogContext).send, leftButtonText: S.of(_dialogContext).cancel, actionRightButton: () async { diff --git a/lib/src/screens/send/widgets/confirm_sending_alert.dart b/lib/src/screens/send/widgets/confirm_sending_alert.dart index 3af1c3f8c..c7b6d3407 100644 --- a/lib/src/screens/send/widgets/confirm_sending_alert.dart +++ b/lib/src/screens/send/widgets/confirm_sending_alert.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/view_model/send/output.dart'; +import 'package:cw_core/pending_transaction.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -21,6 +22,7 @@ class ConfirmSendingAlert extends BaseAlertDialog { required this.feeValue, required this.feeFiatAmount, required this.outputs, + this.change, required this.leftButtonText, required this.rightButtonText, required this.actionLeftButton, @@ -44,6 +46,7 @@ class ConfirmSendingAlert extends BaseAlertDialog { final String feeValue; final String feeFiatAmount; final List outputs; + final PendingChange? change; final String leftButtonText; final String rightButtonText; final VoidCallback actionLeftButton; @@ -101,6 +104,7 @@ class ConfirmSendingAlert extends BaseAlertDialog { feeValue: feeValue, feeFiatAmount: feeFiatAmount, outputs: outputs, + change: change, onDispose: onDispose); } @@ -117,6 +121,7 @@ class ConfirmSendingAlertContent extends StatefulWidget { required this.feeValue, required this.feeFiatAmount, required this.outputs, + this.change, required this.onDispose}) {} final String? paymentId; @@ -130,6 +135,7 @@ class ConfirmSendingAlertContent extends StatefulWidget { final String feeValue; final String feeFiatAmount; final List outputs; + final PendingChange? change; final Function? onDispose; @override @@ -145,6 +151,7 @@ class ConfirmSendingAlertContent extends StatefulWidget { feeValue: feeValue, feeFiatAmount: feeFiatAmount, outputs: outputs, + change: change, onDispose: onDispose); } @@ -161,6 +168,7 @@ class ConfirmSendingAlertContentState extends State required this.feeValue, required this.feeFiatAmount, required this.outputs, + this.change, this.onDispose}) : recipientTitle = '' { recipientTitle = outputs.length > 1 @@ -179,6 +187,7 @@ class ConfirmSendingAlertContentState extends State final String feeValue; final String feeFiatAmount; final List outputs; + final PendingChange? change; final Function? onDispose; final double backgroundHeight = 160; @@ -391,100 +400,57 @@ class ConfirmSendingAlertContentState extends State decoration: TextDecoration.none, ), ), - outputs.length > 1 - ? ListView.builder( - padding: EdgeInsets.only(top: 0), - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: outputs.length, - itemBuilder: (context, index) { - final item = outputs[index]; - final _address = - item.isParsedAddress ? item.extractedAddress : item.address; - final _amount = item.cryptoAmount.replaceAll(',', '.'); + ListView.builder( + padding: EdgeInsets.only(top: 0), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: outputs.length, + itemBuilder: (context, index) { + final item = outputs[index]; + final _address = + item.isParsedAddress ? item.extractedAddress : item.address; + final _amount = item.cryptoAmount.replaceAll(',', '.'); - return Column( - children: [ - if (item.isParsedAddress) - Padding( - padding: EdgeInsets.only(top: 8), - child: Text( - item.parsedAddress.name, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none, - ), - )), - Padding( - padding: EdgeInsets.only(top: 8), - child: Text( - _address, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none, - ), - )), - Padding( - padding: EdgeInsets.only(top: 8), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - _amount, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none, - ), - ) - ], - )) - ], - ); - }) - : Column(children: [ - if (outputs.first.isParsedAddress) - Padding( - padding: EdgeInsets.only(top: 8), - child: Text( - outputs.first.parsedAddress.name, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none, - ), - )), - Padding( - padding: EdgeInsets.only(top: 8), - child: Text( - outputs.first.isParsedAddress - ? outputs.first.extractedAddress - : outputs.first.address, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: PaletteDark.pigeonBlue, - decoration: TextDecoration.none, - ), - )), - ]) + return Column( + children: [ + if (item.isParsedAddress) + AddressText(text: item.parsedAddress.name), + AddressText(text: _address, fontSize: 10), + if (stealthAddressText(item.stealthAddress) != null) + AddressText( + text: stealthAddressText(item.stealthAddress)!, fontSize: 10), + AmountText(text: _amount), + ], + ); + }, + ) ], ), - ) + ), + if (change != null) + Padding( + padding: EdgeInsets.only(top: 16), + child: Column( + children: [ + Text( + S.of(context).send_change_to_you, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ), + Column( + children: [ + AddressText(text: change!.address, fontSize: 10), + AmountText(text: change!.amount), + ], + ) + ], + ), + ) ], ))), if (showScrollbar) @@ -539,3 +505,78 @@ class ExpirationTimeWidget extends StatelessWidget { ); } } + +class AddressText extends StatelessWidget { + final String text; + final double fontSize; + final FontWeight fontWeight; + final TextAlign? textAlign; + + const AddressText({ + required this.text, + this.fontSize = 14, + this.fontWeight = FontWeight.w600, + this.textAlign, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: 8), + child: Text( + text, + style: TextStyle( + fontSize: fontSize, + fontWeight: fontWeight, + fontFamily: 'Lato', + color: PaletteDark.pigeonBlue, + decoration: TextDecoration.none, + ), + ), + ); + } +} + +class AmountText extends StatelessWidget { + final String text; + final double fontSize; + final FontWeight fontWeight; + final TextAlign? textAlign; + + const AmountText({ + required this.text, + this.fontSize = 10, + this.fontWeight = FontWeight.w600, + this.textAlign, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: 8), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + text, + style: TextStyle( + fontSize: fontSize, + fontWeight: fontWeight, + fontFamily: 'Lato', + color: PaletteDark.pigeonBlue, + decoration: TextDecoration.none, + ), + ) + ], + )); + } +} + +String? stealthAddressText(String? stealthAddress) { + if (stealthAddress == null) { + return null; + } + + return stealthAddress.isNotEmpty ? "-> $stealthAddress" : null; +} diff --git a/lib/src/screens/settings/privacy_page.dart b/lib/src/screens/settings/privacy_page.dart index 7db244460..53e7686e8 100644 --- a/lib/src/screens/settings/privacy_page.dart +++ b/lib/src/screens/settings/privacy_page.dart @@ -58,8 +58,8 @@ class PrivacyPage extends BasePage { if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible) SettingsSwitcherCell( title: _privacySettingsViewModel.isMoneroWallet - ? S.current.auto_generate_subaddresses - : S.current.auto_generate_addresses, + ? S.current.auto_generate_subaddresses + : S.current.auto_generate_addresses, value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled, onValueChange: (BuildContext _, bool value) { _privacySettingsViewModel.setAutoGenerateSubaddresses(value); @@ -115,21 +115,21 @@ class PrivacyPage extends BasePage { ), if (_privacySettingsViewModel.canUseMempoolFeeAPI) SettingsSwitcherCell( - title: S.current.live_fee_rates, + title: S.current.enable_mempool_api, value: _privacySettingsViewModel.useMempoolFeeAPI, onValueChange: (BuildContext _, bool isEnabled) async { if (!isEnabled) { final bool confirmation = await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context).warning, - alertContent: S.of(context).disable_fee_api_warning, - rightButtonText: S.of(context).confirm, - leftButtonText: S.of(context).cancel, - actionRightButton: () => Navigator.of(context).pop(true), - actionLeftButton: () => Navigator.of(context).pop(false)); - }) ?? + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).warning, + alertContent: S.of(context).disable_fee_api_warning, + rightButtonText: S.of(context).confirm, + leftButtonText: S.of(context).cancel, + actionRightButton: () => Navigator.of(context).pop(true), + actionLeftButton: () => Navigator.of(context).pop(false)); + }) ?? false; if (confirmation) { _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled); diff --git a/lib/src/widgets/blockchain_height_widget.dart b/lib/src/widgets/blockchain_height_widget.dart index e0f83a4f4..40e191438 100644 --- a/lib/src/widgets/blockchain_height_widget.dart +++ b/lib/src/widgets/blockchain_height_widget.dart @@ -20,6 +20,7 @@ class BlockchainHeightWidget extends StatefulWidget { this.isSilentPaymentsScan = false, this.toggleSingleScan, this.doSingleScan = false, + this.bitcoinMempoolAPIEnabled, required this.walletType, }) : super(key: key); @@ -29,6 +30,7 @@ class BlockchainHeightWidget extends StatefulWidget { final bool hasDatePicker; final bool isSilentPaymentsScan; final bool doSingleScan; + final Future? bitcoinMempoolAPIEnabled; final Function()? toggleSingleScan; final WalletType walletType; @@ -79,7 +81,8 @@ class BlockchainHeightState extends State { child: BaseTextFormField( focusNode: widget.focusNode, controller: restoreHeightController, - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false), + keyboardType: + TextInputType.numberWithOptions(signed: false, decimal: false), hintText: widget.isSilentPaymentsScan ? S.of(context).silent_payments_scan_from_height : S.of(context).widgets_restore_from_blockheight, @@ -146,7 +149,9 @@ class BlockchainHeightState extends State { : S.of(context).restore_from_date_or_blockheight, textAlign: TextAlign.center, style: TextStyle( - fontSize: 12, fontWeight: FontWeight.normal, color: Theme.of(context).hintColor), + fontSize: 12, + fontWeight: FontWeight.normal, + color: Theme.of(context).hintColor), ), ) ] @@ -166,7 +171,10 @@ class BlockchainHeightState extends State { if (date != null) { int height; if (widget.isSilentPaymentsScan) { - height = bitcoin!.getHeightByDate(date: date); + height = await bitcoin!.getHeightByDate( + date: date, + bitcoinMempoolAPIEnabled: await widget.bitcoinMempoolAPIEnabled, + ); } else { if (widget.walletType == WalletType.monero) { height = monero!.getHeightByDate(date: date); diff --git a/lib/store/dashboard/transaction_filter_store.dart b/lib/store/dashboard/transaction_filter_store.dart index af0dcce87..fb9ee14cd 100644 --- a/lib/store/dashboard/transaction_filter_store.dart +++ b/lib/store/dashboard/transaction_filter_store.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/view_model/dashboard/action_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart'; import 'package:mobx/mobx.dart'; @@ -6,12 +7,13 @@ import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart'; part 'transaction_filter_store.g.dart'; -class TransactionFilterStore = TransactionFilterStoreBase - with _$TransactionFilterStore; +class TransactionFilterStore = TransactionFilterStoreBase with _$TransactionFilterStore; abstract class TransactionFilterStoreBase with Store { - TransactionFilterStoreBase() : displayIncoming = true, - displayOutgoing = true; + TransactionFilterStoreBase() + : displayIncoming = true, + displayOutgoing = true, + displaySilentPayments = true; @observable bool displayIncoming; @@ -19,6 +21,9 @@ abstract class TransactionFilterStoreBase with Store { @observable bool displayOutgoing; + @observable + bool displaySilentPayments; + @observable DateTime? startDate; @@ -26,31 +31,36 @@ abstract class TransactionFilterStoreBase with Store { DateTime? endDate; @computed - bool get displayAll => displayIncoming && displayOutgoing; + bool get displayAll => displayIncoming && displayOutgoing && displaySilentPayments; @action void toggleAll() { if (displayAll) { displayOutgoing = false; displayIncoming = false; + displaySilentPayments = false; } else { displayOutgoing = true; displayIncoming = true; + displaySilentPayments = true; } } - @action void toggleIncoming() { displayIncoming = !displayIncoming; } - @action void toggleOutgoing() { displayOutgoing = !displayOutgoing; } + @action + void toggleSilentPayments() { + displaySilentPayments = !displaySilentPayments; + } + @action void changeStartDate(DateTime date) => startDate = date; @@ -59,34 +69,33 @@ abstract class TransactionFilterStoreBase with Store { List filtered({required List transactions}) { var _transactions = []; - final needToFilter = !displayAll || - (startDate != null && endDate != null); + final needToFilter = !displayAll || (startDate != null && endDate != null); if (needToFilter) { _transactions = transactions.where((item) { var allowed = true; if (allowed && startDate != null && endDate != null) { - if(item is TransactionListItem){ - allowed = (startDate?.isBefore(item.transaction.date) ?? false) - && (endDate?.isAfter(item.transaction.date) ?? false); - }else if(item is AnonpayTransactionListItem){ - allowed = (startDate?.isBefore(item.transaction.createdAt) ?? false) - && (endDate?.isAfter(item.transaction.createdAt) ?? false); - } + if (item is TransactionListItem) { + allowed = (startDate?.isBefore(item.transaction.date) ?? false) && + (endDate?.isAfter(item.transaction.date) ?? false); + } else if (item is AnonpayTransactionListItem) { + allowed = (startDate?.isBefore(item.transaction.createdAt) ?? false) && + (endDate?.isAfter(item.transaction.createdAt) ?? false); + } } if (allowed && (!displayAll)) { - if(item is TransactionListItem){ - allowed = (displayOutgoing && - item.transaction.direction == - TransactionDirection.outgoing) || - (displayIncoming && - item.transaction.direction == TransactionDirection.incoming); - } else if(item is AnonpayTransactionListItem){ + if (item is TransactionListItem) { + allowed = + (displayOutgoing && item.transaction.direction == TransactionDirection.outgoing) || + (displayIncoming && + item.transaction.direction == TransactionDirection.incoming && + !bitcoin!.txIsReceivedSilentPayment(item.transaction)) || + (displaySilentPayments && bitcoin!.txIsReceivedSilentPayment(item.transaction)); + } else if (item is AnonpayTransactionListItem) { allowed = displayIncoming; } - } return allowed; @@ -97,4 +106,4 @@ abstract class TransactionFilterStoreBase with Store { return _transactions; } -} \ No newline at end of file +} diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index d69d662e1..9aeb3a46b 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -88,6 +88,11 @@ abstract class DashboardViewModelBase with Store { value: () => transactionFilterStore.displayOutgoing, caption: S.current.outgoing, onChanged: transactionFilterStore.toggleOutgoing), + FilterItem( + value: () => transactionFilterStore.displaySilentPayments, + caption: S.current.silent_payments, + onChanged: transactionFilterStore.toggleSilentPayments, + ), // FilterItem( // value: () => false, // caption: S.current.transactions_by_date, @@ -376,12 +381,15 @@ abstract class DashboardViewModelBase with Store { // to not cause work duplication, this will do the job as well, it will be slightly less precise // about what happened - but still enough. // if (keys['privateSpendKey'] == List.generate(64, (index) => "0").join("")) "Private spend key is 0", - if (keys['privateViewKey'] == List.generate(64, (index) => "0").join("")) "private view key is 0", + if (keys['privateViewKey'] == List.generate(64, (index) => "0").join("")) + "private view key is 0", // if (keys['publicSpendKey'] == List.generate(64, (index) => "0").join("")) "public spend key is 0", - if (keys['publicViewKey'] == List.generate(64, (index) => "0").join("")) "public view key is 0", + if (keys['publicViewKey'] == List.generate(64, (index) => "0").join("")) + "public view key is 0", // if (wallet.seed == null) "wallet seed is null", // if (wallet.seed == "") "wallet seed is empty", - if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address == "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4") + if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address == + "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4") "primary address is invalid, you won't be able to receive / spend funds", ]; return errors; diff --git a/lib/view_model/rescan_view_model.dart b/lib/view_model/rescan_view_model.dart index dcc81c0a0..00eed5633 100644 --- a/lib/view_model/rescan_view_model.dart +++ b/lib/view_model/rescan_view_model.dart @@ -29,6 +29,10 @@ abstract class RescanViewModelBase with Store { @computed bool get isSilentPaymentsScan => wallet.type == WalletType.bitcoin; + @computed + Future get isBitcoinMempoolAPIEnabled async => + wallet.type == WalletType.bitcoin && await bitcoin!.checkIfMempoolAPIIsEnabled(wallet); + @action Future rescanCurrentWallet({required int restoreHeight}) async { state = RescanWalletState.rescaning; diff --git a/lib/view_model/send/output.dart b/lib/view_model/send/output.dart index 94854df31..e53127e0c 100644 --- a/lib/view_model/send/output.dart +++ b/lib/view_model/send/output.dart @@ -79,6 +79,9 @@ abstract class OutputBase with Store { bool get isParsedAddress => parsedAddress.parseFrom != ParseFrom.notParsed && parsedAddress.name.isNotEmpty; + @observable + String? stealthAddress; + @computed int get formattedCryptoAmount { int amount = 0; @@ -134,9 +137,8 @@ abstract class OutputBase with Store { final trc20EstimatedFee = tron!.getTronTRC20EstimatedFee(_wallet) ?? 0; return double.parse(trc20EstimatedFee.toString()); } - } - + if (_wallet.type == WalletType.solana) { return solana!.getEstimateFees(_wallet) ?? 0.0; } @@ -145,16 +147,16 @@ abstract class OutputBase with Store { _settingsStore.priority[_wallet.type]!, formattedCryptoAmount); if (_wallet.type == WalletType.bitcoin) { - if (_settingsStore.priority[_wallet.type] == bitcoin!.getBitcoinTransactionPriorityCustom()) { - fee = bitcoin!.getEstimatedFeeWithFeeRate(_wallet, - _settingsStore.customBitcoinFeeRate,formattedCryptoAmount); + if (_settingsStore.priority[_wallet.type] == + bitcoin!.getBitcoinTransactionPriorityCustom()) { + fee = bitcoin!.getEstimatedFeeWithFeeRate( + _wallet, _settingsStore.customBitcoinFeeRate, formattedCryptoAmount); } return bitcoin!.formatterBitcoinAmountToDouble(amount: fee); } - if (_wallet.type == WalletType.litecoin || - _wallet.type == WalletType.bitcoinCash) { + if (_wallet.type == WalletType.litecoin || _wallet.type == WalletType.bitcoinCash) { return bitcoin!.formatterBitcoinAmountToDouble(amount: fee); } @@ -249,7 +251,8 @@ abstract class OutputBase with Store { try { final fiat = calculateFiatAmount( price: _fiatConversationStore.prices[cryptoCurrencyHandler()]!, - cryptoAmount: sendAll ? cryptoFullBalance.replaceAll(",", ".") : cryptoAmount.replaceAll(',', '.')); + cryptoAmount: + sendAll ? cryptoFullBalance.replaceAll(",", ".") : cryptoAmount.replaceAll(',', '.')); if (fiatAmount != fiat) { fiatAmount = fiat; } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 22c083455..e8b00eb7e 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -375,6 +375,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor throw Exception("THORChain does not support Taproot addresses"); } } + + if (wallet.type == WalletType.bitcoin) { + final updatedOutputs = bitcoin!.updateOutputs(pendingTransaction!, outputs); + + if (outputs.length == updatedOutputs.length) { + outputs = ObservableList.of(updatedOutputs); + } + } + state = ExecutedSuccessfullyState(); return pendingTransaction; } catch (e) { @@ -414,8 +423,6 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor } Future _executeReplaceByFee(TransactionInfo tx, String newFee) async { - - clearOutputs(); final output = outputs.first; output.address = tx.outputAddresses?.first ?? ''; diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 0d99c1c8c..54bd54f53 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -100,7 +100,7 @@ dependencies: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v5 + ref: cake-update-v7 ledger_flutter: ^1.0.1 hashlib: ^1.19.2 @@ -138,7 +138,7 @@ dependency_overrides: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v5 + ref: cake-update-v7 flutter_icons: image_path: "assets/images/app_logo.png" diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index cee29eeb4..4784bb5e3 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -232,8 +232,9 @@ "edit_token": "تحرير الرمز المميز", "electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل", "email_address": "عنوان البريد الالكترونى", + "enable_mempool_api": "MEMPOOL API للحصول على رسوم وتواريخ دقيقة", "enable_replace_by_fee": "تمكين الاستبدال", - "enable_silent_payments_scanning": "تمكين المسح الضوئي للمدفوعات الصامتة", + "enable_silent_payments_scanning": "ابدأ في مسح المدفوعات الصامتة ، حتى يتم الوصول إلى الطرف", "enabled": "ممكنة", "enter_amount": "أدخل المبلغ", "enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا", @@ -295,6 +296,7 @@ "failed_authentication": "${state_error} فشل المصادقة.", "faq": "الأسئلة الشائعة", "features": "سمات", + "fee_rate": "معدل الرسوم", "fetching": "جار الجلب", "fiat_api": "Fiat API", "fiat_balance": "الرصيد فيات", @@ -610,6 +612,7 @@ "send": "إرسال", "send_address": "عنوان ${cryptoCurrency}", "send_amount": "مقدار:", + "send_change_to_you": "تغيير لك:", "send_creating_transaction": " يتم إنشاء المعاملة", "send_error_currency": "العملة يجب أن تحتوي على أرقام فقط", "send_error_minimum_value": "الحد الأدنى لقيمة المبلغ هو 0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "التوقيع غير صالح للرسالة المقدمة", "signTransaction": " ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ", "signup_for_card_accept_terms": "قم بالتسجيل للحصول على البطاقة وقبول الشروط.", + "silent_payment": "الدفع الصامت", "silent_payments": "مدفوعات صامتة", "silent_payments_always_scan": "حدد المدفوعات الصامتة دائمًا المسح الضوئي", "silent_payments_disclaimer": "العناوين الجديدة ليست هويات جديدة. إنها إعادة استخدام هوية موجودة مع ملصق مختلف.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ", "symbol": "ﺰﻣﺭ", "sync_all_wallets": "مزامنة جميع المحافظ", + "sync_status_attempting_scan": "محاولة المسح", "sync_status_attempting_sync": "جاري محاولة المزامنة", "sync_status_connected": "متصل", "sync_status_connecting": "يتم التوصيل", "sync_status_failed_connect": "انقطع الاتصال", "sync_status_not_connected": "غير متصل", - "sync_status_starting_scan": "بدء المسح", + "sync_status_starting_scan": "بدء المسح الضوئي (من ${height})", "sync_status_starting_sync": "بدء المزامنة", "sync_status_syncronized": "متزامن", "sync_status_syncronizing": "يتم المزامنة", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 771d58f57..d76e1c763 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -232,8 +232,9 @@ "edit_token": "Редактиране на токена", "electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят", "email_address": "Имейл адрес", + "enable_mempool_api": "Mempool API за точни такси и дати", "enable_replace_by_fee": "Активиране на замяна по забрана", - "enable_silent_payments_scanning": "Активирайте безшумните плащания за сканиране", + "enable_silent_payments_scanning": "Започнете да сканирате безшумните плащания, докато се достигне съветът", "enabled": "Активирано", "enter_amount": "Въведете сума", "enter_backup_password": "Въведете парола за възстановяване", @@ -295,6 +296,7 @@ "failed_authentication": "Неуспешно удостоверяване. ${state_error}", "faq": "FAQ", "features": "Характеристика", + "fee_rate": "Такса ставка", "fetching": "Обработване", "fiat_api": "Fiat API", "fiat_balance": "Фиат Баланс", @@ -610,6 +612,7 @@ "send": "Изпрати", "send_address": "${cryptoCurrency} адрес", "send_amount": "Сума:", + "send_change_to_you": "Променете, на вас:", "send_creating_transaction": "Създаване на транзакция", "send_error_currency": "Валутата може да съдържа само числа", "send_error_minimum_value": "Минималната сума е 0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "Подписът не е валиден за даденото съобщение", "signTransaction": "Подпишете транзакция", "signup_for_card_accept_terms": "Регистрайте се за картата и приемете условията.", + "silent_payment": "Безшумно плащане", "silent_payments": "Мълчаливи плащания", "silent_payments_always_scan": "Задайте мълчаливи плащания винаги сканиране", "silent_payments_disclaimer": "Новите адреси не са нови идентичности. Това е повторна употреба на съществуваща идентичност с различен етикет.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)", "symbol": "Символ", "sync_all_wallets": "Синхронизирайте всички портфейли", + "sync_status_attempting_scan": "Опит за сканиране", "sync_status_attempting_sync": "ОПИТ ЗА СИНХРОНИЗАЦИЯ", "sync_status_connected": "СВЪРЗВАНЕ", "sync_status_connecting": "СВЪРЗВАНЕ", "sync_status_failed_connect": "НЕУСПЕШНО СВЪРЗВАНЕ", "sync_status_not_connected": "НЯМА ВРЪЗКА", - "sync_status_starting_scan": "Стартово сканиране", + "sync_status_starting_scan": "Стартиране на сканиране (от ${height})", "sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ", "sync_status_syncronized": "СИНХРОНИЗИРАНО", "sync_status_syncronizing": "СИНХРОНИЗИРАНЕ", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 33039c741..d4c9e1151 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -232,8 +232,9 @@ "edit_token": "Upravit token", "electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují", "email_address": "E-mailová adresa", + "enable_mempool_api": "Mempool API pro přesné poplatky a data", "enable_replace_by_fee": "Povolit výměnu podle poplatku", - "enable_silent_payments_scanning": "Povolte skenování tichých plateb", + "enable_silent_payments_scanning": "Začněte skenovat tiché platby, dokud není dosaženo špičky", "enabled": "Povoleno", "enter_amount": "Zadejte částku", "enter_backup_password": "Zde zadejte své heslo pro zálohy", @@ -295,6 +296,7 @@ "failed_authentication": "Ověřování selhalo. ${state_error}", "faq": "FAQ", "features": "Funkce", + "fee_rate": "Sazba poplatků", "fetching": "Načítá se", "fiat_api": "Fiat API", "fiat_balance": "Fiat Balance", @@ -610,6 +612,7 @@ "send": "Poslat", "send_address": "${cryptoCurrency} adresa", "send_amount": "Částka:", + "send_change_to_you": "Změňte, vám:", "send_creating_transaction": "Vytváření transakce", "send_error_currency": "Měna může obsahovat pouze čísla", "send_error_minimum_value": "Minimální částka je 0,01", @@ -676,6 +679,7 @@ "signature_invalid_error": "Podpis není platný pro danou zprávu", "signTransaction": "Podepsat transakci", "signup_for_card_accept_terms": "Zaregistrujte se pro kartu a souhlaste s podmínkami.", + "silent_payment": "Tichá platba", "silent_payments": "Tiché platby", "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.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)", "symbol": "Symbol", "sync_all_wallets": "Synchronizovat všechny peněženky", + "sync_status_attempting_scan": "Pokus o skenování", "sync_status_attempting_sync": "ZAHAJUJI SYNCHR.", "sync_status_connected": "PŘIPOJENO", "sync_status_connecting": "PŘIPOJOVÁNÍ", "sync_status_failed_connect": "ODPOJENO", "sync_status_not_connected": "NEPŘIPOJENO", - "sync_status_starting_scan": "Počáteční skenování", + "sync_status_starting_scan": "Počáteční skenování (z ${height})", "sync_status_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE", "sync_status_syncronized": "SYNCHRONIZOVÁNO", "sync_status_syncronizing": "SYNCHRONIZUJI", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 98429ea04..8b316fe97 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -232,8 +232,9 @@ "edit_token": "Token bearbeiten", "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin", "email_address": "E-Mail-Adresse", + "enable_mempool_api": "Mempool -API für genaue Gebühren und Daten", "enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee", - "enable_silent_payments_scanning": "Aktivieren Sie stille Zahlungen Scannen", + "enable_silent_payments_scanning": "Scannen Sie stille Zahlungen, bis die Spitze erreicht ist", "enabled": "Ermöglicht", "enter_amount": "Betrag eingeben", "enter_backup_password": "Sicherungskennwort hier eingeben", @@ -295,6 +296,7 @@ "failed_authentication": "Authentifizierung fehlgeschlagen. ${state_error}", "faq": "Häufig gestellte Fragen", "features": "Merkmale", + "fee_rate": "Gebührenpreis", "fetching": "Frage ab", "fiat_api": "Fiat API", "fiat_balance": "Fiat Balance", @@ -611,6 +613,7 @@ "send": "Senden", "send_address": "${cryptoCurrency}-Adresse", "send_amount": "Betrag:", + "send_change_to_you": "Verändere dich zu dir:", "send_creating_transaction": "Erstelle Transaktion", "send_error_currency": "Die Währung darf nur Zahlen enthalten", "send_error_minimum_value": "Der Mindestbetrag ist 0,01", @@ -677,6 +680,7 @@ "signature_invalid_error": "Die Signatur gilt nicht für die angegebene Nachricht", "signTransaction": "Transaktion unterzeichnen", "signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.", + "silent_payment": "Stille Zahlung", "silent_payments": "Stille Zahlungen", "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.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)", "symbol": "Symbol", "sync_all_wallets": "Alle Wallets synchronisieren", + "sync_status_attempting_scan": "Versuch Scan", "sync_status_attempting_sync": "SYNC VERSUCHEN", "sync_status_connected": "VERBUNDEN", "sync_status_connecting": "VERBINDEN", "sync_status_failed_connect": "GETRENNT", "sync_status_not_connected": "NICHT VERBUNDEN", - "sync_status_starting_scan": "Scan beginnen", + "sync_status_starting_scan": "SCAN starten (von ${height})", "sync_status_starting_sync": "STARTE SYNCHRONISIERUNG", "sync_status_syncronized": "SYNCHRONISIERT", "sync_status_syncronizing": "SYNCHRONISIERE", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 7512c3ca0..6858d9359 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -232,8 +232,9 @@ "edit_token": "Edit token", "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work", "email_address": "Email Address", + "enable_mempool_api": "Mempool API for accurate fees and dates", "enable_replace_by_fee": "Enable Replace-By-Fee", - "enable_silent_payments_scanning": "Enable silent payments scanning", + "enable_silent_payments_scanning": "Start scanning silent payments, until the tip is reached", "enabled": "Enabled", "enter_amount": "Enter Amount", "enter_backup_password": "Enter backup password here", @@ -295,6 +296,7 @@ "failed_authentication": "Failed authentication. ${state_error}", "faq": "FAQ", "features": "Features", + "fee_rate": "Fee rate", "fetching": "Fetching", "fiat_api": "Fiat API", "fiat_balance": "Fiat Balance", @@ -611,6 +613,7 @@ "send": "Send", "send_address": "${cryptoCurrency} address", "send_amount": "Amount:", + "send_change_to_you": "Change, to you:", "send_creating_transaction": "Creating transaction", "send_error_currency": "Currency can only contain numbers", "send_error_minimum_value": "Minimum value of amount is 0.01", @@ -677,6 +680,7 @@ "signature_invalid_error": "The signature is not valid for the message given", "signTransaction": "Sign Transaction", "signup_for_card_accept_terms": "Sign up for the card and accept the terms.", + "silent_payment": "Silent Payment", "silent_payments": "Silent Payments", "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.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)", "symbol": "Symbol", "sync_all_wallets": "Sync all wallets", + "sync_status_attempting_scan": "ATTEMPTING SCAN", "sync_status_attempting_sync": "ATTEMPTING SYNC", "sync_status_connected": "CONNECTED", "sync_status_connecting": "CONNECTING", "sync_status_failed_connect": "DISCONNECTED", "sync_status_not_connected": "NOT CONNECTED", - "sync_status_starting_scan": "STARTING SCAN", + "sync_status_starting_scan": "STARTING SCAN (from ${height})", "sync_status_starting_sync": "STARTING SYNC", "sync_status_syncronized": "SYNCHRONIZED", "sync_status_syncronizing": "SYNCHRONIZING", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 66e17f1d5..ab92499f7 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -232,8 +232,9 @@ "edit_token": "Editar token", "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando", "email_address": "Dirección de correo electrónico", + "enable_mempool_api": "API de Mempool para tarifas y fechas precisas", "enable_replace_by_fee": "Habilitar reemplazar por tarea", - "enable_silent_payments_scanning": "Habilitar escaneo de pagos silenciosos", + "enable_silent_payments_scanning": "Comience a escanear pagos silenciosos, hasta que se alcance la punta", "enabled": "Activado", "enter_amount": "Ingrese la cantidad", "enter_backup_password": "Ingrese la contraseña de respaldo aquí", @@ -295,6 +296,7 @@ "failed_authentication": "Autenticación fallida. ${state_error}", "faq": "FAQ", "features": "Características", + "fee_rate": "Tarifa", "fetching": "Cargando", "fiat_api": "Fiat API", "fiat_balance": "Equilibrio Fiat", @@ -611,6 +613,7 @@ "send": "Enviar", "send_address": "Dirección de ${cryptoCurrency}", "send_amount": "Cantidad:", + "send_change_to_you": "Cambiar, a ti:", "send_creating_transaction": "Creando transacción", "send_error_currency": "La moneda solo puede contener números", "send_error_minimum_value": "El valor mínimo de la cantidad es 0.01", @@ -677,6 +680,7 @@ "signature_invalid_error": "La firma no es válida para el mensaje dado", "signTransaction": "Firmar transacción", "signup_for_card_accept_terms": "Regístrese para obtener la tarjeta y acepte los términos.", + "silent_payment": "Pago silencioso", "silent_payments": "Pagos silenciosos", "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.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)", "symbol": "Símbolo", "sync_all_wallets": "Sincronizar todas las billeteras", + "sync_status_attempting_scan": "Intento de escaneo", "sync_status_attempting_sync": "INTENTAR SINCRONIZAR", "sync_status_connected": "CONECTADO", "sync_status_connecting": "CONECTANDO", "sync_status_failed_connect": "DESCONECTADO", "sync_status_not_connected": "NO CONECTADO", - "sync_status_starting_scan": "Escaneo inicial", + "sync_status_starting_scan": "Iniciar escaneo (de ${height})", "sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR", "sync_status_syncronized": "SINCRONIZADO", "sync_status_syncronizing": "SINCRONIZANDO", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index da73d0c00..d062cdd86 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -232,8 +232,9 @@ "edit_token": "Modifier le token", "electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner", "email_address": "Adresse e-mail", + "enable_mempool_api": "API Mempool pour les frais et dates précis", "enable_replace_by_fee": "Activer Remplace-by-Fee", - "enable_silent_payments_scanning": "Activer la numérisation des paiements silencieux", + "enable_silent_payments_scanning": "Commencez à scanner les paiements silencieux, jusqu'à ce que la pointe soit atteinte", "enabled": "Activé", "enter_amount": "Entrez le montant", "enter_backup_password": "Entrez le mot de passe de sauvegarde ici", @@ -295,6 +296,7 @@ "failed_authentication": "Échec d'authentification. ${state_error}", "faq": "FAQ", "features": "Caractéristiques", + "fee_rate": "Taux de frais", "fetching": "Récupération", "fiat_api": "Fiat API", "fiat_balance": "Solde fiat", @@ -610,6 +612,7 @@ "send": "Envoyer", "send_address": "adresse ${cryptoCurrency}", "send_amount": "Montant :", + "send_change_to_you": "Changer, pour vous:", "send_creating_transaction": "Création de la transaction", "send_error_currency": "La monnaie ne peut contenir que des nombres", "send_error_minimum_value": "La valeur minimale du montant est 0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "La signature n'est pas valable pour le message donné", "signTransaction": "Signer une transaction", "signup_for_card_accept_terms": "Inscrivez-vous pour la carte et acceptez les conditions.", + "silent_payment": "Paiement silencieux", "silent_payments": "Paiements silencieux", "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.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)", "symbol": "Symbole", "sync_all_wallets": "Synchroniser tous les portefeuilles", + "sync_status_attempting_scan": "Tentative de numérisation", "sync_status_attempting_sync": "TENTATIVE DE SYNCHRONISATION", "sync_status_connected": "CONNECTÉ", "sync_status_connecting": "CONNEXION EN COURS", "sync_status_failed_connect": "DÉCONNECTÉ", "sync_status_not_connected": "NON CONNECTÉ", - "sync_status_starting_scan": "Démarrage", + "sync_status_starting_scan": "Démarrer la numérisation (à partir de ${height})", "sync_status_starting_sync": "DÉBUT DE SYNCHRO", "sync_status_syncronized": "SYNCHRONISÉ", "sync_status_syncronizing": "SYNCHRONISATION EN COURS", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 387c1a0b0..017fd7e01 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -232,8 +232,9 @@ "edit_token": "Gyara alamar", "electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki", "email_address": "Adireshin i-mel", + "enable_mempool_api": "Mampool API don ingantattun kudade da kwanakin", "enable_replace_by_fee": "Ba da damar maye gurbin-by-kudin", - "enable_silent_payments_scanning": "Kunna biya biya", + "enable_silent_payments_scanning": "Fara bincika biya na shiru, har sai tip ɗin ya kai", "enabled": "An kunna", "enter_amount": "Shigar da Adadi", "enter_backup_password": "Shigar da kalmar wucewa ta madadin nan", @@ -295,6 +296,7 @@ "failed_authentication": "Binne wajen shiga. ${state_error}", "faq": "FAQ", "features": "Fasas", + "fee_rate": "Kudi", "fetching": "Daukewa", "fiat_api": "API ɗin Fiat", "fiat_balance": "Fiat Balance", @@ -612,6 +614,7 @@ "send": "Aika", "send_address": "${cryptoCurrency} address", "send_amount": "Adadi:", + "send_change_to_you": "Canza, a gare ku:", "send_creating_transaction": "Ƙirƙirar ciniki", "send_error_currency": "Kudi zai iya ƙunsar lambobi kawai", "send_error_minimum_value": "Mafi ƙarancin ƙimar adadin shine 0.01", @@ -678,6 +681,7 @@ "signature_invalid_error": "Sa hannu ba shi da inganci ga sakon da aka bayar", "signTransaction": "Sa hannu Ma'amala", "signup_for_card_accept_terms": "Yi rajista don katin kuma karɓi sharuɗɗan.", + "silent_payment": "Biya silent", "silent_payments": "Biya silent", "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.", @@ -710,12 +714,13 @@ "switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)", "symbol": "Alama", "sync_all_wallets": "Sync Duk Wallet", + "sync_status_attempting_scan": "Yunƙurin scan", "sync_status_attempting_sync": "KWAFI", "sync_status_connected": "HANNU", "sync_status_connecting": "HADA", "sync_status_failed_connect": "BABU INTERNET", "sync_status_not_connected": "BABU INTERNET", - "sync_status_starting_scan": "Fara scan", + "sync_status_starting_scan": "Farawa Scan (daga ${height})", "sync_status_starting_sync": "KWAFI", "sync_status_syncronized": "KYAU", "sync_status_syncronizing": "KWAFI", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index a0d826c98..95eb228f4 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -232,8 +232,9 @@ "edit_token": "टोकन संपादित करें", "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं", "email_address": "ईमेल पता", + "enable_mempool_api": "सटीक शुल्क और तिथियों के लिए मेमपूल एपीआई", "enable_replace_by_fee": "प्रतिस्थापित-दर-शुल्क सक्षम करें", - "enable_silent_payments_scanning": "मूक भुगतान स्कैनिंग सक्षम करें", + "enable_silent_payments_scanning": "साइलेंट पेमेंट्स को स्कैन करना शुरू करें, जब तक कि टिप तक पहुंच न जाए", "enabled": "सक्रिय", "enter_amount": "राशि दर्ज करें", "enter_backup_password": "यहां बैकअप पासवर्ड डालें", @@ -295,6 +296,7 @@ "failed_authentication": "प्रमाणीकरण विफल. ${state_error}", "faq": "FAQ", "features": "विशेषताएँ", + "fee_rate": "शुल्क दर", "fetching": "ला रहा है", "fiat_api": "फिएट पैसे API", "fiat_balance": "फिएट बैलेंस", @@ -612,6 +614,7 @@ "send": "संदेश", "send_address": "${cryptoCurrency} पता", "send_amount": "रकम:", + "send_change_to_you": "बदलो, आप को:", "send_creating_transaction": "लेन-देन बनाना", "send_error_currency": "मुद्रा में केवल संख्याएँ हो सकती हैं", "send_error_minimum_value": "राशि का न्यूनतम मूल्य 0.01 है", @@ -678,6 +681,7 @@ "signature_invalid_error": "हस्ताक्षर दिए गए संदेश के लिए मान्य नहीं है", "signTransaction": "लेन-देन पर हस्ताक्षर करें", "signup_for_card_accept_terms": "कार्ड के लिए साइन अप करें और शर्तें स्वीकार करें।", + "silent_payment": "मूक भुगतान", "silent_payments": "मूक भुगतान", "silent_payments_always_scan": "मूक भुगतान हमेशा स्कैनिंग सेट करें", "silent_payments_disclaimer": "नए पते नई पहचान नहीं हैं। यह एक अलग लेबल के साथ एक मौजूदा पहचान का पुन: उपयोग है।", @@ -710,12 +714,13 @@ "switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)", "symbol": "प्रतीक", "sync_all_wallets": "सभी वॉलेट सिंक करें", + "sync_status_attempting_scan": "स्कैन का प्रयास", "sync_status_attempting_sync": "सिंक करने का प्रयास", "sync_status_connected": "जुड़े हुए", "sync_status_connecting": "कनेक्ट", "sync_status_failed_connect": "डिस्कनेक्ट किया गया", "sync_status_not_connected": "जुड़े नहीं हैं", - "sync_status_starting_scan": "स्कैन शुरू करना", + "sync_status_starting_scan": "स्कैन शुरू करना (${height} से)", "sync_status_starting_sync": "सिताज़ा करना", "sync_status_syncronized": "सिंक्रनाइज़", "sync_status_syncronizing": "सिंक्रनाइज़ करने", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 6a7214201..28f1c05b1 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -232,8 +232,9 @@ "edit_token": "Uredi token", "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek", "email_address": "Adresa e-pošte", + "enable_mempool_api": "Mempool API za točne naknade i datume", "enable_replace_by_fee": "Omogući zamjenu", - "enable_silent_payments_scanning": "Omogući skeniranje tihih plaćanja", + "enable_silent_payments_scanning": "Započnite skeniranje tihih plaćanja, dok se ne postigne savjet", "enabled": "Omogućeno", "enter_amount": "Unesite iznos", "enter_backup_password": "Unesite svoju lozinku za sigurnosnu kopiju ovdje", @@ -295,6 +296,7 @@ "failed_authentication": "Autentifikacija neuspješna. ${state_error}", "faq": "FAQ", "features": "Značajke", + "fee_rate": "Stopa naknade", "fetching": "Dohvaćanje", "fiat_api": "Fiat API", "fiat_balance": "Fiat Bilans", @@ -610,6 +612,7 @@ "send": "Pošalji", "send_address": "${cryptoCurrency} adresa", "send_amount": "Iznos:", + "send_change_to_you": "Promijenite, u vas:", "send_creating_transaction": "Izrada transakcije", "send_error_currency": "Iznos smije sadržavati samo brojeve", "send_error_minimum_value": "Minimalna vrijednost iznosa je 0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "Potpis ne vrijedi za danu poruku", "signTransaction": "Potpišite transakciju", "signup_for_card_accept_terms": "Prijavite se za karticu i prihvatite uvjete.", + "silent_payment": "Tiho plaćanje", "silent_payments": "Tiha plaćanja", "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.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)", "symbol": "Simbol", "sync_all_wallets": "Sinkronizirajte sve novčanike", + "sync_status_attempting_scan": "Pokušaj skeniranja", "sync_status_attempting_sync": "POKUŠAJ SINKRONIZACIJE", "sync_status_connected": "SPOJENO", "sync_status_connecting": "SPAJANJE", "sync_status_failed_connect": "ISKLJUČENO", "sync_status_not_connected": "NIJE POVEZANO", - "sync_status_starting_scan": "Početno skeniranje", + "sync_status_starting_scan": "Početno skeniranje (od ${height})", "sync_status_starting_sync": "ZAPOČINJEMO SINKRONIZIRANJE", "sync_status_syncronized": "SINKRONIZIRANO", "sync_status_syncronizing": "SINKRONIZIRANJE", diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb index 21b940a63..56d45deb1 100644 --- a/res/values/strings_hy.arb +++ b/res/values/strings_hy.arb @@ -231,8 +231,9 @@ "edit_token": "Փոփոխել տոկեն", "electrum_address_disclaimer": "Մենք ստեղծում ենք նոր հասցե ամեն անգամ, երբ դուք օգտագործում եք այն, բայց նախորդ հասցեները շարունակում են աշխատել", "email_address": "Էլ. փոստի հասցե", + "enable_mempool_api": "Mempool API ճշգրիտ վճարների եւ ամսաթվերի համար", "enable_replace_by_fee": "Միացնել փոխարինումը միջնորդավճարով", - "enable_silent_payments_scanning": "Միացնել Լուռ Վճարումների սկանավորումը", + "enable_silent_payments_scanning": "Սկսեք սկանավորել լուռ վճարումները, մինչեւ որ ծայրը հասնի", "enabled": "Միացված", "enter_amount": "Մուտքագրեք գումար", "enter_backup_password": "Մուտքագրեք կրկնօրինակի գաղտնաբառը", @@ -294,6 +295,7 @@ "failed_authentication": "Վավերացումը ձախողվեց. ${state_error}", "faq": "Հաճախ տրվող հարցեր", "features": "Հատկանիշներ", + "fee_rate": "Վճարման տոկոսադրույքը", "fetching": "Ստացվում է", "fiat_api": "Fiat API", "fiat_balance": "Fiat մնացորդ", @@ -610,6 +612,7 @@ "send": "Ուղարկել", "send_address": "${cryptoCurrency} հասցե", "send_amount": "Քանակ՝", + "send_change_to_you": "Փոփոխություն, ձեզ համար.", "send_creating_transaction": "Ստեղծել գործարք", "send_error_currency": "Արժույթը կարող է պարունակել միայն թվեր", "send_error_minimum_value": "Քանակի նվազագույն արժեքը 0.01 է", @@ -676,6 +679,7 @@ "signature_invalid_error": "Կնիքը անվավեր է տրված հաղորդագրության համար", "signTransaction": "Կնքել Գործարք", "signup_for_card_accept_terms": "Գրանցվել քարտի համար և ընդունել պայմանները", + "silent_payment": "Լուռ վճարում", "silent_payments": "Լուռ Վճարումներ", "silent_payments_always_scan": "Միացնել Լուռ Վճարումներ մշտական սկանավորումը", "silent_payments_disclaimer": "Նոր հասցեները նոր ինքնություն չեն։ Դա այլ պիտակով գոյություն ունեցող ինքնության վերագործածում է", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Խնդրում ենք անցնել EVM համատեղելի դրամապանակ և փորձել կրկին (Ethereum, Polygon)", "symbol": "Նշան", "sync_all_wallets": "Համաժամեցնել բոլոր դրամապանակները", + "sync_status_attempting_scan": "Փորձի սկան", "sync_status_attempting_sync": "ՀԱՄԱԺԱՄԵՑՄԱՆ ՓՈՐՁ", "sync_status_connected": "ՄԻԱՑՎԱԾԷ", "sync_status_connecting": "ՄԻԱՑՎՈՒՄ Է", "sync_status_failed_connect": "ՉՄԻԱՑԱՎ", "sync_status_not_connected": "ՄԻԱՑՎԱԾ ՉԷ", - "sync_status_starting_scan": "ՍԿԱՆԱՎՈՐՈՒՄԸ ՍԿՍՎՈՒՄ Է", + "sync_status_starting_scan": "Սկսած սկան (${height})", "sync_status_starting_sync": "ՀԱՄԱԺԱՄԵՑՈՒՄԸ ՍԿՍՎՈՒՄ Է", "sync_status_syncronized": "ՀԱՄԱԺԱՄԵՑՎԱԾԷ", "sync_status_syncronizing": "ՀԱՄԱԺԱՄԵՑՎՈՒՄ Է", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index f677a65a6..77a2c68e2 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -232,8 +232,9 @@ "edit_token": "Mengedit token", "electrum_address_disclaimer": "Kami menghasilkan alamat baru setiap kali Anda menggunakan satu, tetapi alamat sebelumnya tetap berfungsi", "email_address": "Alamat Email", + "enable_mempool_api": "API Mempool untuk biaya dan tanggal yang akurat", "enable_replace_by_fee": "Aktifkan ganti-by-fee", - "enable_silent_payments_scanning": "Aktifkan pemindaian pembayaran diam", + "enable_silent_payments_scanning": "Mulailah memindai pembayaran diam, sampai ujung tercapai", "enabled": "Diaktifkan", "enter_amount": "Masukkan Jumlah", "enter_backup_password": "Masukkan kata sandi cadangan di sini", @@ -295,6 +296,7 @@ "failed_authentication": "Otentikasi gagal. ${state_error}", "faq": "Pertanyaan yang Sering Diajukan", "features": "Fitur", + "fee_rate": "Tarif biaya", "fetching": "Mengambil", "fiat_api": "API fiat", "fiat_balance": "Saldo Fiat", @@ -613,6 +615,7 @@ "send": "Mengirim", "send_address": "Alamat ${cryptoCurrency}", "send_amount": "Jumlah:", + "send_change_to_you": "Ubah, untukmu:", "send_creating_transaction": "Membuat transaksi", "send_error_currency": "Mata uang hanya dapat berisi angka", "send_error_minimum_value": "Nilai minimum jumlah adalah 0.01", @@ -679,6 +682,7 @@ "signature_invalid_error": "Tanda tangan tidak valid untuk pesan yang diberikan", "signTransaction": "Tandatangani Transaksi", "signup_for_card_accept_terms": "Daftar untuk kartu dan terima syarat dan ketentuan.", + "silent_payment": "Pembayaran diam", "silent_payments": "Pembayaran diam", "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.", @@ -711,12 +715,13 @@ "switchToEVMCompatibleWallet": "Silakan beralih ke dompet yang kompatibel dengan EVM dan coba lagi (Ethereum, Polygon)", "symbol": "Simbol", "sync_all_wallets": "Sinkronkan semua dompet", + "sync_status_attempting_scan": "Mencoba memindai", "sync_status_attempting_sync": "MENCOBA SINKRONISASI", "sync_status_connected": "TERHUBUNG", "sync_status_connecting": "MENGHUBUNGKAN", "sync_status_failed_connect": "GAGAL TERHUBUNG", "sync_status_not_connected": "TIDAK TERHUBUNG", - "sync_status_starting_scan": "Mulai pindai", + "sync_status_starting_scan": "Mulai pemindaian (dari ${height})", "sync_status_starting_sync": "MULAI SINKRONISASI", "sync_status_syncronized": "SUDAH TERSINKRONISASI", "sync_status_syncronizing": "SEDANG SINKRONISASI", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 94cd0fa1d..161f46ad9 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -233,8 +233,9 @@ "edit_token": "Modifica token", "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare", "email_address": "Indirizzo e-mail", + "enable_mempool_api": "API di Mempool per commissioni e date accurate", "enable_replace_by_fee": "Abilita sostituzione per fee", - "enable_silent_payments_scanning": "Abilita la scansione dei pagamenti silenziosi", + "enable_silent_payments_scanning": "Inizia a scansionare i pagamenti silenziosi, fino a raggiungere la punta", "enabled": "Abilitato", "enter_amount": "Inserisci importo", "enter_backup_password": "Inserisci la password di backup qui", @@ -296,6 +297,7 @@ "failed_authentication": "Autenticazione fallita. ${state_error}", "faq": "Domande Frequenti", "features": "Caratteristiche", + "fee_rate": "Tasso di commissione", "fetching": "Recupero", "fiat_api": "Fiat API", "fiat_balance": "Equilibrio fiat", @@ -612,6 +614,7 @@ "send": "Invia", "send_address": "${cryptoCurrency} indirizzo", "send_amount": "Ammontare:", + "send_change_to_you": "Cambiamento, a te:", "send_creating_transaction": "Creazione della transazione", "send_error_currency": "L'ammontare può contenere solo numeri", "send_error_minimum_value": "L'ammontare minimo è 0.01", @@ -678,6 +681,7 @@ "signature_invalid_error": "La firma non è valida per il messaggio dato", "signTransaction": "Firma la transazione", "signup_for_card_accept_terms": "Registrati per la carta e accetta i termini.", + "silent_payment": "Pagamento silenzioso", "silent_payments": "Pagamenti silenziosi", "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.", @@ -710,12 +714,13 @@ "switchToEVMCompatibleWallet": "Passa a un portafoglio compatibile con EVM e riprova (Ethereum, Polygon)", "symbol": "Simbolo", "sync_all_wallets": "Sincronizza tutti i portafogli", + "sync_status_attempting_scan": "Tentando la scansione", "sync_status_attempting_sync": "TENTATIVO DI SINCRONIZZAZIONE", "sync_status_connected": "CONNESSO", "sync_status_connecting": "CONNESSIONE", "sync_status_failed_connect": "DISCONNESSO", "sync_status_not_connected": "NON CONNESSO", - "sync_status_starting_scan": "Scansione di partenza", + "sync_status_starting_scan": "Avvia scansione (da ${height})", "sync_status_starting_sync": "INIZIO SINC", "sync_status_syncronized": "SINCRONIZZATO", "sync_status_syncronizing": "SINCRONIZZAZIONE", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 2dd24346c..8c465f2f7 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -232,8 +232,9 @@ "edit_token": "トークンの編集", "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します", "email_address": "メールアドレス", + "enable_mempool_api": "正確な料金と日付のMempool API", "enable_replace_by_fee": "交換ごとに有効にします", - "enable_silent_payments_scanning": "サイレントペイメントスキャンを有効にします", + "enable_silent_payments_scanning": "先端に達するまで、サイレント決済のスキャンを開始します", "enabled": "有効", "enter_amount": "金額を入力", "enter_backup_password": "ここにバックアップパスワードを入力してください", @@ -295,6 +296,7 @@ "failed_authentication": "認証失敗. ${state_error}", "faq": "FAQ", "features": "特徴", + "fee_rate": "料金金利", "fetching": "フェッチング", "fiat_api": "不換紙幣 API", "fiat_balance": "フィアットバランス", @@ -611,6 +613,7 @@ "send": "送る", "send_address": "${cryptoCurrency} 住所", "send_amount": "量:", + "send_change_to_you": "あなたに変更:", "send_creating_transaction": "トランザクションを作成する", "send_error_currency": "通貨には数字のみを含めることができます", "send_error_minimum_value": "金額の最小値は0.01です", @@ -677,6 +680,7 @@ "signature_invalid_error": "署名は、指定されたメッセージに対して無効です", "signTransaction": "トランザクションに署名する", "signup_for_card_accept_terms": "カードにサインアップして、利用規約に同意してください。", + "silent_payment": "サイレント支払い", "silent_payments": "サイレント支払い", "silent_payments_always_scan": "サイレント決済を常にスキャンします", "silent_payments_disclaimer": "新しいアドレスは新しいアイデンティティではありません。これは、異なるラベルを持つ既存のアイデンティティの再利用です。", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "EVM 互換のウォレットに切り替えて再試行してください (イーサリアム、ポリゴン)", "symbol": "シンボル", "sync_all_wallets": "すべてのウォレットを同期", + "sync_status_attempting_scan": "スキャンの試み", "sync_status_attempting_sync": "同期を試みています", "sync_status_connected": "接続済み", "sync_status_connecting": "接続中", "sync_status_failed_connect": "切断されました", "sync_status_not_connected": "接続されていません", - "sync_status_starting_scan": "スキャンを開始します", + "sync_status_starting_scan": "スキャンを開始する(${height} から)", "sync_status_starting_sync": "同期の開始", "sync_status_syncronized": "同期された", "sync_status_syncronizing": "同期", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 9780de120..a5325ddff 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -232,8 +232,9 @@ "edit_token": "토큰 편집", "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다.", "email_address": "이메일 주소", + "enable_mempool_api": "정확한 수수료 및 날짜에 대한 Mempool API", "enable_replace_by_fee": "대체별로 활성화하십시오", - "enable_silent_payments_scanning": "무음 지불 스캔을 활성화합니다", + "enable_silent_payments_scanning": "팁에 도달 할 때까지 사일런트 지불을 스캔하기 시작합니다.", "enabled": "사용", "enter_amount": "금액 입력", "enter_backup_password": "여기에 백업 비밀번호를 입력하세요.", @@ -295,6 +296,7 @@ "failed_authentication": "인증 실패. ${state_error}", "faq": "FAQ", "features": "특징", + "fee_rate": "수수료", "fetching": "가져 오는 중", "fiat_api": "명목 화폐 API", "fiat_balance": "피아트 잔액", @@ -611,6 +613,7 @@ "send": "보내다", "send_address": "${cryptoCurrency} 주소", "send_amount": "양:", + "send_change_to_you": "당신에게 변경 :", "send_creating_transaction": "거래 생성", "send_error_currency": "통화는 숫자 만 포함 할 수 있습니다", "send_error_minimum_value": "금액의 최소값은 0.01입니다", @@ -677,6 +680,7 @@ "signature_invalid_error": "서명은 주어진 메시지에 유효하지 않습니다", "signTransaction": "거래 서명", "signup_for_card_accept_terms": "카드에 가입하고 약관에 동의합니다.", + "silent_payment": "조용한 지불", "silent_payments": "조용한 지불", "silent_payments_always_scan": "무음금을 항상 스캔합니다", "silent_payments_disclaimer": "새로운 주소는 새로운 정체성이 아닙니다. 다른 레이블로 기존 신원을 재사용하는 것입니다.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "EVM 호환 지갑으로 전환 후 다시 시도해 주세요. (이더리움, 폴리곤)", "symbol": "상징", "sync_all_wallets": "모든 지갑 동기화", + "sync_status_attempting_scan": "스캔 시도", "sync_status_attempting_sync": "동기화 시도 중", "sync_status_connected": "연결됨", "sync_status_connecting": "연결 중", "sync_status_failed_connect": "연결 해제", "sync_status_not_connected": "연결되지 않은", - "sync_status_starting_scan": "스캔 시작", + "sync_status_starting_scan": "시작 스캔 (${height} 에서)", "sync_status_starting_sync": "동기화 시작", "sync_status_syncronized": "동기화", "sync_status_syncronizing": "동기화", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index af28f5e9b..d2332092a 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -232,8 +232,9 @@ "edit_token": "တိုကင်ကို တည်းဖြတ်ပါ။", "electrum_address_disclaimer": "သင်အသုံးပြုသည့်အချိန်တိုင်းတွင် ကျွန်ုပ်တို့သည် လိပ်စာအသစ်များကို ထုတ်ပေးသော်လည်း ယခင်လိပ်စာများသည် ဆက်လက်အလုပ်လုပ်နေပါသည်။", "email_address": "အီးမေးလ်လိပ်စာ", + "enable_mempool_api": "Mempool API တိကျသောအခကြေးငွေနှင့်ရက်စွဲများအတွက်", "enable_replace_by_fee": "အစားထိုး - by- အခကြေးငွေ enable", - "enable_silent_payments_scanning": "အသံတိတ်ငွေပေးချေမှုကို scanable လုပ်ပါ", + "enable_silent_payments_scanning": "အစွန်အဖျားသို့ရောက်ရှိသည်အထိအသံတိတ်ငွေပေးချေမှုကိုစကင်ဖတ်စစ်ဆေးပါ", "enabled": "ဖွင့်ထားသည်။", "enter_amount": "ပမာဏကို ထည့်ပါ။", "enter_backup_password": "အရန်စကားဝှက်ကို ဤနေရာတွင် ထည့်ပါ။", @@ -295,6 +296,7 @@ "failed_authentication": "အထောက်အထားစိစစ်ခြင်း မအောင်မြင်ပါ။. ${state_error}", "faq": "အမြဲမေးလေ့ရှိသောမေးခွန်းများ", "features": "အင်္ဂါရပ်များ", + "fee_rate": "ကြေးနှုန်း", "fetching": "ခေါ်ယူခြင်း။", "fiat_api": "Fiat API", "fiat_balance": "Fiat Balance", @@ -610,6 +612,7 @@ "send": "ပို့ပါ။", "send_address": "${cryptoCurrency} လိပ်စာ", "send_amount": "ပမာဏ-", + "send_change_to_you": "ပြောင်းလဲမှု,", "send_creating_transaction": "အရောင်းအဝယ်ပြုလုပ်ခြင်း။", "send_error_currency": "ငွေကြေးတွင် နံပါတ်များသာ ပါဝင်နိုင်သည်။", "send_error_minimum_value": "ပမာဏ၏ အနည်းဆုံးတန်ဖိုးမှာ 0.01 ဖြစ်သည်။", @@ -676,6 +679,7 @@ "signature_invalid_error": "အဆိုပါလက်မှတ်ပေးထားသောမက်ဆေ့ခ်ျကိုများအတွက်မမှန်ကန်ပါ", "signTransaction": "ငွေလွှဲဝင်ပါ။", "signup_for_card_accept_terms": "ကတ်အတွက် စာရင်းသွင်းပြီး စည်းကမ်းချက်များကို လက်ခံပါ။", + "silent_payment": "အသံတိတ်ငွေပေးချေမှု", "silent_payments": "အသံတိတ်ငွေပေးချေမှု", "silent_payments_always_scan": "အမြဲတမ်း scanning အမြဲ scanning", "silent_payments_disclaimer": "လိပ်စာအသစ်များသည်အထောက်အထားအသစ်များမဟုတ်ပါ။ ၎င်းသည်ကွဲပြားခြားနားသောတံဆိပ်ဖြင့်ရှိပြီးသားဝိသေသလက်ခဏာကိုပြန်လည်အသုံးပြုခြင်းဖြစ်သည်။", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "ကျေးဇူးပြု၍ EVM တွဲဖက်သုံးနိုင်သော ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ (Ethereum၊ Polygon)", "symbol": "သင်္ကေတ", "sync_all_wallets": "အားလုံးပိုက်ဆံအိတ်စည်းညှိ", + "sync_status_attempting_scan": "scan ကြိုးစားနေ", "sync_status_attempting_sync": "ချိန်ကိုက်ခြင်းကို ကြိုးစားနေသည်။", "sync_status_connected": "ချိတ်ဆက်ထားသည်။", "sync_status_connecting": "ချိတ်ဆက်ခြင်း။", "sync_status_failed_connect": "အဆက်အသွယ်ဖြတ်ထားသည်။", "sync_status_not_connected": "မချိတ်ဆက်ပါ။", - "sync_status_starting_scan": "စကင်ဖတ်စစ်ဆေးမှု", + "sync_status_starting_scan": "စကင်ဖတ်စစ်ဆေးမှုစတင်ခြင်း (${height})", "sync_status_starting_sync": "စင့်ခ်လုပ်ခြင်း။", "sync_status_syncronized": "ထပ်တူပြုထားသည်။", "sync_status_syncronizing": "ထပ်တူပြုခြင်း။", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index c6a107d6d..fcbf0f7c9 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -232,8 +232,9 @@ "edit_token": "Token bewerken", "electrum_address_disclaimer": "We genereren nieuwe adressen elke keer dat u er een gebruikt, maar eerdere adressen blijven werken", "email_address": "E-mailadres", + "enable_mempool_api": "Mempool API voor nauwkeurige kosten en datums", "enable_replace_by_fee": "Schakel vervangen door een fee", - "enable_silent_payments_scanning": "Schakel stille betalingen in scannen in", + "enable_silent_payments_scanning": "Begin met het scannen van stille betalingen, totdat de tip is bereikt", "enabled": "Ingeschakeld", "enter_amount": "Voer Bedrag in", "enter_backup_password": "Voer hier een back-upwachtwoord in", @@ -295,6 +296,7 @@ "failed_authentication": "Mislukte authenticatie. ${state_error}", "faq": "FAQ", "features": "Functies", + "fee_rate": "Tarief", "fetching": "Ophalen", "fiat_api": "Fiat API", "fiat_balance": "Fiat Balans", @@ -610,6 +612,7 @@ "send": "Sturen", "send_address": "${cryptoCurrency}-adres", "send_amount": "Bedrag:", + "send_change_to_you": "Verander, aan jou:", "send_creating_transaction": "Transactie maken", "send_error_currency": "Valuta kan alleen cijfers bevatten", "send_error_minimum_value": "Minimale waarde van bedrag is 0,01", @@ -676,6 +679,7 @@ "signature_invalid_error": "De handtekening is niet geldig voor het gegeven bericht", "signTransaction": "Transactie ondertekenen", "signup_for_card_accept_terms": "Meld je aan voor de kaart en accepteer de voorwaarden.", + "silent_payment": "Stille betaling", "silent_payments": "Stille betalingen", "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.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Schakel over naar een EVM-compatibele portemonnee en probeer het opnieuw (Ethereum, Polygon)", "symbol": "Symbool", "sync_all_wallets": "Alle portemonnees synchroniseren", + "sync_status_attempting_scan": "Proberen scan", "sync_status_attempting_sync": "SYNCHRONISATIE PROBEREN", "sync_status_connected": "VERBONDEN", "sync_status_connecting": "AANSLUITING", "sync_status_failed_connect": "LOSGEKOPPELD", "sync_status_not_connected": "NIET VERBONDEN", - "sync_status_starting_scan": "Startscan", + "sync_status_starting_scan": "SCAN starten (van ${height})", "sync_status_starting_sync": "BEGINNEN MET SYNCHRONISEREN", "sync_status_syncronized": "SYNCHRONIZED", "sync_status_syncronizing": "SYNCHRONISEREN", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 85e75f40c..13976991a 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -232,8 +232,9 @@ "edit_token": "Edytuj token", "electrum_address_disclaimer": "Za każdym razem, gdy wykorzystasz adres, dla wiekszej prywatności generujemy nowy, ale poprzednie adresy nadal działają, i moga odbierać środki", "email_address": "Adres e-mail", + "enable_mempool_api": "Mempool API dla dokładnych opłat i dat", "enable_replace_by_fee": "Włącz wymianę po lewej", - "enable_silent_payments_scanning": "Włącz skanowanie cichych płatności", + "enable_silent_payments_scanning": "Zacznij skanować ciche płatności, aż do osiągnięcia wskazówki", "enabled": "Włączone", "enter_amount": "Wprowadź kwotę", "enter_backup_password": "Wprowadź tutaj hasło kopii zapasowej", @@ -295,6 +296,7 @@ "failed_authentication": "Nieudane uwierzytelnienie. ${state_error}", "faq": "FAQ", "features": "Cechy", + "fee_rate": "Stawka opłaty", "fetching": "Pobieranie", "fiat_api": "API Walut FIAT", "fiat_balance": "Bilans Fiata", @@ -610,6 +612,7 @@ "send": "Wyślij", "send_address": "Adres ${cryptoCurrency}", "send_amount": "Ilość:", + "send_change_to_you": "Zmień do ciebie:", "send_creating_transaction": "Tworzenie transakcji", "send_error_currency": "Waluta może zawierać tylko cyfry", "send_error_minimum_value": "Minimalna wartość to 0,01", @@ -676,6 +679,7 @@ "signature_invalid_error": "Podpis nie jest ważny dla podanej wiadomości", "signTransaction": "Podpisz transakcję", "signup_for_card_accept_terms": "Zarejestruj się, aby otrzymać kartę i zaakceptuj warunki.", + "silent_payment": "Cicha płatność", "silent_payments": "Ciche płatności", "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ą.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Przejdź na portfel zgodny z EVM i spróbuj ponownie (Ethereum, Polygon)", "symbol": "Symbol", "sync_all_wallets": "Synchronizuj wszystkie portfele", + "sync_status_attempting_scan": "Próba skanowania", "sync_status_attempting_sync": "PRÓBA SYNCHRONIZACJI", "sync_status_connected": "POŁĄCZONY", "sync_status_connecting": "ŁĄCZENIE", "sync_status_failed_connect": "POŁĄCZENIE NIEUDANE", "sync_status_not_connected": "NIE POŁĄCZONY", - "sync_status_starting_scan": "Rozpoczęcie skanowania", + "sync_status_starting_scan": "Rozpoczęcie skanowania (od ${height})", "sync_status_starting_sync": "ROZPOCZĘCIE SYNCHRONIZACJI", "sync_status_syncronized": "ZSYNCHRONIZOWANO", "sync_status_syncronizing": "SYNCHRONIZACJA", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 9283ca691..6f0f4f0b0 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -143,7 +143,7 @@ "confirm_fee_deduction": "Confirme dedução da taxa", "confirm_fee_deduction_content": "Você concorda em deduzir a taxa da saída?", "confirm_sending": "Confirmar o envio", - "confirm_silent_payments_switch_node": "Seu nó atual não suporta pagamentos silenciosos \\ Ncake Wallet mudará para um nó compatível, apenas para digitalização", + "confirm_silent_payments_switch_node": "Seu nó atual não suporta pagamentos silenciosos \n A Cake Wallet mudará para um nó compatível, apenas para escanear", "confirmations": "Confirmações", "confirmed": "Saldo Confirmado", "confirmed_tx": "Confirmado", @@ -232,8 +232,9 @@ "edit_token": "Editar símbolo", "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando", "email_address": "Endereço de e-mail", + "enable_mempool_api": "Mempool API para taxas e datas precisas", "enable_replace_by_fee": "Habilite substituir por taxa", - "enable_silent_payments_scanning": "Ativar escaneamento de pagamentos silenciosos", + "enable_silent_payments_scanning": "Comece a escanear pagamentos silenciosos, até que o topo seja alcançada", "enabled": "Habilitado", "enter_amount": "Digite o valor", "enter_backup_password": "Digite a senha de backup aqui", @@ -295,6 +296,7 @@ "failed_authentication": "Falha na autenticação. ${state_error}", "faq": "FAQ", "features": "Funcionalidades", + "fee_rate": "Taxa de transação", "fetching": "Buscando", "fiat_api": "API da Fiat", "fiat_balance": "Equilíbrio Fiat", @@ -612,6 +614,7 @@ "send": "Enviar", "send_address": "Endereço ${cryptoCurrency}", "send_amount": "Montante:", + "send_change_to_you": "Troco, para você:", "send_creating_transaction": "Criando transação", "send_error_currency": "A moeda só pode conter números", "send_error_minimum_value": "O valor mínimo da quantia é 0,01", @@ -678,8 +681,9 @@ "signature_invalid_error": "A assinatura não é válida para a mensagem dada", "signTransaction": "Assinar transação", "signup_for_card_accept_terms": "Cadastre-se no cartão e aceite os termos.", + "silent_payment": "Pagamento silencioso", "silent_payments": "Pagamentos silenciosos", - "silent_payments_always_scan": "Defina pagamentos silenciosos sempre digitalizando", + "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_scan_from_date": "Escanear a partir da data", @@ -710,12 +714,13 @@ "switchToEVMCompatibleWallet": "Mude para uma carteira compatível com EVM e tente novamente (Ethereum, Polygon)", "symbol": "Símbolo", "sync_all_wallets": "Sincronize todas as carteiras", + "sync_status_attempting_scan": "TENTANDO ESCANEAR", "sync_status_attempting_sync": "TENTANDO SINCRONIZAR", "sync_status_connected": "CONECTADO", "sync_status_connecting": "CONECTANDO", "sync_status_failed_connect": "DESCONECTADO", "sync_status_not_connected": "DESCONECTADO", - "sync_status_starting_scan": "Diretor inicial", + "sync_status_starting_scan": "Começando scan (de ${height})", "sync_status_starting_sync": "INICIANDO SINCRONIZAÇÃO", "sync_status_syncronized": "SINCRONIZADO", "sync_status_syncronizing": "SINCRONIZANDO", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index bbdc9f745..5d600c3b4 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -232,8 +232,9 @@ "edit_token": "Изменить токен", "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать.", "email_address": "Адрес электронной почты", + "enable_mempool_api": "Mempool API за точные сборы и даты", "enable_replace_by_fee": "Включить замену за пикой", - "enable_silent_payments_scanning": "Включить сканирование безмолвных платежей", + "enable_silent_payments_scanning": "Начните сканировать безмолвные платежи, пока не будет достигнут наконечник", "enabled": "Включено", "enter_amount": "Введите сумму", "enter_backup_password": "Введите пароль резервной копии", @@ -295,6 +296,7 @@ "failed_authentication": "Ошибка аутентификации. ${state_error}", "faq": "FAQ", "features": "Функции", + "fee_rate": "Плата", "fetching": "Загрузка", "fiat_api": "Фиат API", "fiat_balance": "Фиатный баланс", @@ -611,6 +613,7 @@ "send": "Отправить", "send_address": "${cryptoCurrency} адрес", "send_amount": "Сумма:", + "send_change_to_you": "Изменить, для вас:", "send_creating_transaction": "Создать транзакцию", "send_error_currency": "Валюта может содержать только цифры", "send_error_minimum_value": "Mинимальная сумма 0.01", @@ -677,6 +680,7 @@ "signature_invalid_error": "Подпись недопустима для данного сообщения", "signTransaction": "Подписать транзакцию", "signup_for_card_accept_terms": "Подпишитесь на карту и примите условия.", + "silent_payment": "Молчаливый платеж", "silent_payments": "Молчаливые платежи", "silent_payments_always_scan": "Установить молчаливые платежи всегда сканирование", "silent_payments_disclaimer": "Новые адреса не являются новыми личностями. Это повторное использование существующей идентичности с другой этикеткой.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "Пожалуйста, переключитесь на кошелек, совместимый с EVM, и повторите попытку (Ethereum, Polygon).", "symbol": "Символ", "sync_all_wallets": "Синхронизировать все кошельки", + "sync_status_attempting_scan": "Попытка сканирования", "sync_status_attempting_sync": "ПОПЫТКА СИНХРОНИЗАЦИИ", "sync_status_connected": "ПОДКЛЮЧЕНО", "sync_status_connecting": "ПОДКЛЮЧЕНИЕ", "sync_status_failed_connect": "ОТКЛЮЧЕНО", "sync_status_not_connected": "НЕ ПОДКЛЮЧЁН", - "sync_status_starting_scan": "Начальное сканирование", + "sync_status_starting_scan": "Начальное сканирование (от ${height})", "sync_status_starting_sync": "НАЧАЛО СИНХРОНИЗАЦИИ", "sync_status_syncronized": "СИНХРОНИЗИРОВАН", "sync_status_syncronizing": "СИНХРОНИЗАЦИЯ", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 3161f60d7..f924c0d2b 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -232,8 +232,9 @@ "edit_token": "แก้ไขโทเค็น", "electrum_address_disclaimer": "เราสร้างที่อยู่ใหม่ทุกครั้งที่คุณใช้หนึ่งอย่าง แต่ที่อยู่เก่ายังสามารถใช้ได้ต่อไป", "email_address": "ที่อยู่อีเมล", + "enable_mempool_api": "Mempool API สำหรับค่าธรรมเนียมและวันที่ที่ถูกต้อง", "enable_replace_by_fee": "เปิดใช้งานการเปลี่ยนโดยค่าธรรมเนียม", - "enable_silent_payments_scanning": "เปิดใช้งานการสแกนการชำระเงินแบบเงียบ", + "enable_silent_payments_scanning": "เริ่มสแกนการชำระเงินแบบเงียบจนกว่าจะถึงปลาย", "enabled": "เปิดใช้งาน", "enter_amount": "กรอกจำนวน", "enter_backup_password": "ป้อนรหัสผ่านสำรองที่นี่", @@ -295,6 +296,7 @@ "failed_authentication": "การยืนยันสิทธิ์ล้มเหลว ${state_error}", "faq": "คำถามที่พบบ่อย", "features": "คุณสมบัติ", + "fee_rate": "อัตราค่าธรรมเนียม", "fetching": "กำลังโหลด", "fiat_api": "API สกุลเงินตรา", "fiat_balance": "เฟียต บาลานซ์", @@ -610,6 +612,7 @@ "send": "ส่ง", "send_address": "ที่อยู่ ${cryptoCurrency}", "send_amount": "จำนวน:", + "send_change_to_you": "เปลี่ยนเป็นคุณ:", "send_creating_transaction": "กำลังสร้างธุรกรรม", "send_error_currency": "สกุลเงินสามารถเป็นเลขเท่านั้น", "send_error_minimum_value": "จำนวนขั้นต่ำของจำนวนเงินคือ 0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "ลายเซ็นไม่ถูกต้องสำหรับข้อความที่ให้ไว้", "signTransaction": "ลงนามในการทำธุรกรรม", "signup_for_card_accept_terms": "ลงทะเบียนสำหรับบัตรและยอมรับเงื่อนไข", + "silent_payment": "การชำระเงินแบบเงียบ", "silent_payments": "การชำระเงินเงียบ", "silent_payments_always_scan": "ตั้งค่าการชำระเงินแบบเงียบเสมอ", "silent_payments_disclaimer": "ที่อยู่ใหม่ไม่ใช่ตัวตนใหม่ มันเป็นการใช้ซ้ำของตัวตนที่มีอยู่ด้วยฉลากที่แตกต่างกัน", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงินที่รองรับ EVM แล้วลองอีกครั้ง (Ethereum, Polygon)", "symbol": "เครื่องหมาย", "sync_all_wallets": "ซิงค์กระเป๋าเงินทั้งหมด", + "sync_status_attempting_scan": "พยายามสแกน", "sync_status_attempting_sync": "พยายามซิงโครไนซ์", "sync_status_connected": "เชื่อมต่อแล้ว", "sync_status_connecting": "กำลังเชื่อมต่อ", "sync_status_failed_connect": "การเชื่อมต่อล้มเหลว", "sync_status_not_connected": "ไม่ได้เชื่อมต่อ", - "sync_status_starting_scan": "เริ่มการสแกน", + "sync_status_starting_scan": "การสแกนเริ่มต้น (จาก ${height})", "sync_status_starting_sync": "กำลังเริ่มซิงโครไนซ์", "sync_status_syncronized": "ซิงโครไนซ์แล้ว", "sync_status_syncronizing": "กำลังซิงโครไนซ์", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 54c8c4c01..00a59b9a0 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -232,8 +232,9 @@ "edit_token": "I-edit ang token", "electrum_address_disclaimer": "Bumubuo kami ng mga bagong address sa tuwing gagamit ka ng isa, ngunit ang mga nakaraang address ay patuloy na gumagana", "email_address": "Email Address", + "enable_mempool_api": "Mempool API para sa tumpak na bayad at mga petsa", "enable_replace_by_fee": "Paganahin ang Replace-By-Fee", - "enable_silent_payments_scanning": "Paganahin ang pag-scan ng mga tahimik na pagbabayad", + "enable_silent_payments_scanning": "Simulan ang pag -scan ng tahimik na pagbabayad, hanggang sa maabot ang tip", "enabled": "Pinagana", "enter_amount": "Ipasok ang halaga", "enter_backup_password": "Ipasok ang backup na password dito", @@ -295,6 +296,7 @@ "failed_authentication": "Nabigo ang pagpapatunay. ${state_error}", "faq": "FAQ", "features": "Mga tampok", + "fee_rate": "Rate ng bayad", "fetching": "Pagkuha", "fiat_api": "Fiat API", "fiat_balance": "Balanse ng fiat", @@ -610,6 +612,7 @@ "send": "Ipadala", "send_address": "${cryptoCurrency} address", "send_amount": "Halaga:", + "send_change_to_you": "Baguhin, sa iyo:", "send_creating_transaction": "Paglikha ng transaksyon", "send_error_currency": "Ang halaga ay maaari lamang maglaman ng mga numero", "send_error_minimum_value": "Ang minimum na halaga ay 0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "Ang lagda ay hindi wasto para sa ibinigay na mensahe", "signTransaction": "Mag-sign ang Transaksyon", "signup_for_card_accept_terms": "Mag-sign up para sa card at tanggapin ang mga tuntunin.", + "silent_payment": "Tahimik na pagbabayad", "silent_payments": "Tahimik na pagbabayad", "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.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Mangyaring lumipat sa isang EVM compatible na wallet at subukang muli (Ethereum, Polygon)", "symbol": "Simbolo", "sync_all_wallets": "I-sync ang lahat ng mga wallet", + "sync_status_attempting_scan": "Pagtatangka ng pag -scan", "sync_status_attempting_sync": "SINUSUBUKANG I-SYNC", "sync_status_connected": "KONEKTADO", "sync_status_connecting": "KUMOKENEKTA", "sync_status_failed_connect": "NADISKONEKTA", "sync_status_not_connected": "HINDI KONEKTADO", - "sync_status_starting_scan": "SIMULA SA PAG-SCAN", + "sync_status_starting_scan": "Simula sa pag -scan (mula sa ${height})", "sync_status_starting_sync": "SIMULA SA PAG-SYNC", "sync_status_syncronized": "NAKA-SYNCHRONIZE", "sync_status_syncronizing": "PAG-SYNCHRONIZE", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index dc0040002..700dd05b3 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -232,8 +232,9 @@ "edit_token": "Belirteci düzenle", "electrum_address_disclaimer": "Adresini her kullandığında yeni adres oluşturuyoruz, ancak önceki adresler de çalışmaya devam eder", "email_address": "E-posta Adresi", + "enable_mempool_api": "Doğru ücretler ve tarihler için Mempool API'si", "enable_replace_by_fee": "Farklı Değiştir'i Etkinleştir", - "enable_silent_payments_scanning": "Sessiz ödeme taramasını etkinleştirin", + "enable_silent_payments_scanning": "Bahşiş ulaşılıncaya kadar sessiz ödemeleri taramaya başlayın", "enabled": "Etkin", "enter_amount": "Miktar Girin", "enter_backup_password": "Yedekleme parolasını buraya gir", @@ -295,6 +296,7 @@ "failed_authentication": "Doğrulama başarısız oldu. ${state_error}", "faq": "SSS", "features": "Özellikler", + "fee_rate": "Ücret oranı", "fetching": "Getiriliyor", "fiat_api": "İtibari Para API", "fiat_balance": "Fiat Bakiyesi", @@ -610,6 +612,7 @@ "send": "Para Gönder", "send_address": "${cryptoCurrency} adresi", "send_amount": "Miktar:", + "send_change_to_you": "Değiştir, size:", "send_creating_transaction": "İşlem oluşturuluyor", "send_error_currency": "Para birimi sadece sayı içerebilir", "send_error_minimum_value": "Minimum tutar değeri 0.01'dir", @@ -676,6 +679,7 @@ "signature_invalid_error": "İmza verilen mesaj için geçerli değil", "signTransaction": "İşlem İmzala", "signup_for_card_accept_terms": "Kart için kaydol ve koşulları kabul et.", + "silent_payment": "Sessiz Ödeme", "silent_payments": "Sessiz ödemeler", "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.", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "Lütfen EVM uyumlu bir cüzdana geçin ve tekrar deneyin (Ethereum, Polygon)", "symbol": "Sembol", "sync_all_wallets": "Tüm cüzdanları senkronize edin", + "sync_status_attempting_scan": "Tarama deneme", "sync_status_attempting_sync": "SENKRONİZE EDİLMEYE ÇALIŞILIYOR", "sync_status_connected": "BAĞLANILDI", "sync_status_connecting": "BAĞLANILIYOR", "sync_status_failed_connect": "BAĞLANTI KESİLDİ", "sync_status_not_connected": "BAĞLI DEĞİL", - "sync_status_starting_scan": "Başlangıç ​​taraması", + "sync_status_starting_scan": "Başlangıç ​​taraması (${height})", "sync_status_starting_sync": "SENKRONİZE BAŞLATILIYOR", "sync_status_syncronized": "SENKRONİZE EDİLDİ", "sync_status_syncronizing": "SENKRONİZE EDİLİYOR", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index a53d54492..8772f4ba3 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -232,8 +232,9 @@ "edit_token": "Редагувати маркер", "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати", "email_address": "Адреса електронної пошти", + "enable_mempool_api": "API Mempool для точних зборів та дат", "enable_replace_by_fee": "Увімкнути заміну з комісією", - "enable_silent_payments_scanning": "Увімкнути мовчазні платежі сканування", + "enable_silent_payments_scanning": "Почніть сканувати мовчазні платежі, поки не буде досягнуто наконечника", "enabled": "Увімкнено", "enter_amount": "Введіть суму", "enter_backup_password": "Введіть пароль резервної копії", @@ -295,6 +296,7 @@ "failed_authentication": "Помилка аутентифікації. ${state_error}", "faq": "FAQ", "features": "Особливості", + "fee_rate": "Ставка плати", "fetching": "Завантаження", "fiat_api": "Фіат API", "fiat_balance": "Фіат Баланс", @@ -611,6 +613,7 @@ "send": "Відправити", "send_address": "${cryptoCurrency} адреса", "send_amount": "Сума:", + "send_change_to_you": "Зміна, для вас:", "send_creating_transaction": "Створити транзакцію", "send_error_currency": "Валюта може містити тільки цифри", "send_error_minimum_value": "Мінімальна сума 0.01", @@ -677,6 +680,7 @@ "signature_invalid_error": "Підпис не є дійсним для наведеного повідомлення", "signTransaction": "Підписати транзакцію", "signup_for_card_accept_terms": "Зареєструйтеся на картку та прийміть умови.", + "silent_payment": "Мовчазний платіж", "silent_payments": "Мовчазні платежі", "silent_payments_always_scan": "Встановити мовчазні платежі завжди сканувати", "silent_payments_disclaimer": "Нові адреси - це не нові ідентичності. Це повторне використання існуючої ідентичності з іншою етикеткою.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "Перейдіть на гаманець, сумісний з EVM, і повторіть спробу (Ethereum, Polygon)", "symbol": "символ", "sync_all_wallets": "Синхронізувати всі гаманці", + "sync_status_attempting_scan": "Спроба сканування", "sync_status_attempting_sync": "СПРОБА СИНХРОНІЗАЦІЇ", "sync_status_connected": "ПІДКЛЮЧЕНО", "sync_status_connecting": "ПІДКЛЮЧЕННЯ", "sync_status_failed_connect": "ВІДКЛЮЧЕНО", "sync_status_not_connected": "НЕ ПІДКЛЮЧЕННИЙ", - "sync_status_starting_scan": "Початок сканування", + "sync_status_starting_scan": "Початок сканування (від ${height})", "sync_status_starting_sync": "ПОЧАТОК СИНХРОНІЗАЦІЇ", "sync_status_syncronized": "СИНХРОНІЗОВАНИЙ", "sync_status_syncronizing": "СИНХРОНІЗАЦІЯ", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 65c2a768c..9b713900e 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -232,8 +232,9 @@ "edit_token": "ٹوکن میں ترمیم کریں۔", "electrum_address_disclaimer": "جب بھی آپ ایک کا استعمال کرتے ہیں تو ہم نئے پتے تیار کرتے ہیں، لیکن پچھلے پتے کام کرتے رہتے ہیں۔", "email_address": "ای میل اڈریس", + "enable_mempool_api": "درست فیسوں اور تاریخوں کے لئے میمپول API", "enable_replace_by_fee": "فی فیس کو تبدیل کریں", - "enable_silent_payments_scanning": "خاموش ادائیگیوں کو اسکیننگ کے قابل بنائیں", + "enable_silent_payments_scanning": "خاموش ادائیگیوں کو اسکین کرنا شروع کریں ، جب تک کہ نوک نہ پہنچ جائے", "enabled": "فعال", "enter_amount": "رقم درج کریں۔", "enter_backup_password": "یہاں بیک اپ پاس ورڈ درج کریں۔", @@ -295,6 +296,7 @@ "failed_authentication": "ناکام تصدیق۔ ${state_error}", "faq": "عمومی سوالات", "features": "خصوصیات", + "fee_rate": "فیس کی شرح", "fetching": "لا رہا ہے۔", "fiat_api": "Fiat API", "fiat_balance": "فیاٹ بیلنس", @@ -612,6 +614,7 @@ "send": "بھیجیں", "send_address": "${cryptoCurrency} پتہ", "send_amount": "رقم:", + "send_change_to_you": "آپ کو تبدیل کریں:", "send_creating_transaction": "لین دین کی تخلیق", "send_error_currency": "کرنسی صرف نمبروں پر مشتمل ہو سکتی ہے۔", "send_error_minimum_value": "رقم کی کم از کم قیمت 0.01 ہے۔", @@ -678,6 +681,7 @@ "signature_invalid_error": "دستخط دیئے گئے پیغام کے لئے درست نہیں ہے", "signTransaction": "۔ﮟﯾﺮﮐ ﻂﺨﺘﺳﺩ ﺮﭘ ﻦﯾﺩ ﻦﯿﻟ", "signup_for_card_accept_terms": "کارڈ کے لیے سائن اپ کریں اور شرائط کو قبول کریں۔", + "silent_payment": "خاموش ادائیگی", "silent_payments": "خاموش ادائیگی", "silent_payments_always_scan": "خاموش ادائیگی ہمیشہ اسکیننگ کریں", "silent_payments_disclaimer": "نئے پتے نئی شناخت نہیں ہیں۔ یہ ایک مختلف لیبل کے ساتھ موجودہ شناخت کا دوبارہ استعمال ہے۔", @@ -710,12 +714,13 @@ "switchToEVMCompatibleWallet": "(Ethereum, Polygon) ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ ﮯﻟﺍﻭ ﮯﻨﮭﮐﺭ ﺖﻘﺑﺎﻄﻣ ", "symbol": "ﺖﻣﻼﻋ", "sync_all_wallets": "تمام بٹوے کو ہم آہنگ کریں", + "sync_status_attempting_scan": "اسکین کی کوشش کرنا", "sync_status_attempting_sync": "ہم آہنگی کی کوشش کر رہا ہے۔", "sync_status_connected": "منسلک", "sync_status_connecting": "جڑ رہا ہے۔", "sync_status_failed_connect": "منقطع", "sync_status_not_connected": "منسلک نہیں", - "sync_status_starting_scan": "اسکین شروع کرنا", + "sync_status_starting_scan": "اسکین شروع کرنا (${height})", "sync_status_starting_sync": "مطابقت پذیری شروع کر رہا ہے۔", "sync_status_syncronized": "مطابقت پذیر", "sync_status_syncronizing": "مطابقت پذیری", diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb index d2c98fe2b..79c0fc519 100644 --- a/res/values/strings_vi.arb +++ b/res/values/strings_vi.arb @@ -140,8 +140,8 @@ "confirm": "Xác nhận", "confirm_delete_template": "Thao tác này sẽ xóa mẫu này. Bạn có muốn tiếp tục không?", "confirm_delete_wallet": "Thao tác này sẽ xóa ví này. Bạn có muốn tiếp tục không?", - "confirm_fee_deduction": "Xác nhận Khấu trừ Phí", "confirm_fee_dedction_content": "Bạn có đồng ý trừ phí từ đầu ra không?", + "confirm_fee_deduction": "Xác nhận Khấu trừ Phí", "confirm_sending": "Xác nhận gửi", "confirm_silent_payments_switch_node": "Nút hiện tại của bạn không hỗ trợ thanh toán im lặng\\nCake Wallet sẽ chuyển sang một nút tương thích chỉ để quét", "confirmations": "Xác nhận", @@ -230,6 +230,7 @@ "edit_token": "Chỉnh sửa token", "electrum_address_disclaimer": "Chúng tôi tạo địa chỉ mới mỗi khi bạn sử dụng, nhưng các địa chỉ cũ vẫn tiếp tục hoạt động", "email_address": "Địa chỉ Email", + "enable_mempool_api": "API Mempool cho các khoản phí và ngày chính xác", "enable_replace_by_fee": "Bật Thay thế Bằng Phí", "enable_silent_payments_scanning": "Bật quét thanh toán im lặng", "enabled": "Đã bật", @@ -298,7 +299,7 @@ "fiat_balance": "Số dư Fiat", "field_required": "Trường này là bắt buộc", "fill_code": "Vui lòng điền mã xác minh được gửi đến email của bạn", - "filter_by": "Lọc theo", + "filter_by": "Lọc theo", "first_wallet_text": "Ví tuyệt vời cho Monero, Bitcoin, Ethereum, Litecoin, và Haven", "fixed_pair_not_supported": "Cặp tỷ giá cố định này không được hỗ trợ với các sàn giao dịch đã chọn", "fixed_rate": "Tỷ giá cố định", @@ -398,7 +399,7 @@ "new_subaddress_label_name": "Tên nhãn", "new_subaddress_title": "Địa chỉ mới", "new_template": "Mẫu mới", - "new_wallet": "Ví mới", + "new_wallet": "Ví mới", "newConnection": "Kết nối mới", "no_cards_found": "Không tìm thấy thẻ", "no_id_needed": "Không cần ID!", @@ -498,7 +499,7 @@ "red_dark_theme": "Chủ đề tối đỏ", "red_light_theme": "Chủ đề sáng đỏ", "redeemed": "Đã đổi", - "refund_address": "Địa chỉ hoàn tiền", + "refund_address": "Địa chỉ hoàn tiền", "reject": "Từ chối", "remaining": "còn lại", "remove": "Gỡ bỏ", @@ -598,7 +599,7 @@ "seedtype": "Loại hạt giống", "seedtype_legacy": "Di sản (25 từ)", "seedtype_polyseed": "Polyseed (16 từ)", - "seedtype_wownero": "Wownero (14 từ)", + "seedtype_wownero": "Wownero (14 từ)", "select_backup_file": "Chọn tệp sao lưu", "select_buy_provider_notice": "Chọn nhà cung cấp mua ở trên. Bạn có thể bỏ qua màn hình này bằng cách thiết lập nhà cung cấp mua mặc định trong cài đặt ứng dụng.", "select_destination": "Vui lòng chọn đích cho tệp sao lưu.", @@ -698,7 +699,7 @@ "support_description_guides": "Tài liệu và hỗ trợ cho các vấn đề phổ biến", "support_description_live_chat": "Miễn phí và nhanh chóng! Các đại diện hỗ trợ được đào tạo sẵn sàng hỗ trợ", "support_description_other_links": "Tham gia cộng đồng của chúng tôi hoặc liên hệ với chúng tôi hoặc các đối tác của chúng tôi qua các phương pháp khác", - "support_title_guides": "Hướng dẫn Cake Wallet", + "support_title_guides": "Hướng dẫn Cake Wallet", "support_title_live_chat": "Hỗ trợ trực tiếp", "support_title_other_links": "Liên kết hỗ trợ khác", "sweeping_wallet": "Quét ví", @@ -712,7 +713,7 @@ "sync_status_connecting": "ĐANG KẾT NỐI", "sync_status_failed_connect": "ĐÃ NGẮT KẾT NỐI", "sync_status_not_connected": "CHƯA KẾT NỐI", - "sync_status_starting_scan": "ĐANG BẮT ĐẦU QUÉT", + "sync_status_starting_scan": "ĐANG BẮT ĐẦU QUÉT (${height})", "sync_status_starting_sync": "ĐANG BẮT ĐẦU ĐỒNG BỘ", "sync_status_syncronized": "ĐÃ ĐỒNG BỘ", "sync_status_syncronizing": "ĐANG ĐỒNG BỘ", @@ -798,7 +799,7 @@ "trongrid_history": "Lịch sử TronGrid", "trusted": "Đã tin cậy", "tx_commit_exception_no_dust_on_change": "Giao dịch bị từ chối với số tiền này. Với số tiền này bạn có thể gửi ${min} mà không cần đổi tiền lẻ hoặc ${max} trả lại tiền lẻ.", - "tx_commit_failed": "Giao dịch không thành công. Vui lòng liên hệ với hỗ trợ.", + "tx_commit_failed": "Giao dịch không thành công. Vui lòng liên hệ với hỗ trợ.", "tx_invalid_input": "Bạn đang sử dụng loại đầu vào sai cho loại thanh toán này", "tx_no_dust_exception": "Giao dịch bị từ chối vì gửi một số tiền quá nhỏ. Vui lòng thử tăng số tiền.", "tx_not_enough_inputs_exception": "Không đủ đầu vào có sẵn. Vui lòng chọn thêm dưới Coin Control", @@ -897,4 +898,4 @@ "you_will_get": "Chuyển đổi thành", "you_will_send": "Chuyển đổi từ", "yy": "YY" -} +} \ No newline at end of file diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index a5ef82d62..fbea1ba84 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -233,8 +233,9 @@ "edit_token": "Ṣatunkọ àmi", "electrum_address_disclaimer": "A dá àwọn àdírẹ́sì títun ní gbogbo àwọn ìgbà t'ẹ́ lo ó kan ṣùgbọ́n ẹ lè tẹ̀síwájú lo àwọn àdírẹ́sì tẹ́lẹ̀tẹ́lẹ̀.", "email_address": "Àdírẹ́sì ímeèlì", + "enable_mempool_api": "Mempool API fun awọn owo deede ati awọn ọjọ", "enable_replace_by_fee": "Mu ki o rọpo", - "enable_silent_payments_scanning": "Mu ki awọn sisanwo ipalọlọ", + "enable_silent_payments_scanning": "Bẹrẹ awọn sisanwo ipalọlọ, titi ti o fi de opin", "enabled": "Wọ́n tíwọn ti tan", "enter_amount": "Tẹ̀ iye", "enter_backup_password": "Tẹ̀ ọ̀rọ̀ aṣínà ti ẹ̀dà ḿbí", @@ -296,6 +297,7 @@ "failed_authentication": "Ìfẹ̀rílàdí pipòfo. ${state_error}", "faq": "Àwọn ìbéèrè l'a máa ń bèèrè", "features": "Awọn ẹya", + "fee_rate": "Oṣuwọn owo ọya", "fetching": "ń wá", "fiat_api": "Ojú ètò áàpù owó tí ìjọba pàṣẹ wa lò", "fiat_balance": "Fiat Iwontunws.funfun", @@ -611,6 +613,7 @@ "send": "Ránṣẹ́", "send_address": "${cryptoCurrency} àdírẹ́sì", "send_amount": "Iye:", + "send_change_to_you": "Yipada, si ọ:", "send_creating_transaction": "Ńṣe àránṣẹ́", "send_error_currency": "Ó yẹ kí òǹkà dá wà nínu iye", "send_error_minimum_value": "Ránṣẹ́ owó kò kéré dé 0.01", @@ -677,6 +680,7 @@ "signature_invalid_error": "Ibuwọlu ko wulo fun ifiranṣẹ ti a fun", "signTransaction": "Wole Idunadura", "signup_for_card_accept_terms": "Ẹ f'orúkọ sílẹ̀ láti gba káàdì àti àjọrò.", + "silent_payment": "Isanwo dakẹ", "silent_payments": "Awọn sisanwo ipalọlọ", "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.", @@ -709,12 +713,13 @@ "switchToEVMCompatibleWallet": "Jọwọ yipada si apamọwọ ibaramu EVM ki o tun gbiyanju lẹẹkansi (Ethereum, Polygon)", "symbol": "Aami", "sync_all_wallets": "Muṣiṣẹpọ gbogbo awọn Woleti", + "sync_status_attempting_scan": "Igbiyanju ọlọjẹ", "sync_status_attempting_sync": "Ń GBÌYÀNJÚ MÚDỌ́GBA", "sync_status_connected": "TI DÁRAPỌ̀ MỌ́", "sync_status_connecting": "Ń DÁRAPỌ̀ MỌ́", "sync_status_failed_connect": "ÌKÀNPỌ̀ TI KÚ", "sync_status_not_connected": "KÒ TI DÁRAPỌ̀ MỌ́ Ọ", - "sync_status_starting_scan": "Bibẹrẹ ọlọjẹ", + "sync_status_starting_scan": "Ibẹrẹ ọlọjẹ (lati ${height})", "sync_status_starting_sync": "Ń BẸ̀RẸ̀ RẸ́", "sync_status_syncronized": "TI MÚDỌ́GBA", "sync_status_syncronizing": "Ń MÚDỌ́GBA", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 37e760de2..2c0abe5eb 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -232,8 +232,9 @@ "edit_token": "编辑令牌", "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效", "email_address": "电子邮件地址", + "enable_mempool_api": "Mempool API获得准确的费用和日期", "enable_replace_by_fee": "启用by-Fee替换", - "enable_silent_payments_scanning": "启用无声付款扫描", + "enable_silent_payments_scanning": "开始扫描无声付款,直到达到提示", "enabled": "启用", "enter_amount": "输入金额", "enter_backup_password": "在此处输入備用密码", @@ -295,6 +296,7 @@ "failed_authentication": "身份验证失败. ${state_error}", "faq": "FAQ", "features": "特征", + "fee_rate": "费率", "fetching": "正在获取", "fiat_api": "法币API", "fiat_balance": "法币余额", @@ -610,6 +612,7 @@ "send": "发送", "send_address": "${cryptoCurrency} 地址", "send_amount": "金额:", + "send_change_to_you": "改变,向您:", "send_creating_transaction": "创建交易", "send_error_currency": "货币只能包含数字", "send_error_minimum_value": "最小金额为0.01", @@ -676,6 +679,7 @@ "signature_invalid_error": "签名对于给出的消息无效", "signTransaction": "签署交易", "signup_for_card_accept_terms": "注册卡并接受条款。", + "silent_payment": "无声付款", "silent_payments": "无声付款", "silent_payments_always_scan": "设置无声付款总是扫描", "silent_payments_disclaimer": "新地址不是新的身份。这是重复使用具有不同标签的现有身份。", @@ -708,12 +712,13 @@ "switchToEVMCompatibleWallet": "请切换到 EVM 兼容钱包并重试(以太坊、Polygon)", "symbol": "象征", "sync_all_wallets": "同步所有钱包", + "sync_status_attempting_scan": "尝试扫描", "sync_status_attempting_sync": "嘗試同步", "sync_status_connected": "已连接", "sync_status_connecting": "连接中", "sync_status_failed_connect": "断线", "sync_status_not_connected": "未连接", - "sync_status_starting_scan": "开始扫描", + "sync_status_starting_scan": "启动扫描(来自 ${height})", "sync_status_starting_sync": "开始同步", "sync_status_syncronized": "已同步", "sync_status_syncronizing": "正在同步", diff --git a/tool/configure.dart b/tool/configure.dart index 1d2166ed6..f77db8d1c 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -116,7 +116,7 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/litecoin_wallet_service.dart'; import 'package:cw_core/get_height_by_date.dart'; -import 'package:cw_bitcoin/script_hash.dart'; +import 'package:cw_core/transaction_info.dart'; import 'package:cw_bitcoin/bitcoin_hardware_wallet_service.dart'; import 'package:mobx/mobx.dart'; """; @@ -211,7 +211,8 @@ 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}); - int getHeightByDate({required DateTime date}); + Future checkIfMempoolAPIIsEnabled(Object wallet); + Future getHeightByDate({required DateTime date, bool? bitcoinMempoolAPIEnabled}); Future rescan(Object wallet, {required int height, bool? doSingleScan}); Future getNodeIsElectrsSPEnabled(Object wallet); void deleteSilentPaymentAddress(Object wallet, String address); @@ -220,6 +221,8 @@ abstract class Bitcoin { void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device); Future> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5}); + List updateOutputs(PendingTransaction pendingTransaction, List outputs); + bool txIsReceivedSilentPayment(TransactionInfo txInfo); } """;