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 <omarh.ismail1@gmail.com>

Rafael committed Sep 20, 2024 at 14:24 UTC 3a391f10a37e4f8726fb6d374fe3aa217a78a1b7
61 files changed +872 -531
cw_bitcoin/lib/address_to_output_script.dart deleted
-14
@@ -1,14 +0,0 @@
1 -import 'dart:typed_data';
2 -import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin;
3 -
4 -List<int> addressToOutputScript(String address, bitcoin.BasedUtxoNetwork network) {
5 - try {
6 - if (network == bitcoin.BitcoinCashNetwork.mainnet) {
7 - return bitcoin.BitcoinCashAddress(address).baseAddress.toScriptPubKey().toBytes();
8 - }
9 - return bitcoin.addressToOutputScript(address: address, network: network);
10 - } catch (err) {
11 - print(err);
12 - return Uint8List(0);
13 - }
14 -}
cw_bitcoin/lib/bitcoin_address_record.dart
+3 -4
@@ -1,7 +1,6 @@
1 import 'dart:convert';
2
3 import 'package:bitcoin_base/bitcoin_base.dart';
4 -import 'package:cw_bitcoin/script_hash.dart' as sh;
4
5 abstract class BaseBitcoinAddressRecord {
6 BaseBitcoinAddressRecord(
@@ -65,8 +64,8 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
64 required super.type,
65 String? scriptHash,
66 required super.network,
68 - }) : scriptHash =
69 - scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null);
67 + }) : scriptHash = scriptHash ??
68 + (network != null ? BitcoinAddressUtils.scriptHash(address, network: network) : null);
69
70 factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) {
71 final decoded = json.decode(jsonSource) as Map;
@@ -92,7 +91,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
91
92 String getScriptHash(BasedUtxoNetwork network) {
93 if (scriptHash != null) return scriptHash!;
95 - scriptHash = sh.scriptHash(address, network: network);
94 + scriptHash = BitcoinAddressUtils.scriptHash(address, network: network);
95 return scriptHash!;
96 }
97
cw_bitcoin/lib/electrum.dart
+24 -34
@@ -4,7 +4,6 @@ import 'dart:io';
4 import 'dart:typed_data';
5 import 'package:bitcoin_base/bitcoin_base.dart';
6 import 'package:cw_bitcoin/bitcoin_amount_format.dart';
7 -import 'package:cw_bitcoin/script_hash.dart';
7 import 'package:flutter/foundation.dart';
8 import 'package:rxdart/rxdart.dart';
9
@@ -48,6 +47,7 @@ class ElectrumClient {
47 final Map<String, SocketTask> _tasks;
48 Map<String, SocketTask> get tasks => _tasks;
49 final Map<String, String> _errors;
50 + ConnectionStatus _connectionStatus = ConnectionStatus.disconnected;
51 bool _isConnected;
52 Timer? _aliveTimer;
53 String unterminatedString;
@@ -57,11 +57,13 @@ class ElectrumClient {
57
58 Future<void> connectToUri(Uri uri, {bool? useSSL}) async {
59 this.uri = uri;
60 - this.useSSL = useSSL;
61 - await connect(host: uri.host, port: uri.port, useSSL: useSSL);
60 + if (useSSL != null) {
61 + this.useSSL = useSSL;
62 + }
63 + await connect(host: uri.host, port: uri.port);
64 }
65
64 - Future<void> connect({required String host, required int port, bool? useSSL}) async {
66 + Future<void> connect({required String host, required int port}) async {
67 _setConnectionStatus(ConnectionStatus.connecting);
68
69 try {
@@ -80,15 +82,26 @@ class ElectrumClient {
82 onBadCertificate: (_) => true,
83 );
84 }
83 - } catch (_) {
84 - _setConnectionStatus(ConnectionStatus.failed);
85 + } catch (e) {
86 + if (e is HandshakeException) {
87 + useSSL = !(useSSL ?? false);
88 + }
89 +
90 + if (_connectionStatus != ConnectionStatus.connecting) {
91 + _setConnectionStatus(ConnectionStatus.failed);
92 + }
93 +
94 return;
95 }
96
97 if (socket == null) {
89 - _setConnectionStatus(ConnectionStatus.failed);
98 + if (_connectionStatus != ConnectionStatus.connecting) {
99 + _setConnectionStatus(ConnectionStatus.failed);
100 + }
101 +
102 return;
103 }
104 +
105 _setConnectionStatus(ConnectionStatus.connected);
106
107 socket!.listen(
@@ -118,7 +131,7 @@ class ElectrumClient {
131 socket?.destroy();
132 _setConnectionStatus(ConnectionStatus.disconnected);
133 }
121 - } catch(e) {
134 + } catch (e) {
135 print(e.toString());
136 }
137 },
@@ -217,25 +230,6 @@ class ElectrumClient {
230 return [];
231 });
232
220 - Future<List<Map<String, dynamic>>> getListUnspentWithAddress(
221 - String address, BasedUtxoNetwork network) =>
222 - call(
223 - method: 'blockchain.scripthash.listunspent',
224 - params: [scriptHash(address, network: network)]).then((dynamic result) {
225 - if (result is List) {
226 - return result.map((dynamic val) {
227 - if (val is Map<String, dynamic>) {
228 - val['address'] = address;
229 - return val;
230 - }
231 -
232 - return <String, dynamic>{};
233 - }).toList();
234 - }
235 -
236 - return [];
237 - });
238 -
233 Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) =>
234 call(method: 'blockchain.scripthash.listunspent', params: [scriptHash])
235 .then((dynamic result) {
@@ -272,16 +266,12 @@ class ElectrumClient {
266 try {
267 final result = await callWithTimeout(
268 method: 'blockchain.transaction.get', params: [hash, verbose], timeout: 10000);
275 - if (result is Map<String, dynamic>) {
276 - return result;
277 - }
269 + return result;
270 } on RequestFailedTimeoutException catch (_) {
271 return <String, dynamic>{};
272 } catch (e) {
281 - print("getTransaction: ${e.toString()}");
273 return <String, dynamic>{};
274 }
284 - return <String, dynamic>{};
275 }
276
277 Future<Map<String, dynamic>> getTransactionVerbose({required String hash}) =>
@@ -326,9 +316,8 @@ class ElectrumClient {
316 await call(method: 'blockchain.block.get_header', params: [height]) as Map<String, dynamic>;
317
318 BehaviorSubject<Object>? tweaksSubscribe({required int height, required int count}) {
329 - _id += 1;
319 return subscribe<Object>(
331 - id: 'blockchain.tweaks.subscribe:${height + count}',
320 + id: 'blockchain.tweaks.subscribe',
321 method: 'blockchain.tweaks.subscribe',
322 params: [height, count, false],
323 );
@@ -539,6 +528,7 @@ class ElectrumClient {
528
529 void _setConnectionStatus(ConnectionStatus status) {
530 onConnectionStatusChange?.call(status);
531 + _connectionStatus = status;
532 _isConnected = status == ConnectionStatus.connected;
533 }
534
cw_bitcoin/lib/electrum_transaction_info.dart
+20 -14
@@ -23,20 +23,24 @@ class ElectrumTransactionBundle {
23
24 class ElectrumTransactionInfo extends TransactionInfo {
25 List<BitcoinSilentPaymentsUnspent>? unspents;
26 -
27 - ElectrumTransactionInfo(this.type,
28 - {required String id,
29 - int? height,
30 - required int amount,
31 - int? fee,
32 - List<String>? inputAddresses,
33 - List<String>? outputAddresses,
34 - required TransactionDirection direction,
35 - required bool isPending,
36 - required DateTime date,
37 - required int confirmations,
38 - String? to,
39 - this.unspents}) {
26 + bool isReceivedSilentPayment;
27 +
28 + ElectrumTransactionInfo(
29 + this.type, {
30 + required String id,
31 + int? height,
32 + required int amount,
33 + int? fee,
34 + List<String>? inputAddresses,
35 + List<String>? outputAddresses,
36 + required TransactionDirection direction,
37 + required bool isPending,
38 + required DateTime date,
39 + required int confirmations,
40 + String? to,
41 + this.unspents,
42 + this.isReceivedSilentPayment = false,
43 + }) {
44 this.id = id;
45 this.height = height;
46 this.amount = amount;
@@ -202,6 +206,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
206 .map((unspent) =>
207 BitcoinSilentPaymentsUnspent.fromJSON(null, unspent as Map<String, dynamic>))
208 .toList(),
209 + isReceivedSilentPayment: data['isReceivedSilentPayment'] as bool? ?? false,
210 );
211 }
212
@@ -252,6 +257,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
257 m['unspents'] = unspents?.map((e) => e.toJson()).toList() ?? [];
258 m['inputAddresses'] = inputAddresses;
259 m['outputAddresses'] = outputAddresses;
260 + m['isReceivedSilentPayment'] = isReceivedSilentPayment;
261 return m;
262 }
263
cw_bitcoin/lib/electrum_wallet.dart
+113 -86
@@ -24,7 +24,6 @@ import 'package:cw_bitcoin/electrum_transaction_info.dart';
24 import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
25 import 'package:cw_bitcoin/exceptions.dart';
26 import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
27 -import 'package:cw_bitcoin/script_hash.dart';
27 import 'package:cw_bitcoin/utils.dart';
28 import 'package:cw_core/crypto_currency.dart';
29 import 'package:cw_core/node.dart';
@@ -51,8 +50,6 @@ part 'electrum_wallet.g.dart';
50
51 class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet;
52
54 -const int TWEAKS_COUNT = 25;
55 -
53 abstract class ElectrumWalletBase
54 extends WalletBase<ElectrumBalance, ElectrumTransactionHistory, ElectrumTransactionInfo>
55 with Store, WalletKeysFile {
@@ -166,12 +163,12 @@ abstract class ElectrumWalletBase
163 Set<String> get addressesSet => walletAddresses.allAddresses.map((addr) => addr.address).toSet();
164
165 List<String> get scriptHashes => walletAddresses.addressesByReceiveType
169 - .map((addr) => scriptHash(addr.address, network: network))
166 + .map((addr) => (addr as BitcoinAddressRecord).getScriptHash(network))
167 .toList();
168
169 List<String> get publicScriptHashes => walletAddresses.allAddresses
170 .where((addr) => !addr.isHidden)
174 - .map((addr) => scriptHash(addr.address, network: network))
171 + .map((addr) => addr.getScriptHash(network))
172 .toList();
173
174 String get xpub => accountHD.publicKey.toExtended;
@@ -212,7 +209,7 @@ abstract class ElectrumWalletBase
209 silentPaymentsScanningActive = active;
210
211 if (active) {
215 - syncStatus = StartingScanSyncStatus();
212 + syncStatus = AttemptingScanSyncStatus();
213
214 final tip = await getUpdatedChainTip();
215
@@ -290,12 +287,7 @@ abstract class ElectrumWalletBase
287 }
288
289 @action
293 - Future<void> _setListeners(
294 - int height, {
295 - int? chainTipParam,
296 - bool? doSingleScan,
297 - bool? usingSupportedNode,
298 - }) async {
290 + Future<void> _setListeners(int height, {int? chainTipParam, bool? doSingleScan}) async {
291 final chainTip = chainTipParam ?? await getUpdatedChainTip();
292
293 if (chainTip == height) {
@@ -303,7 +295,7 @@ abstract class ElectrumWalletBase
295 return;
296 }
297
306 - syncStatus = StartingScanSyncStatus();
298 + syncStatus = AttemptingScanSyncStatus();
299
300 if (_isolate != null) {
301 final runningIsolate = await _isolate!;
@@ -550,7 +542,8 @@ abstract class ElectrumWalletBase
542 electrumClient.onConnectionStatusChange = _onConnectionStatusChange;
543
544 await electrumClient.connectToUri(node.uri, useSSL: node.useSSL);
553 - } catch (e) {
545 + } catch (e, stacktrace) {
546 + print(stacktrace);
547 print(e.toString());
548 syncStatus = FailedSyncStatus();
549 }
@@ -592,7 +585,7 @@ abstract class ElectrumWalletBase
585 allInputsAmount += utx.value;
586 leftAmount = leftAmount - utx.value;
587
595 - final address = addressTypeFromStr(utx.address, network);
588 + final address = RegexUtils.addressTypeFromStr(utx.address, network);
589 ECPrivate? privkey;
590 bool? isSilentPayment = false;
591
@@ -796,10 +789,11 @@ abstract class ElectrumWalletBase
789 }
790
791 final changeAddress = await walletAddresses.getChangeAddress();
799 - final address = addressTypeFromStr(changeAddress, network);
792 + final address = RegexUtils.addressTypeFromStr(changeAddress, network);
793 outputs.add(BitcoinOutput(
794 address: address,
795 value: BigInt.from(amountLeftForChangeAndFee),
796 + isChange: true,
797 ));
798
799 int estimatedSize;
@@ -833,8 +827,12 @@ abstract class ElectrumWalletBase
827
828 if (!_isBelowDust(amountLeftForChange)) {
829 // Here, lastOutput already is change, return the amount left without the fee to the user's address.
836 - outputs[outputs.length - 1] =
837 - BitcoinOutput(address: lastOutput.address, value: BigInt.from(amountLeftForChange));
830 + outputs[outputs.length - 1] = BitcoinOutput(
831 + address: lastOutput.address,
832 + value: BigInt.from(amountLeftForChange),
833 + isSilentPayment: lastOutput.isSilentPayment,
834 + isChange: true,
835 + );
836 } else {
837 // If has change that is lower than dust, will end up with tx rejected by network rules, so estimate again without the added change
838 outputs.removeLast();
@@ -938,18 +936,27 @@ abstract class ElectrumWalletBase
936
937 credentialsAmount += outputAmount;
938
941 - final address =
942 - addressTypeFromStr(out.isParsedAddress ? out.extractedAddress! : out.address, network);
939 + final address = RegexUtils.addressTypeFromStr(
940 + out.isParsedAddress ? out.extractedAddress! : out.address, network);
941 + final isSilentPayment = address is SilentPaymentAddress;
942
944 - if (address is SilentPaymentAddress) {
943 + if (isSilentPayment) {
944 hasSilentPayment = true;
945 }
946
947 if (sendAll) {
948 // The value will be changed after estimating the Tx size and deducting the fee from the total to be sent
950 - outputs.add(BitcoinOutput(address: address, value: BigInt.from(0)));
949 + outputs.add(BitcoinOutput(
950 + address: address,
951 + value: BigInt.from(0),
952 + isSilentPayment: isSilentPayment,
953 + ));
954 } else {
952 - outputs.add(BitcoinOutput(address: address, value: BigInt.from(outputAmount)));
955 + outputs.add(BitcoinOutput(
956 + address: address,
957 + value: BigInt.from(outputAmount),
958 + isSilentPayment: isSilentPayment,
959 + ));
960 }
961 }
962
@@ -1089,7 +1096,8 @@ abstract class ElectrumWalletBase
1096 });
1097 }
1098
1092 - unspentCoins.removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash));
1099 + unspentCoins
1100 + .removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash));
1101
1102 await updateBalance();
1103 });
@@ -1237,12 +1245,7 @@ abstract class ElectrumWalletBase
1245
1246 @action
1247 @override
1240 - Future<void> rescan({
1241 - required int height,
1242 - int? chainTip,
1243 - ScanData? scanData,
1244 - bool? doSingleScan,
1245 - }) async {
1248 + Future<void> rescan({required int height, bool? doSingleScan}) async {
1249 silentPaymentsScanningActive = true;
1250 _setListeners(height, doSingleScan: doSingleScan);
1251 }
@@ -1460,7 +1463,7 @@ abstract class ElectrumWalletBase
1463 final addressRecord =
1464 walletAddresses.allAddresses.firstWhere((element) => element.address == address);
1465
1463 - final btcAddress = addressTypeFromStr(addressRecord.address, network);
1466 + final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network);
1467 final privkey = generateECPrivate(
1468 hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
1469 index: addressRecord.index,
@@ -1501,7 +1504,7 @@ abstract class ElectrumWalletBase
1504 }
1505
1506 final address = addressFromOutputScript(out.scriptPubKey, network);
1504 - final btcAddress = addressTypeFromStr(address, network);
1507 + final btcAddress = RegexUtils.addressTypeFromStr(address, network);
1508 outputs.add(BitcoinOutput(address: btcAddress, value: BigInt.from(out.amount.toInt())));
1509 }
1510
@@ -1597,8 +1600,6 @@ abstract class ElectrumWalletBase
1600 Future<ElectrumTransactionBundle> getTransactionExpanded(
1601 {required String hash, int? height}) async {
1602 String transactionHex;
1600 - // TODO: time is not always available, and calculating it from height is not always accurate.
1601 - // Add settings to choose API provider and use and http server instead of electrum for this.
1603 int? time;
1604 int? confirmations;
1605
@@ -1606,6 +1607,29 @@ abstract class ElectrumWalletBase
1607
1608 if (verboseTransaction.isEmpty) {
1609 transactionHex = await electrumClient.getTransactionHex(hash: hash);
1610 +
1611 + if (height != null && await checkIfMempoolAPIIsEnabled()) {
1612 + final blockHash = await http.get(
1613 + Uri.parse(
1614 + "http://mempool.cakewallet.com:8999/api/v1/block-height/$height",
1615 + ),
1616 + );
1617 +
1618 + if (blockHash.statusCode == 200 &&
1619 + blockHash.body.isNotEmpty &&
1620 + jsonDecode(blockHash.body) != null) {
1621 + final blockResponse = await http.get(
1622 + Uri.parse(
1623 + "http://mempool.cakewallet.com:8999/api/v1/block/${blockHash.body}",
1624 + ),
1625 + );
1626 + if (blockResponse.statusCode == 200 &&
1627 + blockResponse.body.isNotEmpty &&
1628 + jsonDecode(blockResponse.body)['timestamp'] != null) {
1629 + time = int.parse(jsonDecode(blockResponse.body)['timestamp'].toString());
1630 + }
1631 + }
1632 + }
1633 } else {
1634 transactionHex = verboseTransaction['hex'] as String;
1635 time = verboseTransaction['time'] as int?;
@@ -1860,7 +1884,7 @@ abstract class ElectrumWalletBase
1884 final balanceFutures = <Future<Map<String, dynamic>>>[];
1885 for (var i = 0; i < addresses.length; i++) {
1886 final addressRecord = addresses[i];
1863 - final sh = scriptHash(addressRecord.address, network: network);
1887 + final sh = addressRecord.getScriptHash(network);
1888 final balanceFuture = electrumClient.getBalance(sh);
1889 balanceFutures.add(balanceFuture);
1890 }
@@ -1900,7 +1924,10 @@ abstract class ElectrumWalletBase
1924 }
1925
1926 return ElectrumBalance(
1903 - confirmed: totalConfirmed, unconfirmed: totalUnconfirmed, frozen: totalFrozen);
1927 + confirmed: totalConfirmed,
1928 + unconfirmed: totalUnconfirmed,
1929 + frozen: totalFrozen,
1930 + );
1931 }
1932
1933 Future<void> updateBalance() async {
@@ -1968,7 +1995,7 @@ abstract class ElectrumWalletBase
1995
1996 List<int> possibleRecoverIds = [0, 1];
1997
1971 - final baseAddress = addressTypeFromStr(address, network);
1998 + final baseAddress = RegexUtils.addressTypeFromStr(address, network);
1999
2000 for (int recoveryId in possibleRecoverIds) {
2001 final pubKey = sig.recoverPublicKey(messageHash, Curves.generatorSecp256k1, recoveryId);
@@ -2061,7 +2088,8 @@ abstract class ElectrumWalletBase
2088 _isTryingToConnect = true;
2089
2090 Timer(Duration(seconds: 5), () {
2064 - if (this.syncStatus is NotConnectedSyncStatus || this.syncStatus is LostConnectionSyncStatus) {
2091 + if (this.syncStatus is NotConnectedSyncStatus ||
2092 + this.syncStatus is LostConnectionSyncStatus) {
2093 this.electrumClient.connectToUri(
2094 node!.uri,
2095 useSSL: node!.useSSL ?? false,
@@ -2192,21 +2220,22 @@ Future<void> startRefresh(ScanData scanData) async {
2220
2221 BehaviorSubject<Object>? tweaksSubscription = null;
2222
2195 - final syncingStatus = scanData.isSingleScan
2196 - ? SyncingSyncStatus(1, 0)
2197 - : SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, syncHeight);
2198 -
2199 - // Initial status UI update, send how many blocks left to scan
2200 - scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
2201 -
2223 final electrumClient = scanData.electrumClient;
2224 await electrumClient.connectToUri(
2225 scanData.node?.uri ?? Uri.parse("tcp://electrs.cakewallet.com:50001"),
2226 useSSL: scanData.node?.useSSL ?? false,
2227 );
2228
2229 + int getCountPerRequest(int syncHeight) {
2230 + if (scanData.isSingleScan) {
2231 + return 1;
2232 + }
2233 +
2234 + final amountLeft = scanData.chainTip - syncHeight + 1;
2235 + return amountLeft;
2236 + }
2237 +
2238 if (tweaksSubscription == null) {
2209 - final count = scanData.isSingleScan ? 1 : TWEAKS_COUNT;
2239 final receiver = Receiver(
2240 scanData.silentAddress.b_scan.toHex(),
2241 scanData.silentAddress.B_spend.toHex(),
@@ -2215,16 +2244,45 @@ Future<void> startRefresh(ScanData scanData) async {
2244 scanData.labelIndexes.length,
2245 );
2246
2218 - tweaksSubscription = await electrumClient.tweaksSubscribe(height: syncHeight, count: count);
2219 - tweaksSubscription?.listen((t) async {
2247 + // Initial status UI update, send how many blocks in total to scan
2248 + final initialCount = getCountPerRequest(syncHeight);
2249 + scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
2250 +
2251 + tweaksSubscription = await electrumClient.tweaksSubscribe(
2252 + height: syncHeight,
2253 + count: initialCount,
2254 + );
2255 +
2256 + Future<void> listenFn(t) async {
2257 final tweaks = t as Map<String, dynamic>;
2258 + final msg = tweaks["message"];
2259 + // success or error msg
2260 + final noData = msg != null;
2261
2222 - if (tweaks["message"] != null) {
2262 + if (noData) {
2263 // re-subscribe to continue receiving messages, starting from the next unscanned height
2224 - electrumClient.tweaksSubscribe(height: syncHeight + 1, count: count);
2264 + final nextHeight = syncHeight + 1;
2265 + final nextCount = getCountPerRequest(nextHeight);
2266 +
2267 + if (nextCount > 0) {
2268 + tweaksSubscription?.close();
2269 +
2270 + final nextTweaksSubscription = electrumClient.tweaksSubscribe(
2271 + height: nextHeight,
2272 + count: nextCount,
2273 + );
2274 + nextTweaksSubscription?.listen(listenFn);
2275 + }
2276 +
2277 return;
2278 }
2279
2280 + // Continuous status UI update, send how many blocks left to scan
2281 + final syncingStatus = scanData.isSingleScan
2282 + ? SyncingSyncStatus(1, 0)
2283 + : SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, syncHeight);
2284 + scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
2285 +
2286 final blockHeight = tweaks.keys.first;
2287 final tweakHeight = int.parse(blockHeight);
2288
@@ -2264,6 +2322,7 @@ Future<void> startRefresh(ScanData scanData) async {
2322 : DateTime.now(),
2323 confirmations: scanData.chainTip - tweakHeight + 1,
2324 unspents: [],
2325 + isReceivedSilentPayment: true,
2326 );
2327
2328 addToWallet.forEach((label, value) {
@@ -2318,16 +2377,6 @@ Future<void> startRefresh(ScanData scanData) async {
2377 } catch (_) {}
2378
2379 syncHeight = tweakHeight;
2321 - scanData.sendPort.send(
2322 - SyncResponse(
2323 - syncHeight,
2324 - SyncingSyncStatus.fromHeightValues(
2325 - scanData.chainTip,
2326 - initialSyncHeight,
2327 - syncHeight,
2328 - ),
2329 - ),
2330 - );
2380
2381 if (tweakHeight >= scanData.chainTip || scanData.isSingleScan) {
2382 if (tweakHeight >= scanData.chainTip)
@@ -2343,7 +2392,9 @@ Future<void> startRefresh(ScanData scanData) async {
2392 await tweaksSubscription!.close();
2393 await electrumClient.close();
2394 }
2346 - });
2395 + }
2396 +
2397 + tweaksSubscription?.listen(listenFn);
2398 }
2399
2400 if (tweaksSubscription == null) {
@@ -2373,6 +2424,7 @@ class EstimatedTxResult {
2424 final int fee;
2425 final int amount;
2426 final bool spendsSilentPayment;
2427 + // final bool sendsToSilentPayment;
2428 final bool hasChange;
2429 final bool isSendAll;
2430 final String? memo;
@@ -2386,31 +2438,6 @@ class PublicKeyWithDerivationPath {
2438 final String publicKey;
2439 }
2440
2389 -BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network) {
2390 - if (network is BitcoinCashNetwork) {
2391 - if (!address.startsWith("bitcoincash:") &&
2392 - (address.startsWith("q") || address.startsWith("p"))) {
2393 - address = "bitcoincash:$address";
2394 - }
2395 -
2396 - return BitcoinCashAddress(address).baseAddress;
2397 - }
2398 -
2399 - if (P2pkhAddress.regex.hasMatch(address)) {
2400 - return P2pkhAddress.fromAddress(address: address, network: network);
2401 - } else if (P2shAddress.regex.hasMatch(address)) {
2402 - return P2shAddress.fromAddress(address: address, network: network);
2403 - } else if (P2wshAddress.regex.hasMatch(address)) {
2404 - return P2wshAddress.fromAddress(address: address, network: network);
2405 - } else if (P2trAddress.regex.hasMatch(address)) {
2406 - return P2trAddress.fromAddress(address: address, network: network);
2407 - } else if (SilentPaymentAddress.regex.hasMatch(address)) {
2408 - return SilentPaymentAddress.fromAddress(address);
2409 - } else {
2410 - return P2wpkhAddress.fromAddress(address: address, network: network);
2411 - }
2412 -}
2413 -
2441 BitcoinAddressType _getScriptType(BitcoinBaseAddress type) {
2442 if (type is P2pkhAddress) {
2443 return P2pkhAddressType.p2pkh;
cw_bitcoin/lib/litecoin_wallet.dart
+1 -1
@@ -301,7 +301,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
301
302 List<int> possibleRecoverIds = [0, 1];
303
304 - final baseAddress = addressTypeFromStr(address, network);
304 + final baseAddress = RegexUtils.addressTypeFromStr(address, network);
305
306 for (int recoveryId in possibleRecoverIds) {
307 final pubKey = sig.recoverPublicKey(messageHash, Curves.generatorSecp256k1, recoveryId);
cw_bitcoin/lib/pending_bitcoin_transaction.dart
+13
@@ -47,6 +47,19 @@ class PendingBitcoinTransaction with PendingTransaction {
47 @override
48 int? get outputCount => _tx.outputs.length;
49
50 + List<TxOutput> get outputs => _tx.outputs;
51 +
52 + bool get hasSilentPayment => _tx.hasSilentPayment;
53 +
54 + PendingChange? get change {
55 + try {
56 + final change = _tx.outputs.firstWhere((out) => out.isChange);
57 + return PendingChange(change.scriptPubKey.toAddress(), BtcUtils.fromSatoshi(change.amount));
58 + } catch (_) {
59 + return null;
60 + }
61 + }
62 +
63 final List<void Function(ElectrumTransactionInfo transaction)> _listeners;
64
65 @override
cw_bitcoin/lib/script_hash.dart deleted
-19
@@ -1,19 +0,0 @@
1 -import 'package:crypto/crypto.dart';
2 -import 'package:cw_bitcoin/address_to_output_script.dart';
3 -import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin;
4 -
5 -String scriptHash(String address, {required bitcoin.BasedUtxoNetwork network}) {
6 - final outputScript = addressToOutputScript(address, network);
7 - final parts = sha256.convert(outputScript).toString().split('');
8 - var res = '';
9 -
10 - for (var i = parts.length - 1; i >= 0; i--) {
11 - final char = parts[i];
12 - i--;
13 - final nextChar = parts[i];
14 - res += nextChar;
15 - res += char;
16 - }
17 -
18 - return res;
19 -}
cw_bitcoin/pubspec.lock
+2 -2
@@ -70,8 +70,8 @@ packages:
70 dependency: "direct overridden"
71 description:
72 path: "."
73 - ref: cake-update-v5
74 - resolved-ref: ff2b10eb27b0254ce4518d054332d97d77d9b380
73 + ref: cake-update-v7
74 + resolved-ref: bc49e3b1cba601828f8ddc3d016188d8c2499088
75 url: "https://github.com/cake-tech/bitcoin_base"
76 source: git
77 version: "4.7.0"
cw_bitcoin/pubspec.yaml
+1 -1
@@ -57,7 +57,7 @@ dependency_overrides:
57 bitcoin_base:
58 git:
59 url: https://github.com/cake-tech/bitcoin_base
60 - ref: cake-update-v5
60 + ref: cake-update-v7
61
62 # For information on the generic Dart part of this file, see the
63 # following page: https://dart.dev/tools/pub/pubspec
cw_bitcoin_cash/pubspec.yaml
+1 -1
@@ -42,7 +42,7 @@ dependency_overrides:
42 bitcoin_base:
43 git:
44 url: https://github.com/cake-tech/bitcoin_base
45 - ref: cake-update-v5
45 + ref: cake-update-v7
46
47 # For information on the generic Dart part of this file, see the
48 # following page: https://dart.dev/tools/pub/pubspec
cw_core/lib/get_height_by_date.dart
+10 -1
@@ -267,6 +267,16 @@ const bitcoinDates = {
267 "2023-01": 769810,
268 };
269
270 +Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
271 + final response = await http.get(
272 + Uri.parse(
273 + "http://mempool.cakewallet.com:8999/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}",
274 + ),
275 + );
276 +
277 + return jsonDecode(response.body)['height'] as int;
278 +}
279 +
280 int getBitcoinHeightByDate({required DateTime date}) {
281 String dateKey = '${date.year}-${date.month.toString().padLeft(2, '0')}';
282 final closestKey = bitcoinDates.keys
@@ -377,4 +387,3 @@ int getWowneroHeightByDate({required DateTime date}) {
387
388 return wowDates[closestKey] ?? 0;
389 }
380 -
cw_core/lib/pending_transaction.dart
+8
@@ -1,3 +1,10 @@
1 +class PendingChange {
2 + final String address;
3 + final String amount;
4 +
5 + PendingChange(this.address, this.amount);
6 +}
7 +
8 mixin PendingTransaction {
9 String get id;
10 String get amountFormatted;
@@ -5,6 +12,7 @@ mixin PendingTransaction {
12 String? feeRate;
13 String get hex;
14 int? get outputCount => null;
15 + PendingChange? change;
16
17 Future<void> commit();
18 }
cw_core/lib/sync_status.dart
+8
@@ -4,6 +4,9 @@ abstract class SyncStatus {
4 }
5
6 class StartingScanSyncStatus extends SyncStatus {
7 + StartingScanSyncStatus(this.beginHeight);
8 +
9 + final int beginHeight;
10 @override
11 double progress() => 0.0;
12 }
@@ -59,6 +62,11 @@ class AttemptingSyncStatus extends SyncStatus {
62 double progress() => 0.0;
63 }
64
65 +class AttemptingScanSyncStatus extends SyncStatus {
66 + @override
67 + double progress() => 0.0;
68 +}
69 +
70 class FailedSyncStatus extends NotConnectedSyncStatus {}
71
72 class ConnectingSyncStatus extends SyncStatus {
cw_nano/pubspec.lock
+2 -2
@@ -117,10 +117,10 @@ packages:
117 dependency: "direct overridden"
118 description:
119 name: build_runner_core
120 - sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e"
120 + sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
121 url: "https://pub.dev"
122 source: hosted
123 - version: "7.2.7+1"
123 + version: "7.2.7"
124 built_collection:
125 dependency: transitive
126 description:
lib/bitcoin/cw_bitcoin.dart
+46 -2
@@ -361,7 +361,7 @@ class CWBitcoin extends Bitcoin {
361 continue;
362 }
363
364 - final sh = scriptHash(address, network: network);
364 + final sh = BitcoinAddressUtils.scriptHash(address, network: network);
365 final history = await electrumClient.getHistory(sh);
366
367 final balance = await electrumClient.getBalance(sh);
@@ -522,7 +522,20 @@ class CWBitcoin extends Bitcoin {
522 }
523
524 @override
525 - int getHeightByDate({required DateTime date}) => getBitcoinHeightByDate(date: date);
525 + Future<bool> checkIfMempoolAPIIsEnabled(Object wallet) async {
526 + final bitcoinWallet = wallet as ElectrumWallet;
527 + return await bitcoinWallet.checkIfMempoolAPIIsEnabled();
528 + }
529 +
530 + @override
531 + Future<int> getHeightByDate({required DateTime date, bool? bitcoinMempoolAPIEnabled}) async {
532 + if (bitcoinMempoolAPIEnabled ?? false) {
533 + try {
534 + return await getBitcoinHeightByDateAPI(date: date);
535 + } catch (_) {}
536 + }
537 + return await getBitcoinHeightByDate(date: date);
538 + }
539
540 @override
541 Future<void> rescan(Object wallet, {required int height, bool? doSingleScan}) async {
@@ -547,4 +560,35 @@ class CWBitcoin extends Bitcoin {
560 final bitcoinWallet = wallet as ElectrumWallet;
561 await bitcoinWallet.updateFeeRates();
562 }
563 +
564 + @override
565 + List<Output> updateOutputs(PendingTransaction pendingTransaction, List<Output> outputs) {
566 + final pendingTx = pendingTransaction as PendingBitcoinTransaction;
567 +
568 + if (!pendingTx.hasSilentPayment) {
569 + return outputs;
570 + }
571 +
572 + final updatedOutputs = outputs.map((output) {
573 +
574 + try {
575 + final pendingOut = pendingTx!.outputs[outputs.indexOf(output)];
576 + final updatedOutput = output;
577 +
578 + updatedOutput.stealthAddress = P2trAddress.fromScriptPubkey(script: pendingOut.scriptPubKey)
579 + .toAddress(BitcoinNetwork.mainnet);
580 + return updatedOutput;
581 + } catch (_) {}
582 +
583 + return output;
584 + }).toList();
585 +
586 + return updatedOutputs;
587 + }
588 +
589 + @override
590 + bool txIsReceivedSilentPayment(TransactionInfo txInfo) {
591 + final tx = txInfo as ElectrumTransactionInfo;
592 + return tx.isReceivedSilentPayment;
593 + }
594 }
lib/core/address_validator.dart
+65 -56
@@ -5,32 +5,40 @@ import 'package:cake_wallet/solana/solana.dart';
5 import 'package:cw_core/crypto_currency.dart';
6 import 'package:cw_core/erc20_token.dart';
7
8 +const BEFORE_REGEX = '(^|\s)';
9 +const AFTER_REGEX = '(\$|\s)';
10 +
11 class AddressValidator extends TextValidator {
12 AddressValidator({required CryptoCurrency type})
13 : super(
14 errorMessage: S.current.error_text_address,
15 useAdditionalValidation: type == CryptoCurrency.btc
13 - ? (String txt) => validateAddress(address: txt, network: BitcoinNetwork.mainnet)
16 + ? (String txt) => BitcoinAddressUtils.validateAddress(
17 + address: txt,
18 + network: BitcoinNetwork.mainnet,
19 + )
20 : null,
21 pattern: getPattern(type),
22 length: getLength(type));
23
24 static String getPattern(CryptoCurrency type) {
25 + var pattern = "";
26 if (type is Erc20Token) {
20 - return '0x[0-9a-zA-Z]';
27 + pattern = '0x[0-9a-zA-Z]';
28 }
29 switch (type) {
30 case CryptoCurrency.xmr:
24 - return '^4[0-9a-zA-Z]{94}\$|^8[0-9a-zA-Z]{94}\$|^[0-9a-zA-Z]{106}\$';
31 + pattern = '4[0-9a-zA-Z]{94}|8[0-9a-zA-Z]{94}|[0-9a-zA-Z]{106}';
32 case CryptoCurrency.ada:
26 - return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
27 - '|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
33 + pattern = '[0-9a-zA-Z]{59}|[0-9a-zA-Z]{92}|[0-9a-zA-Z]{104}'
34 + '|[0-9a-zA-Z]{105}|addr1[0-9a-zA-Z]{98}';
35 case CryptoCurrency.btc:
29 - return '^${P2pkhAddress.regex.pattern}\$|^${P2shAddress.regex.pattern}\$|^${P2wpkhAddress.regex.pattern}\$|${P2trAddress.regex.pattern}\$|^${P2wshAddress.regex.pattern}\$|^${SilentPaymentAddress.regex.pattern}\$';
36 + pattern =
37 + '${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}';
38 case CryptoCurrency.nano:
31 - return '[0-9a-zA-Z_]';
39 + pattern = '[0-9a-zA-Z_]';
40 case CryptoCurrency.banano:
33 - return '[0-9a-zA-Z_]';
41 + pattern = '[0-9a-zA-Z_]';
42 case CryptoCurrency.usdc:
43 case CryptoCurrency.usdcpoly:
44 case CryptoCurrency.usdtPoly:
@@ -66,11 +74,11 @@ class AddressValidator extends TextValidator {
74 case CryptoCurrency.dydx:
75 case CryptoCurrency.steth:
76 case CryptoCurrency.shib:
69 - return '0x[0-9a-zA-Z]';
77 + pattern = '0x[0-9a-zA-Z]';
78 case CryptoCurrency.xrp:
71 - return '^[0-9a-zA-Z]{34}\$|^X[0-9a-zA-Z]{46}\$';
79 + pattern = '[0-9a-zA-Z]{34}|X[0-9a-zA-Z]{46}';
80 case CryptoCurrency.xhv:
73 - return '^hvx|hvi|hvs[0-9a-zA-Z]';
81 + pattern = 'hvx|hvi|hvs[0-9a-zA-Z]';
82 case CryptoCurrency.xag:
83 case CryptoCurrency.xau:
84 case CryptoCurrency.xaud:
@@ -92,40 +100,43 @@ class AddressValidator extends TextValidator {
100 case CryptoCurrency.dash:
101 case CryptoCurrency.eos:
102 case CryptoCurrency.wow:
95 - return '[0-9a-zA-Z]';
103 + pattern = '[0-9a-zA-Z]';
104 case CryptoCurrency.bch:
97 - 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}\$';
105 + pattern =
106 + '(?!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}';
107 case CryptoCurrency.bnb:
99 - return '[0-9a-zA-Z]';
108 + pattern = '[0-9a-zA-Z]';
109 case CryptoCurrency.ltc:
101 - return '^(?!(ltc|LTC)1)[0-9a-zA-Z]*\$|(^LTC1[A-Z0-9]*\$)|(^ltc1[a-z0-9]*\$)';
110 + pattern = '(?!(ltc|LTC)1)[0-9a-zA-Z]*|(LTC1[A-Z0-9]*)|(ltc1[a-z0-9]*)';
111 case CryptoCurrency.hbar:
103 - return '[0-9a-zA-Z.]';
112 + pattern = '[0-9a-zA-Z.]';
113 case CryptoCurrency.zaddr:
105 - return '^zs[0-9a-zA-Z]{75}';
114 + pattern = 'zs[0-9a-zA-Z]{75}';
115 case CryptoCurrency.zec:
107 - return '^t1[0-9a-zA-Z]{33}\$|^t3[0-9a-zA-Z]{33}\$';
116 + pattern = 't1[0-9a-zA-Z]{33}|t3[0-9a-zA-Z]{33}';
117 case CryptoCurrency.dcr:
109 - return 'D[ksecS]([0-9a-zA-Z])+';
118 + pattern = 'D[ksecS]([0-9a-zA-Z])+';
119 case CryptoCurrency.rvn:
111 - return '[Rr]([1-9a-km-zA-HJ-NP-Z]){33}';
120 + pattern = '[Rr]([1-9a-km-zA-HJ-NP-Z]){33}';
121 case CryptoCurrency.near:
113 - return '[0-9a-f]{64}';
122 + pattern = '[0-9a-f]{64}';
123 case CryptoCurrency.rune:
115 - return 'thor1[0-9a-z]{38}';
124 + pattern = 'thor1[0-9a-z]{38}';
125 case CryptoCurrency.scrt:
117 - return 'secret1[0-9a-z]{38}';
126 + pattern = 'secret1[0-9a-z]{38}';
127 case CryptoCurrency.stx:
119 - return 'S[MP][0-9a-zA-Z]+';
128 + pattern = 'S[MP][0-9a-zA-Z]+';
129 case CryptoCurrency.kmd:
121 - return 'R[0-9a-zA-Z]{33}';
130 + pattern = 'R[0-9a-zA-Z]{33}';
131 case CryptoCurrency.pivx:
123 - return 'D([1-9a-km-zA-HJ-NP-Z]){33}';
132 + pattern = 'D([1-9a-km-zA-HJ-NP-Z]){33}';
133 case CryptoCurrency.btcln:
125 - return '^(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)';
134 + pattern = '(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)';
135 default:
127 - return '[0-9a-zA-Z]';
136 + pattern = '[0-9a-zA-Z]';
137 }
138 +
139 + return '$BEFORE_REGEX$pattern$AFTER_REGEX';
140 }
141
142 static List<int>? getLength(CryptoCurrency type) {
@@ -266,56 +277,54 @@ class AddressValidator extends TextValidator {
277 }
278
279 static String? getAddressFromStringPattern(CryptoCurrency type) {
280 + String? pattern = null;
281 +
282 switch (type) {
283 case CryptoCurrency.xmr:
284 case CryptoCurrency.wow:
272 - return '([^0-9a-zA-Z]|^)4[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
273 - '|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
274 - '|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)';
285 + pattern = '4[0-9a-zA-Z]{94}'
286 + '|8[0-9a-zA-Z]{94}'
287 + '|[0-9a-zA-Z]{106}';
288 case CryptoCurrency.btc:
276 - return '([^0-9a-zA-Z]|^)([1mn][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2pkhAddress type
277 - '|([^0-9a-zA-Z]|^)([23][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2shAddress type
278 - '|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{25,39})([^0-9a-zA-Z]|\$)' //P2wpkhAddress type
279 - '|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type
280 - '|([^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
281 - '|${SilentPaymentAddress.regex.pattern}\$';
282 -
289 + pattern =
290 + '${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}';
291 case CryptoCurrency.ltc:
284 - return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
285 - '|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
286 - '|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)';
292 + pattern = '^L[a-zA-Z0-9]{26,33}'
293 + '|[LM][a-km-zA-HJ-NP-Z1-9]{26,33}'
294 + '|ltc[a-zA-Z0-9]{26,45}';
295 case CryptoCurrency.eth:
288 - return '0x[0-9a-zA-Z]{42}';
296 + pattern = '0x[0-9a-zA-Z]{42}';
297 case CryptoCurrency.maticpoly:
290 - return '0x[0-9a-zA-Z]{42}';
298 + pattern = '0x[0-9a-zA-Z]{42}';
299 case CryptoCurrency.nano:
292 - return 'nano_[0-9a-zA-Z]{60}';
300 + pattern = 'nano_[0-9a-zA-Z]{60}';
301 case CryptoCurrency.banano:
294 - return 'ban_[0-9a-zA-Z]{60}';
302 + pattern = 'ban_[0-9a-zA-Z]{60}';
303 case CryptoCurrency.bch:
296 - return 'bitcoincash:q[0-9a-zA-Z]{41}([^0-9a-zA-Z]|\$)'
297 - '|bitcoincash:q[0-9a-zA-Z]{42}([^0-9a-zA-Z]|\$)'
298 - '|([^0-9a-zA-Z]|^)q[0-9a-zA-Z]{41}([^0-9a-zA-Z]|\$)'
299 - '|([^0-9a-zA-Z]|^)q[0-9a-zA-Z]{42}([^0-9a-zA-Z]|\$)';
304 + pattern = '(bitcoincash:)?q[0-9a-zA-Z]{41,42}';
305 case CryptoCurrency.sol:
301 - return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
306 + pattern = '[1-9A-HJ-NP-Za-km-z]{43,44}';
307 case CryptoCurrency.trx:
303 - return '(T|t)[1-9A-HJ-NP-Za-km-z]{33}';
308 + pattern = '(T|t)[1-9A-HJ-NP-Za-km-z]{33}';
309 default:
310 if (type.tag == CryptoCurrency.eth.title) {
306 - return '0x[0-9a-zA-Z]{42}';
311 + pattern = '0x[0-9a-zA-Z]{42}';
312 }
313 if (type.tag == CryptoCurrency.maticpoly.tag) {
309 - return '0x[0-9a-zA-Z]{42}';
314 + pattern = '0x[0-9a-zA-Z]{42}';
315 }
316 if (type.tag == CryptoCurrency.sol.title) {
312 - return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
317 + pattern = '[1-9A-HJ-NP-Za-km-z]{43,44}';
318 }
319 if (type.tag == CryptoCurrency.trx.title) {
315 - return '(T|t)[1-9A-HJ-NP-Za-km-z]{33}';
320 + pattern = '(T|t)[1-9A-HJ-NP-Za-km-z]{33}';
321 }
322 + }
323
318 - return null;
324 + if (pattern != null) {
325 + return "$BEFORE_REGEX$pattern$AFTER_REGEX";
326 }
327 +
328 + return null;
329 }
330 }
lib/core/sync_status_title.dart
+5 -1
@@ -53,7 +53,11 @@ String syncStatusTitle(SyncStatus syncStatus) {
53 }
54
55 if (syncStatus is StartingScanSyncStatus) {
56 - return S.current.sync_status_starting_scan;
56 + return S.current.sync_status_starting_scan(syncStatus.beginHeight.toString());
57 + }
58 +
59 + if (syncStatus is AttemptingScanSyncStatus) {
60 + return S.current.sync_status_attempting_scan;
61 }
62
63 return '';
lib/entities/parse_address_from_domain.dart
+2 -3
@@ -51,7 +51,7 @@ class AddressResolver {
51 throw Exception('Unexpected token: $type for getAddressFromStringPattern');
52 }
53
54 - final match = RegExp(addressPattern).firstMatch(raw);
54 + final match = RegExp(addressPattern, multiLine: true).firstMatch(raw);
55 return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_|ban_'),
56 (Match match) {
57 String group = match.group(0)!;
@@ -213,8 +213,7 @@ class AddressResolver {
213 await NostrProfileHandler.processRelays(context, nostrProfile!, text);
214
215 if (nostrUserData != null) {
216 - String? addressFromBio = extractAddressByType(
217 - raw: nostrUserData.about, type: currency);
216 + String? addressFromBio = extractAddressByType(raw: nostrUserData.about, type: currency);
217 if (addressFromBio != null) {
218 return ParsedAddress.nostrAddress(
219 address: addressFromBio,
lib/src/screens/dashboard/pages/transactions_page.dart
+8 -4
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/src/screens/dashboard/widgets/anonpay_transaction_row.dart';
3 import 'package:cake_wallet/src/screens/dashboard/widgets/order_row.dart';
4 import 'package:cake_wallet/themes/extensions/placeholder_theme.dart';
@@ -52,7 +53,7 @@ class TransactionsPage extends StatelessWidget {
53 try {
54 final uri = Uri.parse(
55 "https://guides.cakewallet.com/docs/FAQ/why_are_my_funds_not_appearing/");
55 - launchUrl(uri, mode: LaunchMode.externalApplication);
56 + launchUrl(uri, mode: LaunchMode.externalApplication);
57 } catch (_) {}
58 },
59 title: S.of(context).syncing_wallet_alert_title,
@@ -84,7 +85,7 @@ class TransactionsPage extends StatelessWidget {
85
86 final transaction = item.transaction;
87 final transactionType = dashboardViewModel.type == WalletType.ethereum &&
87 - transaction.evmSignatureName == 'approval'
88 + transaction.evmSignatureName == 'approval'
89 ? ' (${transaction.evmSignatureName})'
90 : '';
91
@@ -100,8 +101,11 @@ class TransactionsPage extends StatelessWidget {
101 ? ''
102 : item.formattedFiatAmount,
103 isPending: transaction.isPending,
103 - title: item.formattedTitle +
104 - item.formattedStatus + ' $transactionType',
104 + title:
105 + item.formattedTitle + item.formattedStatus + ' $transactionType',
106 + isReceivedSilentPayment:
107 + dashboardViewModel.type == WalletType.bitcoin &&
108 + bitcoin!.txIsReceivedSilentPayment(transaction),
109 ),
110 );
111 }
lib/src/screens/dashboard/widgets/transaction_raw.dart
+80 -46
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cw_core/transaction_direction.dart';
@@ -5,14 +6,16 @@ import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
6 import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
7
8 class TransactionRow extends StatelessWidget {
8 - TransactionRow(
9 - {required this.direction,
10 - required this.formattedDate,
11 - required this.formattedAmount,
12 - required this.formattedFiatAmount,
13 - required this.isPending,
14 - required this.title,
15 - required this.onTap});
9 + TransactionRow({
10 + required this.direction,
11 + required this.formattedDate,
12 + required this.formattedAmount,
13 + required this.formattedFiatAmount,
14 + required this.isPending,
15 + required this.isReceivedSilentPayment,
16 + required this.title,
17 + required this.onTap,
18 + });
19
20 final VoidCallback onTap;
21 final TransactionDirection direction;
@@ -20,6 +23,7 @@ class TransactionRow extends StatelessWidget {
23 final String formattedAmount;
24 final String formattedFiatAmount;
25 final bool isPending;
26 + final bool isReceivedSilentPayment;
27 final String title;
28
29 @override
@@ -38,50 +42,80 @@ class TransactionRow extends StatelessWidget {
42 width: 36,
43 decoration: BoxDecoration(
44 shape: BoxShape.circle,
41 - color: Theme.of(context).extension<TransactionTradeTheme>()!.rowsColor
42 - ),
43 - child: Image.asset(
44 - direction == TransactionDirection.incoming
45 - ? 'assets/images/down_arrow.png'
46 - : 'assets/images/up_arrow.png'),
45 + color: Theme.of(context).extension<TransactionTradeTheme>()!.rowsColor),
46 + child: Image.asset(direction == TransactionDirection.incoming
47 + ? 'assets/images/down_arrow.png'
48 + : 'assets/images/up_arrow.png'),
49 ),
50 SizedBox(width: 12),
51 Expanded(
52 child: Column(
51 - mainAxisSize: MainAxisSize.min,
52 - children: [
53 - Row(
54 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
55 - children: <Widget>[
56 - Text(title,
57 - style: TextStyle(
58 - fontSize: 16,
59 - fontWeight: FontWeight.w500,
60 - color: Theme.of(context).extension<DashboardPageTheme>()!.textColor)),
61 - Text(formattedAmount,
62 - style: TextStyle(
63 - fontSize: 16,
64 - fontWeight: FontWeight.w500,
65 - color: Theme.of(context).extension<DashboardPageTheme>()!.textColor))
66 - ]),
67 - SizedBox(height: 5),
68 - Row(
69 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
70 - children: <Widget>[
71 - Text(formattedDate,
72 - style: TextStyle(
73 - fontSize: 14,
74 - color: Theme.of(context).extension<CakeTextTheme>()!.dateSectionRowColor)),
75 - Text(formattedFiatAmount,
76 - style: TextStyle(
77 - fontSize: 14,
78 - color: Theme.of(context).extension<CakeTextTheme>()!.dateSectionRowColor))
79 - ])
80 - ],
81 - )
82 - )
53 + mainAxisSize: MainAxisSize.min,
54 + children: [
55 + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[
56 + Row(
57 + children: [
58 + Text(title,
59 + style: TextStyle(
60 + fontSize: 16,
61 + fontWeight: FontWeight.w500,
62 + color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
63 + )),
64 + if (isReceivedSilentPayment) TxTag(tag: S.of(context).silent_payment),
65 + ],
66 + ),
67 + Text(formattedAmount,
68 + style: TextStyle(
69 + fontSize: 16,
70 + fontWeight: FontWeight.w500,
71 + color: Theme.of(context).extension<DashboardPageTheme>()!.textColor))
72 + ]),
73 + SizedBox(height: 5),
74 + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[
75 + Text(formattedDate,
76 + style: TextStyle(
77 + fontSize: 14,
78 + color:
79 + Theme.of(context).extension<CakeTextTheme>()!.dateSectionRowColor)),
80 + Text(formattedFiatAmount,
81 + style: TextStyle(
82 + fontSize: 14,
83 + color:
84 + Theme.of(context).extension<CakeTextTheme>()!.dateSectionRowColor))
85 + ])
86 + ],
87 + ))
88 ],
89 ),
90 ));
91 }
92 }
93 +
94 +// A tag to add context to a transaction
95 +// example use: differ silent payments from regular txs
96 +class TxTag extends StatelessWidget {
97 + TxTag({required this.tag});
98 +
99 + final String tag;
100 +
101 + @override
102 + Widget build(BuildContext context) {
103 + return Container(
104 + height: 17,
105 + padding: EdgeInsets.only(left: 6, right: 6),
106 + decoration: BoxDecoration(
107 + borderRadius: BorderRadius.all(Radius.circular(8.5)),
108 + color: Theme.of(context).extension<TransactionTradeTheme>()!.rowsColor,
109 + ),
110 + alignment: Alignment.center,
111 + child: Text(
112 + tag.toLowerCase(),
113 + style: TextStyle(
114 + color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
115 + fontSize: 9,
116 + fontWeight: FontWeight.w600,
117 + ),
118 + ),
119 + );
120 + }
121 +}
lib/src/screens/rescan/rescan_page.dart
+1
@@ -37,6 +37,7 @@ class RescanPage extends BasePage {
37 toggleSingleScan: () =>
38 _rescanViewModel.doSingleScan = !_rescanViewModel.doSingleScan,
39 walletType: _rescanViewModel.wallet.type,
40 + bitcoinMempoolAPIEnabled: _rescanViewModel.isBitcoinMempoolAPIEnabled,
41 )),
42 Observer(
43 builder: (_) => LoadingPrimaryButton(
lib/src/screens/send/send_page.dart
+25 -25
@@ -68,11 +68,11 @@ class SendPage extends BasePage {
68
69 @override
70 Function(BuildContext)? get pushToNextWidget => (context) {
71 - FocusScopeNode currentFocus = FocusScope.of(context);
72 - if (!currentFocus.hasPrimaryFocus) {
73 - currentFocus.focusedChild?.unfocus();
74 - }
75 - };
71 + FocusScopeNode currentFocus = FocusScope.of(context);
72 + if (!currentFocus.hasPrimaryFocus) {
73 + currentFocus.focusedChild?.unfocus();
74 + }
75 + };
76
77 @override
78 Widget? leading(BuildContext context) {
@@ -212,26 +212,25 @@ class SendPage extends BasePage {
212 final count = sendViewModel.outputs.length;
213
214 return count > 1
215 - ? Semantics (
216 - label: 'Page Indicator',
217 - hint: 'Swipe to change receiver',
218 - excludeSemantics: true,
219 - child:
220 - SmoothPageIndicator(
221 - controller: controller,
222 - count: count,
223 - effect: ScrollingDotsEffect(
224 - spacing: 6.0,
225 - radius: 6.0,
226 - dotWidth: 6.0,
227 - dotHeight: 6.0,
228 - dotColor: Theme.of(context)
229 - .extension<SendPageTheme>()!
230 - .indicatorDotColor,
231 - activeDotColor: Theme.of(context)
232 - .extension<SendPageTheme>()!
233 - .templateBackgroundColor),
234 - ))
215 + ? Semantics(
216 + label: 'Page Indicator',
217 + hint: 'Swipe to change receiver',
218 + excludeSemantics: true,
219 + child: SmoothPageIndicator(
220 + controller: controller,
221 + count: count,
222 + effect: ScrollingDotsEffect(
223 + spacing: 6.0,
224 + radius: 6.0,
225 + dotWidth: 6.0,
226 + dotHeight: 6.0,
227 + dotColor: Theme.of(context)
228 + .extension<SendPageTheme>()!
229 + .indicatorDotColor,
230 + activeDotColor: Theme.of(context)
231 + .extension<SendPageTheme>()!
232 + .templateBackgroundColor),
233 + ))
234 : Offstage();
235 },
236 ),
@@ -478,6 +477,7 @@ class SendPage extends BasePage {
477 feeValue: sendViewModel.pendingTransaction!.feeFormatted,
478 feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
479 outputs: sendViewModel.outputs,
480 + change: sendViewModel.pendingTransaction!.change,
481 rightButtonText: S.of(_dialogContext).send,
482 leftButtonText: S.of(_dialogContext).cancel,
483 actionRightButton: () async {
lib/src/screens/send/widgets/confirm_sending_alert.dart
+133 -92
@@ -1,6 +1,7 @@
1 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 import 'package:cake_wallet/palette.dart';
3 import 'package:cake_wallet/view_model/send/output.dart';
4 +import 'package:cw_core/pending_transaction.dart';
5 import 'package:flutter/material.dart';
6 import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
7 import 'package:cake_wallet/generated/i18n.dart';
@@ -21,6 +22,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
22 required this.feeValue,
23 required this.feeFiatAmount,
24 required this.outputs,
25 + this.change,
26 required this.leftButtonText,
27 required this.rightButtonText,
28 required this.actionLeftButton,
@@ -44,6 +46,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
46 final String feeValue;
47 final String feeFiatAmount;
48 final List<Output> outputs;
49 + final PendingChange? change;
50 final String leftButtonText;
51 final String rightButtonText;
52 final VoidCallback actionLeftButton;
@@ -101,6 +104,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
104 feeValue: feeValue,
105 feeFiatAmount: feeFiatAmount,
106 outputs: outputs,
107 + change: change,
108 onDispose: onDispose);
109 }
110
@@ -117,6 +121,7 @@ class ConfirmSendingAlertContent extends StatefulWidget {
121 required this.feeValue,
122 required this.feeFiatAmount,
123 required this.outputs,
124 + this.change,
125 required this.onDispose}) {}
126
127 final String? paymentId;
@@ -130,6 +135,7 @@ class ConfirmSendingAlertContent extends StatefulWidget {
135 final String feeValue;
136 final String feeFiatAmount;
137 final List<Output> outputs;
138 + final PendingChange? change;
139 final Function? onDispose;
140
141 @override
@@ -145,6 +151,7 @@ class ConfirmSendingAlertContent extends StatefulWidget {
151 feeValue: feeValue,
152 feeFiatAmount: feeFiatAmount,
153 outputs: outputs,
154 + change: change,
155 onDispose: onDispose);
156 }
157
@@ -161,6 +168,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
168 required this.feeValue,
169 required this.feeFiatAmount,
170 required this.outputs,
171 + this.change,
172 this.onDispose})
173 : recipientTitle = '' {
174 recipientTitle = outputs.length > 1
@@ -179,6 +187,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
187 final String feeValue;
188 final String feeFiatAmount;
189 final List<Output> outputs;
190 + final PendingChange? change;
191 final Function? onDispose;
192
193 final double backgroundHeight = 160;
@@ -391,100 +400,57 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
400 decoration: TextDecoration.none,
401 ),
402 ),
394 - outputs.length > 1
395 - ? ListView.builder(
396 - padding: EdgeInsets.only(top: 0),
397 - shrinkWrap: true,
398 - physics: NeverScrollableScrollPhysics(),
399 - itemCount: outputs.length,
400 - itemBuilder: (context, index) {
401 - final item = outputs[index];
402 - final _address =
403 - item.isParsedAddress ? item.extractedAddress : item.address;
404 - final _amount = item.cryptoAmount.replaceAll(',', '.');
405 -
406 - return Column(
407 - children: [
408 - if (item.isParsedAddress)
409 - Padding(
410 - padding: EdgeInsets.only(top: 8),
411 - child: Text(
412 - item.parsedAddress.name,
413 - textAlign: TextAlign.center,
414 - style: TextStyle(
415 - fontSize: 14,
416 - fontWeight: FontWeight.w600,
417 - fontFamily: 'Lato',
418 - color: PaletteDark.pigeonBlue,
419 - decoration: TextDecoration.none,
420 - ),
421 - )),
422 - Padding(
423 - padding: EdgeInsets.only(top: 8),
424 - child: Text(
425 - _address,
426 - style: TextStyle(
427 - fontSize: 10,
428 - fontWeight: FontWeight.w600,
429 - fontFamily: 'Lato',
430 - color: PaletteDark.pigeonBlue,
431 - decoration: TextDecoration.none,
432 - ),
433 - )),
434 - Padding(
435 - padding: EdgeInsets.only(top: 8),
436 - child: Row(
437 - mainAxisSize: MainAxisSize.max,
438 - mainAxisAlignment: MainAxisAlignment.end,
439 - children: [
440 - Text(
441 - _amount,
442 - style: TextStyle(
443 - fontSize: 10,
444 - fontWeight: FontWeight.w600,
445 - fontFamily: 'Lato',
446 - color: PaletteDark.pigeonBlue,
447 - decoration: TextDecoration.none,
448 - ),
449 - )
450 - ],
451 - ))
452 - ],
453 - );
454 - })
455 - : Column(children: [
456 - if (outputs.first.isParsedAddress)
457 - Padding(
458 - padding: EdgeInsets.only(top: 8),
459 - child: Text(
460 - outputs.first.parsedAddress.name,
461 - textAlign: TextAlign.center,
462 - style: TextStyle(
463 - fontSize: 14,
464 - fontWeight: FontWeight.w600,
465 - fontFamily: 'Lato',
466 - color: PaletteDark.pigeonBlue,
467 - decoration: TextDecoration.none,
468 - ),
469 - )),
470 - Padding(
471 - padding: EdgeInsets.only(top: 8),
472 - child: Text(
473 - outputs.first.isParsedAddress
474 - ? outputs.first.extractedAddress
475 - : outputs.first.address,
476 - style: TextStyle(
477 - fontSize: 10,
478 - fontWeight: FontWeight.w600,
479 - fontFamily: 'Lato',
480 - color: PaletteDark.pigeonBlue,
481 - decoration: TextDecoration.none,
482 - ),
483 - )),
484 - ])
403 + ListView.builder(
404 + padding: EdgeInsets.only(top: 0),
405 + shrinkWrap: true,
406 + physics: NeverScrollableScrollPhysics(),
407 + itemCount: outputs.length,
408 + itemBuilder: (context, index) {
409 + final item = outputs[index];
410 + final _address =
411 + item.isParsedAddress ? item.extractedAddress : item.address;
412 + final _amount = item.cryptoAmount.replaceAll(',', '.');
413 +
414 + return Column(
415 + children: [
416 + if (item.isParsedAddress)
417 + AddressText(text: item.parsedAddress.name),
418 + AddressText(text: _address, fontSize: 10),
419 + if (stealthAddressText(item.stealthAddress) != null)
420 + AddressText(
421 + text: stealthAddressText(item.stealthAddress)!, fontSize: 10),
422 + AmountText(text: _amount),
423 + ],
424 + );
425 + },
426 + )
427 ],
428 ),
487 - )
429 + ),
430 + if (change != null)
431 + Padding(
432 + padding: EdgeInsets.only(top: 16),
433 + child: Column(
434 + children: [
435 + Text(
436 + S.of(context).send_change_to_you,
437 + style: TextStyle(
438 + fontSize: 16,
439 + fontWeight: FontWeight.normal,
440 + fontFamily: 'Lato',
441 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
442 + decoration: TextDecoration.none,
443 + ),
444 + ),
445 + Column(
446 + children: [
447 + AddressText(text: change!.address, fontSize: 10),
448 + AmountText(text: change!.amount),
449 + ],
450 + )
451 + ],
452 + ),
453 + )
454 ],
455 ))),
456 if (showScrollbar)
@@ -539,3 +505,78 @@ class ExpirationTimeWidget extends StatelessWidget {
505 );
506 }
507 }
508 +
509 +class AddressText extends StatelessWidget {
510 + final String text;
511 + final double fontSize;
512 + final FontWeight fontWeight;
513 + final TextAlign? textAlign;
514 +
515 + const AddressText({
516 + required this.text,
517 + this.fontSize = 14,
518 + this.fontWeight = FontWeight.w600,
519 + this.textAlign,
520 + });
521 +
522 + @override
523 + Widget build(BuildContext context) {
524 + return Padding(
525 + padding: EdgeInsets.only(top: 8),
526 + child: Text(
527 + text,
528 + style: TextStyle(
529 + fontSize: fontSize,
530 + fontWeight: fontWeight,
531 + fontFamily: 'Lato',
532 + color: PaletteDark.pigeonBlue,
533 + decoration: TextDecoration.none,
534 + ),
535 + ),
536 + );
537 + }
538 +}
539 +
540 +class AmountText extends StatelessWidget {
541 + final String text;
542 + final double fontSize;
543 + final FontWeight fontWeight;
544 + final TextAlign? textAlign;
545 +
546 + const AmountText({
547 + required this.text,
548 + this.fontSize = 10,
549 + this.fontWeight = FontWeight.w600,
550 + this.textAlign,
551 + });
552 +
553 + @override
554 + Widget build(BuildContext context) {
555 + return Padding(
556 + padding: EdgeInsets.only(top: 8),
557 + child: Row(
558 + mainAxisSize: MainAxisSize.max,
559 + mainAxisAlignment: MainAxisAlignment.end,
560 + children: [
561 + Text(
562 + text,
563 + style: TextStyle(
564 + fontSize: fontSize,
565 + fontWeight: fontWeight,
566 + fontFamily: 'Lato',
567 + color: PaletteDark.pigeonBlue,
568 + decoration: TextDecoration.none,
569 + ),
570 + )
571 + ],
572 + ));
573 + }
574 +}
575 +
576 +String? stealthAddressText(String? stealthAddress) {
577 + if (stealthAddress == null) {
578 + return null;
579 + }
580 +
581 + return stealthAddress.isNotEmpty ? "-> $stealthAddress" : null;
582 +}
lib/src/screens/settings/privacy_page.dart
+13 -13
@@ -58,8 +58,8 @@ class PrivacyPage extends BasePage {
58 if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
59 SettingsSwitcherCell(
60 title: _privacySettingsViewModel.isMoneroWallet
61 - ? S.current.auto_generate_subaddresses
62 - : S.current.auto_generate_addresses,
61 + ? S.current.auto_generate_subaddresses
62 + : S.current.auto_generate_addresses,
63 value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
64 onValueChange: (BuildContext _, bool value) {
65 _privacySettingsViewModel.setAutoGenerateSubaddresses(value);
@@ -115,21 +115,21 @@ class PrivacyPage extends BasePage {
115 ),
116 if (_privacySettingsViewModel.canUseMempoolFeeAPI)
117 SettingsSwitcherCell(
118 - title: S.current.live_fee_rates,
118 + title: S.current.enable_mempool_api,
119 value: _privacySettingsViewModel.useMempoolFeeAPI,
120 onValueChange: (BuildContext _, bool isEnabled) async {
121 if (!isEnabled) {
122 final bool confirmation = await showPopUp<bool>(
123 - context: context,
124 - builder: (BuildContext context) {
125 - return AlertWithTwoActions(
126 - alertTitle: S.of(context).warning,
127 - alertContent: S.of(context).disable_fee_api_warning,
128 - rightButtonText: S.of(context).confirm,
129 - leftButtonText: S.of(context).cancel,
130 - actionRightButton: () => Navigator.of(context).pop(true),
131 - actionLeftButton: () => Navigator.of(context).pop(false));
132 - }) ??
123 + context: context,
124 + builder: (BuildContext context) {
125 + return AlertWithTwoActions(
126 + alertTitle: S.of(context).warning,
127 + alertContent: S.of(context).disable_fee_api_warning,
128 + rightButtonText: S.of(context).confirm,
129 + leftButtonText: S.of(context).cancel,
130 + actionRightButton: () => Navigator.of(context).pop(true),
131 + actionLeftButton: () => Navigator.of(context).pop(false));
132 + }) ??
133 false;
134 if (confirmation) {
135 _privacySettingsViewModel.setUseMempoolFeeAPI(isEnabled);
lib/src/widgets/blockchain_height_widget.dart
+11 -3
@@ -20,6 +20,7 @@ class BlockchainHeightWidget extends StatefulWidget {
20 this.isSilentPaymentsScan = false,
21 this.toggleSingleScan,
22 this.doSingleScan = false,
23 + this.bitcoinMempoolAPIEnabled,
24 required this.walletType,
25 }) : super(key: key);
26
@@ -29,6 +30,7 @@ class BlockchainHeightWidget extends StatefulWidget {
30 final bool hasDatePicker;
31 final bool isSilentPaymentsScan;
32 final bool doSingleScan;
33 + final Future<bool>? bitcoinMempoolAPIEnabled;
34 final Function()? toggleSingleScan;
35 final WalletType walletType;
36
@@ -79,7 +81,8 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
81 child: BaseTextFormField(
82 focusNode: widget.focusNode,
83 controller: restoreHeightController,
82 - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
84 + keyboardType:
85 + TextInputType.numberWithOptions(signed: false, decimal: false),
86 hintText: widget.isSilentPaymentsScan
87 ? S.of(context).silent_payments_scan_from_height
88 : S.of(context).widgets_restore_from_blockheight,
@@ -146,7 +149,9 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
149 : S.of(context).restore_from_date_or_blockheight,
150 textAlign: TextAlign.center,
151 style: TextStyle(
149 - fontSize: 12, fontWeight: FontWeight.normal, color: Theme.of(context).hintColor),
152 + fontSize: 12,
153 + fontWeight: FontWeight.normal,
154 + color: Theme.of(context).hintColor),
155 ),
156 )
157 ]
@@ -166,7 +171,10 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
171 if (date != null) {
172 int height;
173 if (widget.isSilentPaymentsScan) {
169 - height = bitcoin!.getHeightByDate(date: date);
174 + height = await bitcoin!.getHeightByDate(
175 + date: date,
176 + bitcoinMempoolAPIEnabled: await widget.bitcoinMempoolAPIEnabled,
177 + );
178 } else {
179 if (widget.walletType == WalletType.monero) {
180 height = monero!.getHeightByDate(date: date);
lib/store/dashboard/transaction_filter_store.dart
+34 -25
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/bitcoin/bitcoin.dart';
2 import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
3 import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
4 import 'package:mobx/mobx.dart';
@@ -6,12 +7,13 @@ import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
7
8 part 'transaction_filter_store.g.dart';
9
9 -class TransactionFilterStore = TransactionFilterStoreBase
10 - with _$TransactionFilterStore;
10 +class TransactionFilterStore = TransactionFilterStoreBase with _$TransactionFilterStore;
11
12 abstract class TransactionFilterStoreBase with Store {
13 - TransactionFilterStoreBase() : displayIncoming = true,
14 - displayOutgoing = true;
13 + TransactionFilterStoreBase()
14 + : displayIncoming = true,
15 + displayOutgoing = true,
16 + displaySilentPayments = true;
17
18 @observable
19 bool displayIncoming;
@@ -19,6 +21,9 @@ abstract class TransactionFilterStoreBase with Store {
21 @observable
22 bool displayOutgoing;
23
24 + @observable
25 + bool displaySilentPayments;
26 +
27 @observable
28 DateTime? startDate;
29
@@ -26,31 +31,36 @@ abstract class TransactionFilterStoreBase with Store {
31 DateTime? endDate;
32
33 @computed
29 - bool get displayAll => displayIncoming && displayOutgoing;
34 + bool get displayAll => displayIncoming && displayOutgoing && displaySilentPayments;
35
36 @action
37 void toggleAll() {
38 if (displayAll) {
39 displayOutgoing = false;
40 displayIncoming = false;
41 + displaySilentPayments = false;
42 } else {
43 displayOutgoing = true;
44 displayIncoming = true;
45 + displaySilentPayments = true;
46 }
47 }
48
42 -
49 @action
50 void toggleIncoming() {
51 displayIncoming = !displayIncoming;
52 }
53
48 -
54 @action
55 void toggleOutgoing() {
56 displayOutgoing = !displayOutgoing;
57 }
58
59 + @action
60 + void toggleSilentPayments() {
61 + displaySilentPayments = !displaySilentPayments;
62 + }
63 +
64 @action
65 void changeStartDate(DateTime date) => startDate = date;
66
@@ -59,34 +69,33 @@ abstract class TransactionFilterStoreBase with Store {
69
70 List<ActionListItem> filtered({required List<ActionListItem> transactions}) {
71 var _transactions = <ActionListItem>[];
62 - final needToFilter = !displayAll ||
63 - (startDate != null && endDate != null);
72 + final needToFilter = !displayAll || (startDate != null && endDate != null);
73
74 if (needToFilter) {
75 _transactions = transactions.where((item) {
76 var allowed = true;
77
78 if (allowed && startDate != null && endDate != null) {
70 - if(item is TransactionListItem){
71 - allowed = (startDate?.isBefore(item.transaction.date) ?? false)
72 - && (endDate?.isAfter(item.transaction.date) ?? false);
73 - }else if(item is AnonpayTransactionListItem){
74 - allowed = (startDate?.isBefore(item.transaction.createdAt) ?? false)
75 - && (endDate?.isAfter(item.transaction.createdAt) ?? false);
76 - }
79 + if (item is TransactionListItem) {
80 + allowed = (startDate?.isBefore(item.transaction.date) ?? false) &&
81 + (endDate?.isAfter(item.transaction.date) ?? false);
82 + } else if (item is AnonpayTransactionListItem) {
83 + allowed = (startDate?.isBefore(item.transaction.createdAt) ?? false) &&
84 + (endDate?.isAfter(item.transaction.createdAt) ?? false);
85 + }
86 }
87
88 if (allowed && (!displayAll)) {
80 - if(item is TransactionListItem){
81 - allowed = (displayOutgoing &&
82 - item.transaction.direction ==
83 - TransactionDirection.outgoing) ||
84 - (displayIncoming &&
85 - item.transaction.direction == TransactionDirection.incoming);
86 - } else if(item is AnonpayTransactionListItem){
89 + if (item is TransactionListItem) {
90 + allowed =
91 + (displayOutgoing && item.transaction.direction == TransactionDirection.outgoing) ||
92 + (displayIncoming &&
93 + item.transaction.direction == TransactionDirection.incoming &&
94 + !bitcoin!.txIsReceivedSilentPayment(item.transaction)) ||
95 + (displaySilentPayments && bitcoin!.txIsReceivedSilentPayment(item.transaction));
96 + } else if (item is AnonpayTransactionListItem) {
97 allowed = displayIncoming;
98 }
89 -
99 }
100
101 return allowed;
@@ -97,4 +106,4 @@ abstract class TransactionFilterStoreBase with Store {
106
107 return _transactions;
108 }
100 -}
\ No newline at end of file
109 +}
lib/view_model/dashboard/dashboard_view_model.dart
+11 -3
@@ -88,6 +88,11 @@ abstract class DashboardViewModelBase with Store {
88 value: () => transactionFilterStore.displayOutgoing,
89 caption: S.current.outgoing,
90 onChanged: transactionFilterStore.toggleOutgoing),
91 + FilterItem(
92 + value: () => transactionFilterStore.displaySilentPayments,
93 + caption: S.current.silent_payments,
94 + onChanged: transactionFilterStore.toggleSilentPayments,
95 + ),
96 // FilterItem(
97 // value: () => false,
98 // caption: S.current.transactions_by_date,
@@ -376,12 +381,15 @@ abstract class DashboardViewModelBase with Store {
381 // to not cause work duplication, this will do the job as well, it will be slightly less precise
382 // about what happened - but still enough.
383 // if (keys['privateSpendKey'] == List.generate(64, (index) => "0").join("")) "Private spend key is 0",
379 - if (keys['privateViewKey'] == List.generate(64, (index) => "0").join("")) "private view key is 0",
384 + if (keys['privateViewKey'] == List.generate(64, (index) => "0").join(""))
385 + "private view key is 0",
386 // if (keys['publicSpendKey'] == List.generate(64, (index) => "0").join("")) "public spend key is 0",
381 - if (keys['publicViewKey'] == List.generate(64, (index) => "0").join("")) "public view key is 0",
387 + if (keys['publicViewKey'] == List.generate(64, (index) => "0").join(""))
388 + "public view key is 0",
389 // if (wallet.seed == null) "wallet seed is null",
390 // if (wallet.seed == "") "wallet seed is empty",
384 - if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address == "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4")
391 + if (monero!.getSubaddressList(wallet).getAll(wallet)[0].address ==
392 + "41d7FXjswpK1111111111111111111111111111111111111111111111111111111111111111111111111111112KhNi4")
393 "primary address is invalid, you won't be able to receive / spend funds",
394 ];
395 return errors;
lib/view_model/rescan_view_model.dart
+4
@@ -29,6 +29,10 @@ abstract class RescanViewModelBase with Store {
29 @computed
30 bool get isSilentPaymentsScan => wallet.type == WalletType.bitcoin;
31
32 + @computed
33 + Future<bool> get isBitcoinMempoolAPIEnabled async =>
34 + wallet.type == WalletType.bitcoin && await bitcoin!.checkIfMempoolAPIIsEnabled(wallet);
35 +
36 @action
37 Future<void> rescanCurrentWallet({required int restoreHeight}) async {
38 state = RescanWalletState.rescaning;
lib/view_model/send/output.dart
+11 -8
@@ -79,6 +79,9 @@ abstract class OutputBase with Store {
79 bool get isParsedAddress =>
80 parsedAddress.parseFrom != ParseFrom.notParsed && parsedAddress.name.isNotEmpty;
81
82 + @observable
83 + String? stealthAddress;
84 +
85 @computed
86 int get formattedCryptoAmount {
87 int amount = 0;
@@ -134,9 +137,8 @@ abstract class OutputBase with Store {
137 final trc20EstimatedFee = tron!.getTronTRC20EstimatedFee(_wallet) ?? 0;
138 return double.parse(trc20EstimatedFee.toString());
139 }
137 -
140 }
139 -
141 +
142 if (_wallet.type == WalletType.solana) {
143 return solana!.getEstimateFees(_wallet) ?? 0.0;
144 }
@@ -145,16 +147,16 @@ abstract class OutputBase with Store {
147 _settingsStore.priority[_wallet.type]!, formattedCryptoAmount);
148
149 if (_wallet.type == WalletType.bitcoin) {
148 - if (_settingsStore.priority[_wallet.type] == bitcoin!.getBitcoinTransactionPriorityCustom()) {
149 - fee = bitcoin!.getEstimatedFeeWithFeeRate(_wallet,
150 - _settingsStore.customBitcoinFeeRate,formattedCryptoAmount);
150 + if (_settingsStore.priority[_wallet.type] ==
151 + bitcoin!.getBitcoinTransactionPriorityCustom()) {
152 + fee = bitcoin!.getEstimatedFeeWithFeeRate(
153 + _wallet, _settingsStore.customBitcoinFeeRate, formattedCryptoAmount);
154 }
155
156 return bitcoin!.formatterBitcoinAmountToDouble(amount: fee);
157 }
158
156 - if (_wallet.type == WalletType.litecoin ||
157 - _wallet.type == WalletType.bitcoinCash) {
159 + if (_wallet.type == WalletType.litecoin || _wallet.type == WalletType.bitcoinCash) {
160 return bitcoin!.formatterBitcoinAmountToDouble(amount: fee);
161 }
162
@@ -249,7 +251,8 @@ abstract class OutputBase with Store {
251 try {
252 final fiat = calculateFiatAmount(
253 price: _fiatConversationStore.prices[cryptoCurrencyHandler()]!,
252 - cryptoAmount: sendAll ? cryptoFullBalance.replaceAll(",", ".") : cryptoAmount.replaceAll(',', '.'));
254 + cryptoAmount:
255 + sendAll ? cryptoFullBalance.replaceAll(",", ".") : cryptoAmount.replaceAll(',', '.'));
256 if (fiatAmount != fiat) {
257 fiatAmount = fiat;
258 }
lib/view_model/send/send_view_model.dart
+9 -2
@@ -375,6 +375,15 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
375 throw Exception("THORChain does not support Taproot addresses");
376 }
377 }
378 +
379 + if (wallet.type == WalletType.bitcoin) {
380 + final updatedOutputs = bitcoin!.updateOutputs(pendingTransaction!, outputs);
381 +
382 + if (outputs.length == updatedOutputs.length) {
383 + outputs = ObservableList.of(updatedOutputs);
384 + }
385 + }
386 +
387 state = ExecutedSuccessfullyState();
388 return pendingTransaction;
389 } catch (e) {
@@ -414,8 +423,6 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
423 }
424
425 Future<void> _executeReplaceByFee(TransactionInfo tx, String newFee) async {
417 -
418 -
426 clearOutputs();
427 final output = outputs.first;
428 output.address = tx.outputAddresses?.first ?? '';
pubspec_base.yaml
+2 -2
@@ -100,7 +100,7 @@ dependencies:
100 bitcoin_base:
101 git:
102 url: https://github.com/cake-tech/bitcoin_base
103 - ref: cake-update-v5
103 + ref: cake-update-v7
104 ledger_flutter: ^1.0.1
105 hashlib: ^1.19.2
106
@@ -138,7 +138,7 @@ dependency_overrides:
138 bitcoin_base:
139 git:
140 url: https://github.com/cake-tech/bitcoin_base
141 - ref: cake-update-v5
141 + ref: cake-update-v7
142
143 flutter_icons:
144 image_path: "assets/images/app_logo.png"
res/values/strings_ar.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "تحرير الرمز المميز",
233 "electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل",
234 "email_address": "عنوان البريد الالكترونى",
235 + "enable_mempool_api": "MEMPOOL API للحصول على رسوم وتواريخ دقيقة",
236 "enable_replace_by_fee": "تمكين الاستبدال",
236 - "enable_silent_payments_scanning": "تمكين المسح الضوئي للمدفوعات الصامتة",
237 + "enable_silent_payments_scanning": "ابدأ في مسح المدفوعات الصامتة ، حتى يتم الوصول إلى الطرف",
238 "enabled": "ممكنة",
239 "enter_amount": "أدخل المبلغ",
240 "enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا",
@@ -295,6 +296,7 @@
296 "failed_authentication": "${state_error} فشل المصادقة.",
297 "faq": "الأسئلة الشائعة",
298 "features": "سمات",
299 + "fee_rate": "معدل الرسوم",
300 "fetching": "جار الجلب",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "الرصيد فيات",
@@ -610,6 +612,7 @@
612 "send": "إرسال",
613 "send_address": "عنوان ${cryptoCurrency}",
614 "send_amount": "مقدار:",
615 + "send_change_to_you": "تغيير لك:",
616 "send_creating_transaction": " يتم إنشاء المعاملة",
617 "send_error_currency": "العملة يجب أن تحتوي على أرقام فقط",
618 "send_error_minimum_value": "الحد الأدنى لقيمة المبلغ هو 0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "التوقيع غير صالح للرسالة المقدمة",
680 "signTransaction": " ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ",
681 "signup_for_card_accept_terms": "قم بالتسجيل للحصول على البطاقة وقبول الشروط.",
682 + "silent_payment": "الدفع الصامت",
683 "silent_payments": "مدفوعات صامتة",
684 "silent_payments_always_scan": "حدد المدفوعات الصامتة دائمًا المسح الضوئي",
685 "silent_payments_disclaimer": "العناوين الجديدة ليست هويات جديدة. إنها إعادة استخدام هوية موجودة مع ملصق مختلف.",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ",
713 "symbol": "ﺰﻣﺭ",
714 "sync_all_wallets": "مزامنة جميع المحافظ",
715 + "sync_status_attempting_scan": "محاولة المسح",
716 "sync_status_attempting_sync": "جاري محاولة المزامنة",
717 "sync_status_connected": "متصل",
718 "sync_status_connecting": "يتم التوصيل",
719 "sync_status_failed_connect": "انقطع الاتصال",
720 "sync_status_not_connected": "غير متصل",
716 - "sync_status_starting_scan": "بدء المسح",
721 + "sync_status_starting_scan": "بدء المسح الضوئي (من ${height})",
722 "sync_status_starting_sync": "بدء المزامنة",
723 "sync_status_syncronized": "متزامن",
724 "sync_status_syncronizing": "يتم المزامنة",
res/values/strings_bg.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Редактиране на токена",
233 "electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят",
234 "email_address": "Имейл адрес",
235 + "enable_mempool_api": "Mempool API за точни такси и дати",
236 "enable_replace_by_fee": "Активиране на замяна по забрана",
236 - "enable_silent_payments_scanning": "Активирайте безшумните плащания за сканиране",
237 + "enable_silent_payments_scanning": "Започнете да сканирате безшумните плащания, докато се достигне съветът",
238 "enabled": "Активирано",
239 "enter_amount": "Въведете сума",
240 "enter_backup_password": "Въведете парола за възстановяване",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Неуспешно удостоверяване. ${state_error}",
297 "faq": "FAQ",
298 "features": "Характеристика",
299 + "fee_rate": "Такса ставка",
300 "fetching": "Обработване",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Фиат Баланс",
@@ -610,6 +612,7 @@
612 "send": "Изпрати",
613 "send_address": "${cryptoCurrency} адрес",
614 "send_amount": "Сума:",
615 + "send_change_to_you": "Променете, на вас:",
616 "send_creating_transaction": "Създаване на транзакция",
617 "send_error_currency": "Валутата може да съдържа само числа",
618 "send_error_minimum_value": "Минималната сума е 0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "Подписът не е валиден за даденото съобщение",
680 "signTransaction": "Подпишете транзакция",
681 "signup_for_card_accept_terms": "Регистрайте се за картата и приемете условията.",
682 + "silent_payment": "Безшумно плащане",
683 "silent_payments": "Мълчаливи плащания",
684 "silent_payments_always_scan": "Задайте мълчаливи плащания винаги сканиране",
685 "silent_payments_disclaimer": "Новите адреси не са нови идентичности. Това е повторна употреба на съществуваща идентичност с различен етикет.",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)",
713 "symbol": "Символ",
714 "sync_all_wallets": "Синхронизирайте всички портфейли",
715 + "sync_status_attempting_scan": "Опит за сканиране",
716 "sync_status_attempting_sync": "ОПИТ ЗА СИНХРОНИЗАЦИЯ",
717 "sync_status_connected": "СВЪРЗВАНЕ",
718 "sync_status_connecting": "СВЪРЗВАНЕ",
719 "sync_status_failed_connect": "НЕУСПЕШНО СВЪРЗВАНЕ",
720 "sync_status_not_connected": "НЯМА ВРЪЗКА",
716 - "sync_status_starting_scan": "Стартово сканиране",
721 + "sync_status_starting_scan": "Стартиране на сканиране (от ${height})",
722 "sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ",
723 "sync_status_syncronized": "СИНХРОНИЗИРАНО",
724 "sync_status_syncronizing": "СИНХРОНИЗИРАНЕ",
res/values/strings_cs.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Upravit token",
233 "electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují",
234 "email_address": "E-mailová adresa",
235 + "enable_mempool_api": "Mempool API pro přesné poplatky a data",
236 "enable_replace_by_fee": "Povolit výměnu podle poplatku",
236 - "enable_silent_payments_scanning": "Povolte skenování tichých plateb",
237 + "enable_silent_payments_scanning": "Začněte skenovat tiché platby, dokud není dosaženo špičky",
238 "enabled": "Povoleno",
239 "enter_amount": "Zadejte částku",
240 "enter_backup_password": "Zde zadejte své heslo pro zálohy",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Ověřování selhalo. ${state_error}",
297 "faq": "FAQ",
298 "features": "Funkce",
299 + "fee_rate": "Sazba poplatků",
300 "fetching": "Načítá se",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Fiat Balance",
@@ -610,6 +612,7 @@
612 "send": "Poslat",
613 "send_address": "${cryptoCurrency} adresa",
614 "send_amount": "Částka:",
615 + "send_change_to_you": "Změňte, vám:",
616 "send_creating_transaction": "Vytváření transakce",
617 "send_error_currency": "Měna může obsahovat pouze čísla",
618 "send_error_minimum_value": "Minimální částka je 0,01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "Podpis není platný pro danou zprávu",
680 "signTransaction": "Podepsat transakci",
681 "signup_for_card_accept_terms": "Zaregistrujte se pro kartu a souhlaste s podmínkami.",
682 + "silent_payment": "Tichá platba",
683 "silent_payments": "Tiché platby",
684 "silent_payments_always_scan": "Nastavit tiché platby vždy skenování",
685 "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 @@
712 "switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)",
713 "symbol": "Symbol",
714 "sync_all_wallets": "Synchronizovat všechny peněženky",
715 + "sync_status_attempting_scan": "Pokus o skenování",
716 "sync_status_attempting_sync": "ZAHAJUJI SYNCHR.",
717 "sync_status_connected": "PŘIPOJENO",
718 "sync_status_connecting": "PŘIPOJOVÁNÍ",
719 "sync_status_failed_connect": "ODPOJENO",
720 "sync_status_not_connected": "NEPŘIPOJENO",
716 - "sync_status_starting_scan": "Počáteční skenování",
721 + "sync_status_starting_scan": "Počáteční skenování (z ${height})",
722 "sync_status_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE",
723 "sync_status_syncronized": "SYNCHRONIZOVÁNO",
724 "sync_status_syncronizing": "SYNCHRONIZUJI",
res/values/strings_de.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Token bearbeiten",
233 "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin",
234 "email_address": "E-Mail-Adresse",
235 + "enable_mempool_api": "Mempool -API für genaue Gebühren und Daten",
236 "enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee",
236 - "enable_silent_payments_scanning": "Aktivieren Sie stille Zahlungen Scannen",
237 + "enable_silent_payments_scanning": "Scannen Sie stille Zahlungen, bis die Spitze erreicht ist",
238 "enabled": "Ermöglicht",
239 "enter_amount": "Betrag eingeben",
240 "enter_backup_password": "Sicherungskennwort hier eingeben",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Authentifizierung fehlgeschlagen. ${state_error}",
297 "faq": "Häufig gestellte Fragen",
298 "features": "Merkmale",
299 + "fee_rate": "Gebührenpreis",
300 "fetching": "Frage ab",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Fiat Balance",
@@ -611,6 +613,7 @@
613 "send": "Senden",
614 "send_address": "${cryptoCurrency}-Adresse",
615 "send_amount": "Betrag:",
616 + "send_change_to_you": "Verändere dich zu dir:",
617 "send_creating_transaction": "Erstelle Transaktion",
618 "send_error_currency": "Die Währung darf nur Zahlen enthalten",
619 "send_error_minimum_value": "Der Mindestbetrag ist 0,01",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "Die Signatur gilt nicht für die angegebene Nachricht",
681 "signTransaction": "Transaktion unterzeichnen",
682 "signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.",
683 + "silent_payment": "Stille Zahlung",
684 "silent_payments": "Stille Zahlungen",
685 "silent_payments_always_scan": "Setzen Sie stille Zahlungen immer scannen",
686 "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 @@
713 "switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)",
714 "symbol": "Symbol",
715 "sync_all_wallets": "Alle Wallets synchronisieren",
716 + "sync_status_attempting_scan": "Versuch Scan",
717 "sync_status_attempting_sync": "SYNC VERSUCHEN",
718 "sync_status_connected": "VERBUNDEN",
719 "sync_status_connecting": "VERBINDEN",
720 "sync_status_failed_connect": "GETRENNT",
721 "sync_status_not_connected": "NICHT VERBUNDEN",
717 - "sync_status_starting_scan": "Scan beginnen",
722 + "sync_status_starting_scan": "SCAN starten (von ${height})",
723 "sync_status_starting_sync": "STARTE SYNCHRONISIERUNG",
724 "sync_status_syncronized": "SYNCHRONISIERT",
725 "sync_status_syncronizing": "SYNCHRONISIERE",
res/values/strings_en.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Edit token",
233 "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work",
234 "email_address": "Email Address",
235 + "enable_mempool_api": "Mempool API for accurate fees and dates",
236 "enable_replace_by_fee": "Enable Replace-By-Fee",
236 - "enable_silent_payments_scanning": "Enable silent payments scanning",
237 + "enable_silent_payments_scanning": "Start scanning silent payments, until the tip is reached",
238 "enabled": "Enabled",
239 "enter_amount": "Enter Amount",
240 "enter_backup_password": "Enter backup password here",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Failed authentication. ${state_error}",
297 "faq": "FAQ",
298 "features": "Features",
299 + "fee_rate": "Fee rate",
300 "fetching": "Fetching",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Fiat Balance",
@@ -611,6 +613,7 @@
613 "send": "Send",
614 "send_address": "${cryptoCurrency} address",
615 "send_amount": "Amount:",
616 + "send_change_to_you": "Change, to you:",
617 "send_creating_transaction": "Creating transaction",
618 "send_error_currency": "Currency can only contain numbers",
619 "send_error_minimum_value": "Minimum value of amount is 0.01",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "The signature is not valid for the message given",
681 "signTransaction": "Sign Transaction",
682 "signup_for_card_accept_terms": "Sign up for the card and accept the terms.",
683 + "silent_payment": "Silent Payment",
684 "silent_payments": "Silent Payments",
685 "silent_payments_always_scan": "Set Silent Payments always scanning",
686 "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 @@
713 "switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)",
714 "symbol": "Symbol",
715 "sync_all_wallets": "Sync all wallets",
716 + "sync_status_attempting_scan": "ATTEMPTING SCAN",
717 "sync_status_attempting_sync": "ATTEMPTING SYNC",
718 "sync_status_connected": "CONNECTED",
719 "sync_status_connecting": "CONNECTING",
720 "sync_status_failed_connect": "DISCONNECTED",
721 "sync_status_not_connected": "NOT CONNECTED",
717 - "sync_status_starting_scan": "STARTING SCAN",
722 + "sync_status_starting_scan": "STARTING SCAN (from ${height})",
723 "sync_status_starting_sync": "STARTING SYNC",
724 "sync_status_syncronized": "SYNCHRONIZED",
725 "sync_status_syncronizing": "SYNCHRONIZING",
res/values/strings_es.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Editar token",
233 "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando",
234 "email_address": "Dirección de correo electrónico",
235 + "enable_mempool_api": "API de Mempool para tarifas y fechas precisas",
236 "enable_replace_by_fee": "Habilitar reemplazar por tarea",
236 - "enable_silent_payments_scanning": "Habilitar escaneo de pagos silenciosos",
237 + "enable_silent_payments_scanning": "Comience a escanear pagos silenciosos, hasta que se alcance la punta",
238 "enabled": "Activado",
239 "enter_amount": "Ingrese la cantidad",
240 "enter_backup_password": "Ingrese la contraseña de respaldo aquí",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Autenticación fallida. ${state_error}",
297 "faq": "FAQ",
298 "features": "Características",
299 + "fee_rate": "Tarifa",
300 "fetching": "Cargando",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Equilibrio Fiat",
@@ -611,6 +613,7 @@
613 "send": "Enviar",
614 "send_address": "Dirección de ${cryptoCurrency}",
615 "send_amount": "Cantidad:",
616 + "send_change_to_you": "Cambiar, a ti:",
617 "send_creating_transaction": "Creando transacción",
618 "send_error_currency": "La moneda solo puede contener números",
619 "send_error_minimum_value": "El valor mínimo de la cantidad es 0.01",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "La firma no es válida para el mensaje dado",
681 "signTransaction": "Firmar transacción",
682 "signup_for_card_accept_terms": "Regístrese para obtener la tarjeta y acepte los términos.",
683 + "silent_payment": "Pago silencioso",
684 "silent_payments": "Pagos silenciosos",
685 "silent_payments_always_scan": "Establecer pagos silenciosos siempre escaneando",
686 "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 @@
713 "switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)",
714 "symbol": "Símbolo",
715 "sync_all_wallets": "Sincronizar todas las billeteras",
716 + "sync_status_attempting_scan": "Intento de escaneo",
717 "sync_status_attempting_sync": "INTENTAR SINCRONIZAR",
718 "sync_status_connected": "CONECTADO",
719 "sync_status_connecting": "CONECTANDO",
720 "sync_status_failed_connect": "DESCONECTADO",
721 "sync_status_not_connected": "NO CONECTADO",
717 - "sync_status_starting_scan": "Escaneo inicial",
722 + "sync_status_starting_scan": "Iniciar escaneo (de ${height})",
723 "sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR",
724 "sync_status_syncronized": "SINCRONIZADO",
725 "sync_status_syncronizing": "SINCRONIZANDO",
res/values/strings_fr.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Modifier le token",
233 "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",
234 "email_address": "Adresse e-mail",
235 + "enable_mempool_api": "API Mempool pour les frais et dates précis",
236 "enable_replace_by_fee": "Activer Remplace-by-Fee",
236 - "enable_silent_payments_scanning": "Activer la numérisation des paiements silencieux",
237 + "enable_silent_payments_scanning": "Commencez à scanner les paiements silencieux, jusqu'à ce que la pointe soit atteinte",
238 "enabled": "Activé",
239 "enter_amount": "Entrez le montant",
240 "enter_backup_password": "Entrez le mot de passe de sauvegarde ici",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Échec d'authentification. ${state_error}",
297 "faq": "FAQ",
298 "features": "Caractéristiques",
299 + "fee_rate": "Taux de frais",
300 "fetching": "Récupération",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Solde fiat",
@@ -610,6 +612,7 @@
612 "send": "Envoyer",
613 "send_address": "adresse ${cryptoCurrency}",
614 "send_amount": "Montant :",
615 + "send_change_to_you": "Changer, pour vous:",
616 "send_creating_transaction": "Création de la transaction",
617 "send_error_currency": "La monnaie ne peut contenir que des nombres",
618 "send_error_minimum_value": "La valeur minimale du montant est 0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "La signature n'est pas valable pour le message donné",
680 "signTransaction": "Signer une transaction",
681 "signup_for_card_accept_terms": "Inscrivez-vous pour la carte et acceptez les conditions.",
682 + "silent_payment": "Paiement silencieux",
683 "silent_payments": "Paiements silencieux",
684 "silent_payments_always_scan": "Définir les paiements silencieux toujours à la scanne",
685 "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 @@
712 "switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)",
713 "symbol": "Symbole",
714 "sync_all_wallets": "Synchroniser tous les portefeuilles",
715 + "sync_status_attempting_scan": "Tentative de numérisation",
716 "sync_status_attempting_sync": "TENTATIVE DE SYNCHRONISATION",
717 "sync_status_connected": "CONNECTÉ",
718 "sync_status_connecting": "CONNEXION EN COURS",
719 "sync_status_failed_connect": "DÉCONNECTÉ",
720 "sync_status_not_connected": "NON CONNECTÉ",
716 - "sync_status_starting_scan": "Démarrage",
721 + "sync_status_starting_scan": "Démarrer la numérisation (à partir de ${height})",
722 "sync_status_starting_sync": "DÉBUT DE SYNCHRO",
723 "sync_status_syncronized": "SYNCHRONISÉ",
724 "sync_status_syncronizing": "SYNCHRONISATION EN COURS",
res/values/strings_ha.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Gyara alamar",
233 "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",
234 "email_address": "Adireshin i-mel",
235 + "enable_mempool_api": "Mampool API don ingantattun kudade da kwanakin",
236 "enable_replace_by_fee": "Ba da damar maye gurbin-by-kudin",
236 - "enable_silent_payments_scanning": "Kunna biya biya",
237 + "enable_silent_payments_scanning": "Fara bincika biya na shiru, har sai tip ɗin ya kai",
238 "enabled": "An kunna",
239 "enter_amount": "Shigar da Adadi",
240 "enter_backup_password": "Shigar da kalmar wucewa ta madadin nan",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Binne wajen shiga. ${state_error}",
297 "faq": "FAQ",
298 "features": "Fasas",
299 + "fee_rate": "Kudi",
300 "fetching": "Daukewa",
301 "fiat_api": "API ɗin Fiat",
302 "fiat_balance": "Fiat Balance",
@@ -612,6 +614,7 @@
614 "send": "Aika",
615 "send_address": "${cryptoCurrency} address",
616 "send_amount": "Adadi:",
617 + "send_change_to_you": "Canza, a gare ku:",
618 "send_creating_transaction": "Ƙirƙirar ciniki",
619 "send_error_currency": "Kudi zai iya ƙunsar lambobi kawai",
620 "send_error_minimum_value": "Mafi ƙarancin ƙimar adadin shine 0.01",
@@ -678,6 +681,7 @@
681 "signature_invalid_error": "Sa hannu ba shi da inganci ga sakon da aka bayar",
682 "signTransaction": "Sa hannu Ma'amala",
683 "signup_for_card_accept_terms": "Yi rajista don katin kuma karɓi sharuɗɗan.",
684 + "silent_payment": "Biya silent",
685 "silent_payments": "Biya silent",
686 "silent_payments_always_scan": "Saita biya na shiru koyaushe",
687 "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 @@
714 "switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)",
715 "symbol": "Alama",
716 "sync_all_wallets": "Sync Duk Wallet",
717 + "sync_status_attempting_scan": "Yunƙurin scan",
718 "sync_status_attempting_sync": "KWAFI",
719 "sync_status_connected": "HANNU",
720 "sync_status_connecting": "HADA",
721 "sync_status_failed_connect": "BABU INTERNET",
722 "sync_status_not_connected": "BABU INTERNET",
718 - "sync_status_starting_scan": "Fara scan",
723 + "sync_status_starting_scan": "Farawa Scan (daga ${height})",
724 "sync_status_starting_sync": "KWAFI",
725 "sync_status_syncronized": "KYAU",
726 "sync_status_syncronizing": "KWAFI",
res/values/strings_hi.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "टोकन संपादित करें",
233 "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं",
234 "email_address": "ईमेल पता",
235 + "enable_mempool_api": "सटीक शुल्क और तिथियों के लिए मेमपूल एपीआई",
236 "enable_replace_by_fee": "प्रतिस्थापित-दर-शुल्क सक्षम करें",
236 - "enable_silent_payments_scanning": "मूक भुगतान स्कैनिंग सक्षम करें",
237 + "enable_silent_payments_scanning": "साइलेंट पेमेंट्स को स्कैन करना शुरू करें, जब तक कि टिप तक पहुंच न जाए",
238 "enabled": "सक्रिय",
239 "enter_amount": "राशि दर्ज करें",
240 "enter_backup_password": "यहां बैकअप पासवर्ड डालें",
@@ -295,6 +296,7 @@
296 "failed_authentication": "प्रमाणीकरण विफल. ${state_error}",
297 "faq": "FAQ",
298 "features": "विशेषताएँ",
299 + "fee_rate": "शुल्क दर",
300 "fetching": "ला रहा है",
301 "fiat_api": "फिएट पैसे API",
302 "fiat_balance": "फिएट बैलेंस",
@@ -612,6 +614,7 @@
614 "send": "संदेश",
615 "send_address": "${cryptoCurrency} पता",
616 "send_amount": "रकम:",
617 + "send_change_to_you": "बदलो, आप को:",
618 "send_creating_transaction": "लेन-देन बनाना",
619 "send_error_currency": "मुद्रा में केवल संख्याएँ हो सकती हैं",
620 "send_error_minimum_value": "राशि का न्यूनतम मूल्य 0.01 है",
@@ -678,6 +681,7 @@
681 "signature_invalid_error": "हस्ताक्षर दिए गए संदेश के लिए मान्य नहीं है",
682 "signTransaction": "लेन-देन पर हस्ताक्षर करें",
683 "signup_for_card_accept_terms": "कार्ड के लिए साइन अप करें और शर्तें स्वीकार करें।",
684 + "silent_payment": "मूक भुगतान",
685 "silent_payments": "मूक भुगतान",
686 "silent_payments_always_scan": "मूक भुगतान हमेशा स्कैनिंग सेट करें",
687 "silent_payments_disclaimer": "नए पते नई पहचान नहीं हैं। यह एक अलग लेबल के साथ एक मौजूदा पहचान का पुन: उपयोग है।",
@@ -710,12 +714,13 @@
714 "switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)",
715 "symbol": "प्रतीक",
716 "sync_all_wallets": "सभी वॉलेट सिंक करें",
717 + "sync_status_attempting_scan": "स्कैन का प्रयास",
718 "sync_status_attempting_sync": "सिंक करने का प्रयास",
719 "sync_status_connected": "जुड़े हुए",
720 "sync_status_connecting": "कनेक्ट",
721 "sync_status_failed_connect": "डिस्कनेक्ट किया गया",
722 "sync_status_not_connected": "जुड़े नहीं हैं",
718 - "sync_status_starting_scan": "स्कैन शुरू करना",
723 + "sync_status_starting_scan": "स्कैन शुरू करना (${height} से)",
724 "sync_status_starting_sync": "सिताज़ा करना",
725 "sync_status_syncronized": "सिंक्रनाइज़",
726 "sync_status_syncronizing": "सिंक्रनाइज़ करने",
res/values/strings_hr.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Uredi token",
233 "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek",
234 "email_address": "Adresa e-pošte",
235 + "enable_mempool_api": "Mempool API za točne naknade i datume",
236 "enable_replace_by_fee": "Omogući zamjenu",
236 - "enable_silent_payments_scanning": "Omogući skeniranje tihih plaćanja",
237 + "enable_silent_payments_scanning": "Započnite skeniranje tihih plaćanja, dok se ne postigne savjet",
238 "enabled": "Omogućeno",
239 "enter_amount": "Unesite iznos",
240 "enter_backup_password": "Unesite svoju lozinku za sigurnosnu kopiju ovdje",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Autentifikacija neuspješna. ${state_error}",
297 "faq": "FAQ",
298 "features": "Značajke",
299 + "fee_rate": "Stopa naknade",
300 "fetching": "Dohvaćanje",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Fiat Bilans",
@@ -610,6 +612,7 @@
612 "send": "Pošalji",
613 "send_address": "${cryptoCurrency} adresa",
614 "send_amount": "Iznos:",
615 + "send_change_to_you": "Promijenite, u vas:",
616 "send_creating_transaction": "Izrada transakcije",
617 "send_error_currency": "Iznos smije sadržavati samo brojeve",
618 "send_error_minimum_value": "Minimalna vrijednost iznosa je 0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "Potpis ne vrijedi za danu poruku",
680 "signTransaction": "Potpišite transakciju",
681 "signup_for_card_accept_terms": "Prijavite se za karticu i prihvatite uvjete.",
682 + "silent_payment": "Tiho plaćanje",
683 "silent_payments": "Tiha plaćanja",
684 "silent_payments_always_scan": "Postavite tiho plaćanje uvijek skeniranje",
685 "silent_payments_disclaimer": "Nove adrese nisu novi identiteti. To je ponovna upotreba postojećeg identiteta s drugom oznakom.",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)",
713 "symbol": "Simbol",
714 "sync_all_wallets": "Sinkronizirajte sve novčanike",
715 + "sync_status_attempting_scan": "Pokušaj skeniranja",
716 "sync_status_attempting_sync": "POKUŠAJ SINKRONIZACIJE",
717 "sync_status_connected": "SPOJENO",
718 "sync_status_connecting": "SPAJANJE",
719 "sync_status_failed_connect": "ISKLJUČENO",
720 "sync_status_not_connected": "NIJE POVEZANO",
716 - "sync_status_starting_scan": "Početno skeniranje",
721 + "sync_status_starting_scan": "Početno skeniranje (od ${height})",
722 "sync_status_starting_sync": "ZAPOČINJEMO SINKRONIZIRANJE",
723 "sync_status_syncronized": "SINKRONIZIRANO",
724 "sync_status_syncronizing": "SINKRONIZIRANJE",
res/values/strings_hy.arb
+7 -2
@@ -231,8 +231,9 @@
231 "edit_token": "Փոփոխել տոկեն",
232 "electrum_address_disclaimer": "Մենք ստեղծում ենք նոր հասցե ամեն անգամ, երբ դուք օգտագործում եք այն, բայց նախորդ հասցեները շարունակում են աշխատել",
233 "email_address": "Էլ. փոստի հասցե",
234 + "enable_mempool_api": "Mempool API ճշգրիտ վճարների եւ ամսաթվերի համար",
235 "enable_replace_by_fee": "Միացնել փոխարինումը միջնորդավճարով",
235 - "enable_silent_payments_scanning": "Միացնել Լուռ Վճարումների սկանավորումը",
236 + "enable_silent_payments_scanning": "Սկսեք սկանավորել լուռ վճարումները, մինչեւ որ ծայրը հասնի",
237 "enabled": "Միացված",
238 "enter_amount": "Մուտքագրեք գումար",
239 "enter_backup_password": "Մուտքագրեք կրկնօրինակի գաղտնաբառը",
@@ -294,6 +295,7 @@
295 "failed_authentication": "Վավերացումը ձախողվեց. ${state_error}",
296 "faq": "Հաճախ տրվող հարցեր",
297 "features": "Հատկանիշներ",
298 + "fee_rate": "Վճարման տոկոսադրույքը",
299 "fetching": "Ստացվում է",
300 "fiat_api": "Fiat API",
301 "fiat_balance": "Fiat մնացորդ",
@@ -610,6 +612,7 @@
612 "send": "Ուղարկել",
613 "send_address": "${cryptoCurrency} հասցե",
614 "send_amount": "Քանակ՝",
615 + "send_change_to_you": "Փոփոխություն, ձեզ համար.",
616 "send_creating_transaction": "Ստեղծել գործարք",
617 "send_error_currency": "Արժույթը կարող է պարունակել միայն թվեր",
618 "send_error_minimum_value": "Քանակի նվազագույն արժեքը 0.01 է",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "Կնիքը անվավեր է տրված հաղորդագրության համար",
680 "signTransaction": "Կնքել Գործարք",
681 "signup_for_card_accept_terms": "Գրանցվել քարտի համար և ընդունել պայմանները",
682 + "silent_payment": "Լուռ վճարում",
683 "silent_payments": "Լուռ Վճարումներ",
684 "silent_payments_always_scan": "Միացնել Լուռ Վճարումներ մշտական սկանավորումը",
685 "silent_payments_disclaimer": "Նոր հասցեները նոր ինքնություն չեն։ Դա այլ պիտակով գոյություն ունեցող ինքնության վերագործածում է",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": "Խնդրում ենք անցնել EVM համատեղելի դրամապանակ և փորձել կրկին (Ethereum, Polygon)",
713 "symbol": "Նշան",
714 "sync_all_wallets": "Համաժամեցնել բոլոր դրամապանակները",
715 + "sync_status_attempting_scan": "Փորձի սկան",
716 "sync_status_attempting_sync": "ՀԱՄԱԺԱՄԵՑՄԱՆ ՓՈՐՁ",
717 "sync_status_connected": "ՄԻԱՑՎԱԾԷ",
718 "sync_status_connecting": "ՄԻԱՑՎՈՒՄ Է",
719 "sync_status_failed_connect": "ՉՄԻԱՑԱՎ",
720 "sync_status_not_connected": "ՄԻԱՑՎԱԾ ՉԷ",
716 - "sync_status_starting_scan": "ՍԿԱՆԱՎՈՐՈՒՄԸ ՍԿՍՎՈՒՄ Է",
721 + "sync_status_starting_scan": "Սկսած սկան (${height})",
722 "sync_status_starting_sync": "ՀԱՄԱԺԱՄԵՑՈՒՄԸ ՍԿՍՎՈՒՄ Է",
723 "sync_status_syncronized": "ՀԱՄԱԺԱՄԵՑՎԱԾԷ",
724 "sync_status_syncronizing": "ՀԱՄԱԺԱՄԵՑՎՈՒՄ Է",
res/values/strings_id.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Mengedit token",
233 "electrum_address_disclaimer": "Kami menghasilkan alamat baru setiap kali Anda menggunakan satu, tetapi alamat sebelumnya tetap berfungsi",
234 "email_address": "Alamat Email",
235 + "enable_mempool_api": "API Mempool untuk biaya dan tanggal yang akurat",
236 "enable_replace_by_fee": "Aktifkan ganti-by-fee",
236 - "enable_silent_payments_scanning": "Aktifkan pemindaian pembayaran diam",
237 + "enable_silent_payments_scanning": "Mulailah memindai pembayaran diam, sampai ujung tercapai",
238 "enabled": "Diaktifkan",
239 "enter_amount": "Masukkan Jumlah",
240 "enter_backup_password": "Masukkan kata sandi cadangan di sini",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Otentikasi gagal. ${state_error}",
297 "faq": "Pertanyaan yang Sering Diajukan",
298 "features": "Fitur",
299 + "fee_rate": "Tarif biaya",
300 "fetching": "Mengambil",
301 "fiat_api": "API fiat",
302 "fiat_balance": "Saldo Fiat",
@@ -613,6 +615,7 @@
615 "send": "Mengirim",
616 "send_address": "Alamat ${cryptoCurrency}",
617 "send_amount": "Jumlah:",
618 + "send_change_to_you": "Ubah, untukmu:",
619 "send_creating_transaction": "Membuat transaksi",
620 "send_error_currency": "Mata uang hanya dapat berisi angka",
621 "send_error_minimum_value": "Nilai minimum jumlah adalah 0.01",
@@ -679,6 +682,7 @@
682 "signature_invalid_error": "Tanda tangan tidak valid untuk pesan yang diberikan",
683 "signTransaction": "Tandatangani Transaksi",
684 "signup_for_card_accept_terms": "Daftar untuk kartu dan terima syarat dan ketentuan.",
685 + "silent_payment": "Pembayaran diam",
686 "silent_payments": "Pembayaran diam",
687 "silent_payments_always_scan": "Tetapkan pembayaran diam selalu pemindaian",
688 "silent_payments_disclaimer": "Alamat baru bukanlah identitas baru. Ini adalah penggunaan kembali identitas yang ada dengan label yang berbeda.",
@@ -711,12 +715,13 @@
715 "switchToEVMCompatibleWallet": "Silakan beralih ke dompet yang kompatibel dengan EVM dan coba lagi (Ethereum, Polygon)",
716 "symbol": "Simbol",
717 "sync_all_wallets": "Sinkronkan semua dompet",
718 + "sync_status_attempting_scan": "Mencoba memindai",
719 "sync_status_attempting_sync": "MENCOBA SINKRONISASI",
720 "sync_status_connected": "TERHUBUNG",
721 "sync_status_connecting": "MENGHUBUNGKAN",
722 "sync_status_failed_connect": "GAGAL TERHUBUNG",
723 "sync_status_not_connected": "TIDAK TERHUBUNG",
719 - "sync_status_starting_scan": "Mulai pindai",
724 + "sync_status_starting_scan": "Mulai pemindaian (dari ${height})",
725 "sync_status_starting_sync": "MULAI SINKRONISASI",
726 "sync_status_syncronized": "SUDAH TERSINKRONISASI",
727 "sync_status_syncronizing": "SEDANG SINKRONISASI",
res/values/strings_it.arb
+7 -2
@@ -233,8 +233,9 @@
233 "edit_token": "Modifica token",
234 "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare",
235 "email_address": "Indirizzo e-mail",
236 + "enable_mempool_api": "API di Mempool per commissioni e date accurate",
237 "enable_replace_by_fee": "Abilita sostituzione per fee",
237 - "enable_silent_payments_scanning": "Abilita la scansione dei pagamenti silenziosi",
238 + "enable_silent_payments_scanning": "Inizia a scansionare i pagamenti silenziosi, fino a raggiungere la punta",
239 "enabled": "Abilitato",
240 "enter_amount": "Inserisci importo",
241 "enter_backup_password": "Inserisci la password di backup qui",
@@ -296,6 +297,7 @@
297 "failed_authentication": "Autenticazione fallita. ${state_error}",
298 "faq": "Domande Frequenti",
299 "features": "Caratteristiche",
300 + "fee_rate": "Tasso di commissione",
301 "fetching": "Recupero",
302 "fiat_api": "Fiat API",
303 "fiat_balance": "Equilibrio fiat",
@@ -612,6 +614,7 @@
614 "send": "Invia",
615 "send_address": "${cryptoCurrency} indirizzo",
616 "send_amount": "Ammontare:",
617 + "send_change_to_you": "Cambiamento, a te:",
618 "send_creating_transaction": "Creazione della transazione",
619 "send_error_currency": "L'ammontare può contenere solo numeri",
620 "send_error_minimum_value": "L'ammontare minimo è 0.01",
@@ -678,6 +681,7 @@
681 "signature_invalid_error": "La firma non è valida per il messaggio dato",
682 "signTransaction": "Firma la transazione",
683 "signup_for_card_accept_terms": "Registrati per la carta e accetta i termini.",
684 + "silent_payment": "Pagamento silenzioso",
685 "silent_payments": "Pagamenti silenziosi",
686 "silent_payments_always_scan": "Impostare i pagamenti silenziosi che scansionano sempre",
687 "silent_payments_disclaimer": "I nuovi indirizzi non sono nuove identità. È un riutilizzo di un'identità esistente con un'etichetta diversa.",
@@ -710,12 +714,13 @@
714 "switchToEVMCompatibleWallet": "Passa a un portafoglio compatibile con EVM e riprova (Ethereum, Polygon)",
715 "symbol": "Simbolo",
716 "sync_all_wallets": "Sincronizza tutti i portafogli",
717 + "sync_status_attempting_scan": "Tentando la scansione",
718 "sync_status_attempting_sync": "TENTATIVO DI SINCRONIZZAZIONE",
719 "sync_status_connected": "CONNESSO",
720 "sync_status_connecting": "CONNESSIONE",
721 "sync_status_failed_connect": "DISCONNESSO",
722 "sync_status_not_connected": "NON CONNESSO",
718 - "sync_status_starting_scan": "Scansione di partenza",
723 + "sync_status_starting_scan": "Avvia scansione (da ${height})",
724 "sync_status_starting_sync": "INIZIO SINC",
725 "sync_status_syncronized": "SINCRONIZZATO",
726 "sync_status_syncronizing": "SINCRONIZZAZIONE",
res/values/strings_ja.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "トークンの編集",
233 "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します",
234 "email_address": "メールアドレス",
235 + "enable_mempool_api": "正確な料金と日付のMempool API",
236 "enable_replace_by_fee": "交換ごとに有効にします",
236 - "enable_silent_payments_scanning": "サイレントペイメントスキャンを有効にします",
237 + "enable_silent_payments_scanning": "先端に達するまで、サイレント決済のスキャンを開始します",
238 "enabled": "有効",
239 "enter_amount": "金額を入力",
240 "enter_backup_password": "ここにバックアップパスワードを入力してください",
@@ -295,6 +296,7 @@
296 "failed_authentication": "認証失敗. ${state_error}",
297 "faq": "FAQ",
298 "features": "特徴",
299 + "fee_rate": "料金金利",
300 "fetching": "フェッチング",
301 "fiat_api": "不換紙幣 API",
302 "fiat_balance": "フィアットバランス",
@@ -611,6 +613,7 @@
613 "send": "送る",
614 "send_address": "${cryptoCurrency} 住所",
615 "send_amount": "量:",
616 + "send_change_to_you": "あなたに変更:",
617 "send_creating_transaction": "トランザクションを作成する",
618 "send_error_currency": "通貨には数字のみを含めることができます",
619 "send_error_minimum_value": "金額の最小値は0.01です",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "署名は、指定されたメッセージに対して無効です",
681 "signTransaction": "トランザクションに署名する",
682 "signup_for_card_accept_terms": "カードにサインアップして、利用規約に同意してください。",
683 + "silent_payment": "サイレント支払い",
684 "silent_payments": "サイレント支払い",
685 "silent_payments_always_scan": "サイレント決済を常にスキャンします",
686 "silent_payments_disclaimer": "新しいアドレスは新しいアイデンティティではありません。これは、異なるラベルを持つ既存のアイデンティティの再利用です。",
@@ -709,12 +713,13 @@
713 "switchToEVMCompatibleWallet": "EVM 互換のウォレットに切り替えて再試行してください (イーサリアム、ポリゴン)",
714 "symbol": "シンボル",
715 "sync_all_wallets": "すべてのウォレットを同期",
716 + "sync_status_attempting_scan": "スキャンの試み",
717 "sync_status_attempting_sync": "同期を試みています",
718 "sync_status_connected": "接続済み",
719 "sync_status_connecting": "接続中",
720 "sync_status_failed_connect": "切断されました",
721 "sync_status_not_connected": "接続されていません",
717 - "sync_status_starting_scan": "スキャンを開始します",
722 + "sync_status_starting_scan": "スキャンを開始する(${height} から)",
723 "sync_status_starting_sync": "同期の開始",
724 "sync_status_syncronized": "同期された",
725 "sync_status_syncronizing": "同期",
res/values/strings_ko.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "토큰 편집",
233 "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다.",
234 "email_address": "이메일 주소",
235 + "enable_mempool_api": "정확한 수수료 및 날짜에 대한 Mempool API",
236 "enable_replace_by_fee": "대체별로 활성화하십시오",
236 - "enable_silent_payments_scanning": "무음 지불 스캔을 활성화합니다",
237 + "enable_silent_payments_scanning": "팁에 도달 할 때까지 사일런트 지불을 스캔하기 시작합니다.",
238 "enabled": "사용",
239 "enter_amount": "금액 입력",
240 "enter_backup_password": "여기에 백업 비밀번호를 입력하세요.",
@@ -295,6 +296,7 @@
296 "failed_authentication": "인증 실패. ${state_error}",
297 "faq": "FAQ",
298 "features": "특징",
299 + "fee_rate": "수수료",
300 "fetching": "가져 오는 중",
301 "fiat_api": "명목 화폐 API",
302 "fiat_balance": "피아트 잔액",
@@ -611,6 +613,7 @@
613 "send": "보내다",
614 "send_address": "${cryptoCurrency} 주소",
615 "send_amount": "양:",
616 + "send_change_to_you": "당신에게 변경 :",
617 "send_creating_transaction": "거래 생성",
618 "send_error_currency": "통화는 숫자 만 포함 할 수 있습니다",
619 "send_error_minimum_value": "금액의 최소값은 0.01입니다",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "서명은 주어진 메시지에 유효하지 않습니다",
681 "signTransaction": "거래 서명",
682 "signup_for_card_accept_terms": "카드에 가입하고 약관에 동의합니다.",
683 + "silent_payment": "조용한 지불",
684 "silent_payments": "조용한 지불",
685 "silent_payments_always_scan": "무음금을 항상 스캔합니다",
686 "silent_payments_disclaimer": "새로운 주소는 새로운 정체성이 아닙니다. 다른 레이블로 기존 신원을 재사용하는 것입니다.",
@@ -709,12 +713,13 @@
713 "switchToEVMCompatibleWallet": "EVM 호환 지갑으로 전환 후 다시 시도해 주세요. (이더리움, 폴리곤)",
714 "symbol": "상징",
715 "sync_all_wallets": "모든 지갑 동기화",
716 + "sync_status_attempting_scan": "스캔 시도",
717 "sync_status_attempting_sync": "동기화 시도 중",
718 "sync_status_connected": "연결됨",
719 "sync_status_connecting": "연결 중",
720 "sync_status_failed_connect": "연결 해제",
721 "sync_status_not_connected": "연결되지 않은",
717 - "sync_status_starting_scan": "스캔 시작",
722 + "sync_status_starting_scan": "시작 스캔 (${height} 에서)",
723 "sync_status_starting_sync": "동기화 시작",
724 "sync_status_syncronized": "동기화",
725 "sync_status_syncronizing": "동기화",
res/values/strings_my.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "တိုကင်ကို တည်းဖြတ်ပါ။",
233 "electrum_address_disclaimer": "သင်အသုံးပြုသည့်အချိန်တိုင်းတွင် ကျွန်ုပ်တို့သည် လိပ်စာအသစ်များကို ထုတ်ပေးသော်လည်း ယခင်လိပ်စာများသည် ဆက်လက်အလုပ်လုပ်နေပါသည်။",
234 "email_address": "အီးမေးလ်လိပ်စာ",
235 + "enable_mempool_api": "Mempool API တိကျသောအခကြေးငွေနှင့်ရက်စွဲများအတွက်",
236 "enable_replace_by_fee": "အစားထိုး - by- အခကြေးငွေ enable",
236 - "enable_silent_payments_scanning": "အသံတိတ်ငွေပေးချေမှုကို scanable လုပ်ပါ",
237 + "enable_silent_payments_scanning": "အစွန်အဖျားသို့ရောက်ရှိသည်အထိအသံတိတ်ငွေပေးချေမှုကိုစကင်ဖတ်စစ်ဆေးပါ",
238 "enabled": "ဖွင့်ထားသည်။",
239 "enter_amount": "ပမာဏကို ထည့်ပါ။",
240 "enter_backup_password": "အရန်စကားဝှက်ကို ဤနေရာတွင် ထည့်ပါ။",
@@ -295,6 +296,7 @@
296 "failed_authentication": "အထောက်အထားစိစစ်ခြင်း မအောင်မြင်ပါ။. ${state_error}",
297 "faq": "အမြဲမေးလေ့ရှိသောမေးခွန်းများ",
298 "features": "အင်္ဂါရပ်များ",
299 + "fee_rate": "ကြေးနှုန်း",
300 "fetching": "ခေါ်ယူခြင်း။",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Fiat Balance",
@@ -610,6 +612,7 @@
612 "send": "ပို့ပါ။",
613 "send_address": "${cryptoCurrency} လိပ်စာ",
614 "send_amount": "ပမာဏ-",
615 + "send_change_to_you": "ပြောင်းလဲမှု,",
616 "send_creating_transaction": "အရောင်းအဝယ်ပြုလုပ်ခြင်း။",
617 "send_error_currency": "ငွေကြေးတွင် နံပါတ်များသာ ပါဝင်နိုင်သည်။",
618 "send_error_minimum_value": "ပမာဏ၏ အနည်းဆုံးတန်ဖိုးမှာ 0.01 ဖြစ်သည်။",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "အဆိုပါလက်မှတ်ပေးထားသောမက်ဆေ့ခ်ျကိုများအတွက်မမှန်ကန်ပါ",
680 "signTransaction": "ငွေလွှဲဝင်ပါ။",
681 "signup_for_card_accept_terms": "ကတ်အတွက် စာရင်းသွင်းပြီး စည်းကမ်းချက်များကို လက်ခံပါ။",
682 + "silent_payment": "အသံတိတ်ငွေပေးချေမှု",
683 "silent_payments": "အသံတိတ်ငွေပေးချေမှု",
684 "silent_payments_always_scan": "အမြဲတမ်း scanning အမြဲ scanning",
685 "silent_payments_disclaimer": "လိပ်စာအသစ်များသည်အထောက်အထားအသစ်များမဟုတ်ပါ။ ၎င်းသည်ကွဲပြားခြားနားသောတံဆိပ်ဖြင့်ရှိပြီးသားဝိသေသလက်ခဏာကိုပြန်လည်အသုံးပြုခြင်းဖြစ်သည်။",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": "ကျေးဇူးပြု၍ EVM တွဲဖက်သုံးနိုင်သော ပိုက်ဆံအိတ်သို့ ပြောင်းပြီး ထပ်စမ်းကြည့်ပါ (Ethereum၊ Polygon)",
713 "symbol": "သင်္ကေတ",
714 "sync_all_wallets": "အားလုံးပိုက်ဆံအိတ်စည်းညှိ",
715 + "sync_status_attempting_scan": "scan ကြိုးစားနေ",
716 "sync_status_attempting_sync": "ချိန်ကိုက်ခြင်းကို ကြိုးစားနေသည်။",
717 "sync_status_connected": "ချိတ်ဆက်ထားသည်။",
718 "sync_status_connecting": "ချိတ်ဆက်ခြင်း။",
719 "sync_status_failed_connect": "အဆက်အသွယ်ဖြတ်ထားသည်။",
720 "sync_status_not_connected": "မချိတ်ဆက်ပါ။",
716 - "sync_status_starting_scan": "စကင်ဖတ်စစ်ဆေးမှု",
721 + "sync_status_starting_scan": "စကင်ဖတ်စစ်ဆေးမှုစတင်ခြင်း (${height})",
722 "sync_status_starting_sync": "စင့်ခ်လုပ်ခြင်း။",
723 "sync_status_syncronized": "ထပ်တူပြုထားသည်။",
724 "sync_status_syncronizing": "ထပ်တူပြုခြင်း။",
res/values/strings_nl.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Token bewerken",
233 "electrum_address_disclaimer": "We genereren nieuwe adressen elke keer dat u er een gebruikt, maar eerdere adressen blijven werken",
234 "email_address": "E-mailadres",
235 + "enable_mempool_api": "Mempool API voor nauwkeurige kosten en datums",
236 "enable_replace_by_fee": "Schakel vervangen door een fee",
236 - "enable_silent_payments_scanning": "Schakel stille betalingen in scannen in",
237 + "enable_silent_payments_scanning": "Begin met het scannen van stille betalingen, totdat de tip is bereikt",
238 "enabled": "Ingeschakeld",
239 "enter_amount": "Voer Bedrag in",
240 "enter_backup_password": "Voer hier een back-upwachtwoord in",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Mislukte authenticatie. ${state_error}",
297 "faq": "FAQ",
298 "features": "Functies",
299 + "fee_rate": "Tarief",
300 "fetching": "Ophalen",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Fiat Balans",
@@ -610,6 +612,7 @@
612 "send": "Sturen",
613 "send_address": "${cryptoCurrency}-adres",
614 "send_amount": "Bedrag:",
615 + "send_change_to_you": "Verander, aan jou:",
616 "send_creating_transaction": "Transactie maken",
617 "send_error_currency": "Valuta kan alleen cijfers bevatten",
618 "send_error_minimum_value": "Minimale waarde van bedrag is 0,01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "De handtekening is niet geldig voor het gegeven bericht",
680 "signTransaction": "Transactie ondertekenen",
681 "signup_for_card_accept_terms": "Meld je aan voor de kaart en accepteer de voorwaarden.",
682 + "silent_payment": "Stille betaling",
683 "silent_payments": "Stille betalingen",
684 "silent_payments_always_scan": "Stel stille betalingen in het scannen",
685 "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 @@
712 "switchToEVMCompatibleWallet": "Schakel over naar een EVM-compatibele portemonnee en probeer het opnieuw (Ethereum, Polygon)",
713 "symbol": "Symbool",
714 "sync_all_wallets": "Alle portemonnees synchroniseren",
715 + "sync_status_attempting_scan": "Proberen scan",
716 "sync_status_attempting_sync": "SYNCHRONISATIE PROBEREN",
717 "sync_status_connected": "VERBONDEN",
718 "sync_status_connecting": "AANSLUITING",
719 "sync_status_failed_connect": "LOSGEKOPPELD",
720 "sync_status_not_connected": "NIET VERBONDEN",
716 - "sync_status_starting_scan": "Startscan",
721 + "sync_status_starting_scan": "SCAN starten (van ${height})",
722 "sync_status_starting_sync": "BEGINNEN MET SYNCHRONISEREN",
723 "sync_status_syncronized": "SYNCHRONIZED",
724 "sync_status_syncronizing": "SYNCHRONISEREN",
res/values/strings_pl.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Edytuj token",
233 "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",
234 "email_address": "Adres e-mail",
235 + "enable_mempool_api": "Mempool API dla dokładnych opłat i dat",
236 "enable_replace_by_fee": "Włącz wymianę po lewej",
236 - "enable_silent_payments_scanning": "Włącz skanowanie cichych płatności",
237 + "enable_silent_payments_scanning": "Zacznij skanować ciche płatności, aż do osiągnięcia wskazówki",
238 "enabled": "Włączone",
239 "enter_amount": "Wprowadź kwotę",
240 "enter_backup_password": "Wprowadź tutaj hasło kopii zapasowej",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Nieudane uwierzytelnienie. ${state_error}",
297 "faq": "FAQ",
298 "features": "Cechy",
299 + "fee_rate": "Stawka opłaty",
300 "fetching": "Pobieranie",
301 "fiat_api": "API Walut FIAT",
302 "fiat_balance": "Bilans Fiata",
@@ -610,6 +612,7 @@
612 "send": "Wyślij",
613 "send_address": "Adres ${cryptoCurrency}",
614 "send_amount": "Ilość:",
615 + "send_change_to_you": "Zmień do ciebie:",
616 "send_creating_transaction": "Tworzenie transakcji",
617 "send_error_currency": "Waluta może zawierać tylko cyfry",
618 "send_error_minimum_value": "Minimalna wartość to 0,01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "Podpis nie jest ważny dla podanej wiadomości",
680 "signTransaction": "Podpisz transakcję",
681 "signup_for_card_accept_terms": "Zarejestruj się, aby otrzymać kartę i zaakceptuj warunki.",
682 + "silent_payment": "Cicha płatność",
683 "silent_payments": "Ciche płatności",
684 "silent_payments_always_scan": "Ustaw ciche płatności zawsze skanowanie",
685 "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 @@
712 "switchToEVMCompatibleWallet": "Przejdź na portfel zgodny z EVM i spróbuj ponownie (Ethereum, Polygon)",
713 "symbol": "Symbol",
714 "sync_all_wallets": "Synchronizuj wszystkie portfele",
715 + "sync_status_attempting_scan": "Próba skanowania",
716 "sync_status_attempting_sync": "PRÓBA SYNCHRONIZACJI",
717 "sync_status_connected": "POŁĄCZONY",
718 "sync_status_connecting": "ŁĄCZENIE",
719 "sync_status_failed_connect": "POŁĄCZENIE NIEUDANE",
720 "sync_status_not_connected": "NIE POŁĄCZONY",
716 - "sync_status_starting_scan": "Rozpoczęcie skanowania",
721 + "sync_status_starting_scan": "Rozpoczęcie skanowania (od ${height})",
722 "sync_status_starting_sync": "ROZPOCZĘCIE SYNCHRONIZACJI",
723 "sync_status_syncronized": "ZSYNCHRONIZOWANO",
724 "sync_status_syncronizing": "SYNCHRONIZACJA",
res/values/strings_pt.arb
+9 -4
@@ -143,7 +143,7 @@
143 "confirm_fee_deduction": "Confirme dedução da taxa",
144 "confirm_fee_deduction_content": "Você concorda em deduzir a taxa da saída?",
145 "confirm_sending": "Confirmar o envio",
146 - "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",
146 + "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",
147 "confirmations": "Confirmações",
148 "confirmed": "Saldo Confirmado",
149 "confirmed_tx": "Confirmado",
@@ -232,8 +232,9 @@
232 "edit_token": "Editar símbolo",
233 "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando",
234 "email_address": "Endereço de e-mail",
235 + "enable_mempool_api": "Mempool API para taxas e datas precisas",
236 "enable_replace_by_fee": "Habilite substituir por taxa",
236 - "enable_silent_payments_scanning": "Ativar escaneamento de pagamentos silenciosos",
237 + "enable_silent_payments_scanning": "Comece a escanear pagamentos silenciosos, até que o topo seja alcançada",
238 "enabled": "Habilitado",
239 "enter_amount": "Digite o valor",
240 "enter_backup_password": "Digite a senha de backup aqui",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Falha na autenticação. ${state_error}",
297 "faq": "FAQ",
298 "features": "Funcionalidades",
299 + "fee_rate": "Taxa de transação",
300 "fetching": "Buscando",
301 "fiat_api": "API da Fiat",
302 "fiat_balance": "Equilíbrio Fiat",
@@ -612,6 +614,7 @@
614 "send": "Enviar",
615 "send_address": "Endereço ${cryptoCurrency}",
616 "send_amount": "Montante:",
617 + "send_change_to_you": "Troco, para você:",
618 "send_creating_transaction": "Criando transação",
619 "send_error_currency": "A moeda só pode conter números",
620 "send_error_minimum_value": "O valor mínimo da quantia é 0,01",
@@ -678,8 +681,9 @@
681 "signature_invalid_error": "A assinatura não é válida para a mensagem dada",
682 "signTransaction": "Assinar transação",
683 "signup_for_card_accept_terms": "Cadastre-se no cartão e aceite os termos.",
684 + "silent_payment": "Pagamento silencioso",
685 "silent_payments": "Pagamentos silenciosos",
682 - "silent_payments_always_scan": "Defina pagamentos silenciosos sempre digitalizando",
686 + "silent_payments_always_scan": "Defina pagamentos silenciosos sempre escaneando",
687 "silent_payments_disclaimer": "Novos endereços não são novas identidades. É uma reutilização de uma identidade existente com um rótulo diferente.",
688 "silent_payments_display_card": "Mostrar cartão de pagamento silencioso",
689 "silent_payments_scan_from_date": "Escanear a partir da data",
@@ -710,12 +714,13 @@
714 "switchToEVMCompatibleWallet": "Mude para uma carteira compatível com EVM e tente novamente (Ethereum, Polygon)",
715 "symbol": "Símbolo",
716 "sync_all_wallets": "Sincronize todas as carteiras",
717 + "sync_status_attempting_scan": "TENTANDO ESCANEAR",
718 "sync_status_attempting_sync": "TENTANDO SINCRONIZAR",
719 "sync_status_connected": "CONECTADO",
720 "sync_status_connecting": "CONECTANDO",
721 "sync_status_failed_connect": "DESCONECTADO",
722 "sync_status_not_connected": "DESCONECTADO",
718 - "sync_status_starting_scan": "Diretor inicial",
723 + "sync_status_starting_scan": "Começando scan (de ${height})",
724 "sync_status_starting_sync": "INICIANDO SINCRONIZAÇÃO",
725 "sync_status_syncronized": "SINCRONIZADO",
726 "sync_status_syncronizing": "SINCRONIZANDO",
res/values/strings_ru.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Изменить токен",
233 "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать.",
234 "email_address": "Адрес электронной почты",
235 + "enable_mempool_api": "Mempool API за точные сборы и даты",
236 "enable_replace_by_fee": "Включить замену за пикой",
236 - "enable_silent_payments_scanning": "Включить сканирование безмолвных платежей",
237 + "enable_silent_payments_scanning": "Начните сканировать безмолвные платежи, пока не будет достигнут наконечник",
238 "enabled": "Включено",
239 "enter_amount": "Введите сумму",
240 "enter_backup_password": "Введите пароль резервной копии",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Ошибка аутентификации. ${state_error}",
297 "faq": "FAQ",
298 "features": "Функции",
299 + "fee_rate": "Плата",
300 "fetching": "Загрузка",
301 "fiat_api": "Фиат API",
302 "fiat_balance": "Фиатный баланс",
@@ -611,6 +613,7 @@
613 "send": "Отправить",
614 "send_address": "${cryptoCurrency} адрес",
615 "send_amount": "Сумма:",
616 + "send_change_to_you": "Изменить, для вас:",
617 "send_creating_transaction": "Создать транзакцию",
618 "send_error_currency": "Валюта может содержать только цифры",
619 "send_error_minimum_value": "Mинимальная сумма 0.01",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "Подпись недопустима для данного сообщения",
681 "signTransaction": "Подписать транзакцию",
682 "signup_for_card_accept_terms": "Подпишитесь на карту и примите условия.",
683 + "silent_payment": "Молчаливый платеж",
684 "silent_payments": "Молчаливые платежи",
685 "silent_payments_always_scan": "Установить молчаливые платежи всегда сканирование",
686 "silent_payments_disclaimer": "Новые адреса не являются новыми личностями. Это повторное использование существующей идентичности с другой этикеткой.",
@@ -709,12 +713,13 @@
713 "switchToEVMCompatibleWallet": "Пожалуйста, переключитесь на кошелек, совместимый с EVM, и повторите попытку (Ethereum, Polygon).",
714 "symbol": "Символ",
715 "sync_all_wallets": "Синхронизировать все кошельки",
716 + "sync_status_attempting_scan": "Попытка сканирования",
717 "sync_status_attempting_sync": "ПОПЫТКА СИНХРОНИЗАЦИИ",
718 "sync_status_connected": "ПОДКЛЮЧЕНО",
719 "sync_status_connecting": "ПОДКЛЮЧЕНИЕ",
720 "sync_status_failed_connect": "ОТКЛЮЧЕНО",
721 "sync_status_not_connected": "НЕ ПОДКЛЮЧЁН",
717 - "sync_status_starting_scan": "Начальное сканирование",
722 + "sync_status_starting_scan": "Начальное сканирование (от ${height})",
723 "sync_status_starting_sync": "НАЧАЛО СИНХРОНИЗАЦИИ",
724 "sync_status_syncronized": "СИНХРОНИЗИРОВАН",
725 "sync_status_syncronizing": "СИНХРОНИЗАЦИЯ",
res/values/strings_th.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "แก้ไขโทเค็น",
233 "electrum_address_disclaimer": "เราสร้างที่อยู่ใหม่ทุกครั้งที่คุณใช้หนึ่งอย่าง แต่ที่อยู่เก่ายังสามารถใช้ได้ต่อไป",
234 "email_address": "ที่อยู่อีเมล",
235 + "enable_mempool_api": "Mempool API สำหรับค่าธรรมเนียมและวันที่ที่ถูกต้อง",
236 "enable_replace_by_fee": "เปิดใช้งานการเปลี่ยนโดยค่าธรรมเนียม",
236 - "enable_silent_payments_scanning": "เปิดใช้งานการสแกนการชำระเงินแบบเงียบ",
237 + "enable_silent_payments_scanning": "เริ่มสแกนการชำระเงินแบบเงียบจนกว่าจะถึงปลาย",
238 "enabled": "เปิดใช้งาน",
239 "enter_amount": "กรอกจำนวน",
240 "enter_backup_password": "ป้อนรหัสผ่านสำรองที่นี่",
@@ -295,6 +296,7 @@
296 "failed_authentication": "การยืนยันสิทธิ์ล้มเหลว ${state_error}",
297 "faq": "คำถามที่พบบ่อย",
298 "features": "คุณสมบัติ",
299 + "fee_rate": "อัตราค่าธรรมเนียม",
300 "fetching": "กำลังโหลด",
301 "fiat_api": "API สกุลเงินตรา",
302 "fiat_balance": "เฟียต บาลานซ์",
@@ -610,6 +612,7 @@
612 "send": "ส่ง",
613 "send_address": "ที่อยู่ ${cryptoCurrency}",
614 "send_amount": "จำนวน:",
615 + "send_change_to_you": "เปลี่ยนเป็นคุณ:",
616 "send_creating_transaction": "กำลังสร้างธุรกรรม",
617 "send_error_currency": "สกุลเงินสามารถเป็นเลขเท่านั้น",
618 "send_error_minimum_value": "จำนวนขั้นต่ำของจำนวนเงินคือ 0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "ลายเซ็นไม่ถูกต้องสำหรับข้อความที่ให้ไว้",
680 "signTransaction": "ลงนามในการทำธุรกรรม",
681 "signup_for_card_accept_terms": "ลงทะเบียนสำหรับบัตรและยอมรับเงื่อนไข",
682 + "silent_payment": "การชำระเงินแบบเงียบ",
683 "silent_payments": "การชำระเงินเงียบ",
684 "silent_payments_always_scan": "ตั้งค่าการชำระเงินแบบเงียบเสมอ",
685 "silent_payments_disclaimer": "ที่อยู่ใหม่ไม่ใช่ตัวตนใหม่ มันเป็นการใช้ซ้ำของตัวตนที่มีอยู่ด้วยฉลากที่แตกต่างกัน",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": "โปรดเปลี่ยนไปใช้กระเป๋าเงินที่รองรับ EVM แล้วลองอีกครั้ง (Ethereum, Polygon)",
713 "symbol": "เครื่องหมาย",
714 "sync_all_wallets": "ซิงค์กระเป๋าเงินทั้งหมด",
715 + "sync_status_attempting_scan": "พยายามสแกน",
716 "sync_status_attempting_sync": "พยายามซิงโครไนซ์",
717 "sync_status_connected": "เชื่อมต่อแล้ว",
718 "sync_status_connecting": "กำลังเชื่อมต่อ",
719 "sync_status_failed_connect": "การเชื่อมต่อล้มเหลว",
720 "sync_status_not_connected": "ไม่ได้เชื่อมต่อ",
716 - "sync_status_starting_scan": "เริ่มการสแกน",
721 + "sync_status_starting_scan": "การสแกนเริ่มต้น (จาก ${height})",
722 "sync_status_starting_sync": "กำลังเริ่มซิงโครไนซ์",
723 "sync_status_syncronized": "ซิงโครไนซ์แล้ว",
724 "sync_status_syncronizing": "กำลังซิงโครไนซ์",
res/values/strings_tl.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "I-edit ang token",
233 "electrum_address_disclaimer": "Bumubuo kami ng mga bagong address sa tuwing gagamit ka ng isa, ngunit ang mga nakaraang address ay patuloy na gumagana",
234 "email_address": "Email Address",
235 + "enable_mempool_api": "Mempool API para sa tumpak na bayad at mga petsa",
236 "enable_replace_by_fee": "Paganahin ang Replace-By-Fee",
236 - "enable_silent_payments_scanning": "Paganahin ang pag-scan ng mga tahimik na pagbabayad",
237 + "enable_silent_payments_scanning": "Simulan ang pag -scan ng tahimik na pagbabayad, hanggang sa maabot ang tip",
238 "enabled": "Pinagana",
239 "enter_amount": "Ipasok ang halaga",
240 "enter_backup_password": "Ipasok ang backup na password dito",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Nabigo ang pagpapatunay. ${state_error}",
297 "faq": "FAQ",
298 "features": "Mga tampok",
299 + "fee_rate": "Rate ng bayad",
300 "fetching": "Pagkuha",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "Balanse ng fiat",
@@ -610,6 +612,7 @@
612 "send": "Ipadala",
613 "send_address": "${cryptoCurrency} address",
614 "send_amount": "Halaga:",
615 + "send_change_to_you": "Baguhin, sa iyo:",
616 "send_creating_transaction": "Paglikha ng transaksyon",
617 "send_error_currency": "Ang halaga ay maaari lamang maglaman ng mga numero",
618 "send_error_minimum_value": "Ang minimum na halaga ay 0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "Ang lagda ay hindi wasto para sa ibinigay na mensahe",
680 "signTransaction": "Mag-sign ang Transaksyon",
681 "signup_for_card_accept_terms": "Mag-sign up para sa card at tanggapin ang mga tuntunin.",
682 + "silent_payment": "Tahimik na pagbabayad",
683 "silent_payments": "Tahimik na pagbabayad",
684 "silent_payments_always_scan": "Itakda ang mga tahimik na pagbabayad na laging nag-scan",
685 "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 @@
712 "switchToEVMCompatibleWallet": "Mangyaring lumipat sa isang EVM compatible na wallet at subukang muli (Ethereum, Polygon)",
713 "symbol": "Simbolo",
714 "sync_all_wallets": "I-sync ang lahat ng mga wallet",
715 + "sync_status_attempting_scan": "Pagtatangka ng pag -scan",
716 "sync_status_attempting_sync": "SINUSUBUKANG I-SYNC",
717 "sync_status_connected": "KONEKTADO",
718 "sync_status_connecting": "KUMOKENEKTA",
719 "sync_status_failed_connect": "NADISKONEKTA",
720 "sync_status_not_connected": "HINDI KONEKTADO",
716 - "sync_status_starting_scan": "SIMULA SA PAG-SCAN",
721 + "sync_status_starting_scan": "Simula sa pag -scan (mula sa ${height})",
722 "sync_status_starting_sync": "SIMULA SA PAG-SYNC",
723 "sync_status_syncronized": "NAKA-SYNCHRONIZE",
724 "sync_status_syncronizing": "PAG-SYNCHRONIZE",
res/values/strings_tr.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Belirteci düzenle",
233 "electrum_address_disclaimer": "Adresini her kullandığında yeni adres oluşturuyoruz, ancak önceki adresler de çalışmaya devam eder",
234 "email_address": "E-posta Adresi",
235 + "enable_mempool_api": "Doğru ücretler ve tarihler için Mempool API'si",
236 "enable_replace_by_fee": "Farklı Değiştir'i Etkinleştir",
236 - "enable_silent_payments_scanning": "Sessiz ödeme taramasını etkinleştirin",
237 + "enable_silent_payments_scanning": "Bahşiş ulaşılıncaya kadar sessiz ödemeleri taramaya başlayın",
238 "enabled": "Etkin",
239 "enter_amount": "Miktar Girin",
240 "enter_backup_password": "Yedekleme parolasını buraya gir",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Doğrulama başarısız oldu. ${state_error}",
297 "faq": "SSS",
298 "features": "Özellikler",
299 + "fee_rate": "Ücret oranı",
300 "fetching": "Getiriliyor",
301 "fiat_api": "İtibari Para API",
302 "fiat_balance": "Fiat Bakiyesi",
@@ -610,6 +612,7 @@
612 "send": "Para Gönder",
613 "send_address": "${cryptoCurrency} adresi",
614 "send_amount": "Miktar:",
615 + "send_change_to_you": "Değiştir, size:",
616 "send_creating_transaction": "İşlem oluşturuluyor",
617 "send_error_currency": "Para birimi sadece sayı içerebilir",
618 "send_error_minimum_value": "Minimum tutar değeri 0.01'dir",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "İmza verilen mesaj için geçerli değil",
680 "signTransaction": "İşlem İmzala",
681 "signup_for_card_accept_terms": "Kart için kaydol ve koşulları kabul et.",
682 + "silent_payment": "Sessiz Ödeme",
683 "silent_payments": "Sessiz ödemeler",
684 "silent_payments_always_scan": "Sessiz ödemeleri her zaman tarama ayarlayın",
685 "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 @@
712 "switchToEVMCompatibleWallet": "Lütfen EVM uyumlu bir cüzdana geçin ve tekrar deneyin (Ethereum, Polygon)",
713 "symbol": "Sembol",
714 "sync_all_wallets": "Tüm cüzdanları senkronize edin",
715 + "sync_status_attempting_scan": "Tarama deneme",
716 "sync_status_attempting_sync": "SENKRONİZE EDİLMEYE ÇALIŞILIYOR",
717 "sync_status_connected": "BAĞLANILDI",
718 "sync_status_connecting": "BAĞLANILIYOR",
719 "sync_status_failed_connect": "BAĞLANTI KESİLDİ",
720 "sync_status_not_connected": "BAĞLI DEĞİL",
716 - "sync_status_starting_scan": "Başlangıç ​​taraması",
721 + "sync_status_starting_scan": "Başlangıç ​​taraması (${height})",
722 "sync_status_starting_sync": "SENKRONİZE BAŞLATILIYOR",
723 "sync_status_syncronized": "SENKRONİZE EDİLDİ",
724 "sync_status_syncronizing": "SENKRONİZE EDİLİYOR",
res/values/strings_uk.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "Редагувати маркер",
233 "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати",
234 "email_address": "Адреса електронної пошти",
235 + "enable_mempool_api": "API Mempool для точних зборів та дат",
236 "enable_replace_by_fee": "Увімкнути заміну з комісією",
236 - "enable_silent_payments_scanning": "Увімкнути мовчазні платежі сканування",
237 + "enable_silent_payments_scanning": "Почніть сканувати мовчазні платежі, поки не буде досягнуто наконечника",
238 "enabled": "Увімкнено",
239 "enter_amount": "Введіть суму",
240 "enter_backup_password": "Введіть пароль резервної копії",
@@ -295,6 +296,7 @@
296 "failed_authentication": "Помилка аутентифікації. ${state_error}",
297 "faq": "FAQ",
298 "features": "Особливості",
299 + "fee_rate": "Ставка плати",
300 "fetching": "Завантаження",
301 "fiat_api": "Фіат API",
302 "fiat_balance": "Фіат Баланс",
@@ -611,6 +613,7 @@
613 "send": "Відправити",
614 "send_address": "${cryptoCurrency} адреса",
615 "send_amount": "Сума:",
616 + "send_change_to_you": "Зміна, для вас:",
617 "send_creating_transaction": "Створити транзакцію",
618 "send_error_currency": "Валюта може містити тільки цифри",
619 "send_error_minimum_value": "Мінімальна сума 0.01",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "Підпис не є дійсним для наведеного повідомлення",
681 "signTransaction": "Підписати транзакцію",
682 "signup_for_card_accept_terms": "Зареєструйтеся на картку та прийміть умови.",
683 + "silent_payment": "Мовчазний платіж",
684 "silent_payments": "Мовчазні платежі",
685 "silent_payments_always_scan": "Встановити мовчазні платежі завжди сканувати",
686 "silent_payments_disclaimer": "Нові адреси - це не нові ідентичності. Це повторне використання існуючої ідентичності з іншою етикеткою.",
@@ -709,12 +713,13 @@
713 "switchToEVMCompatibleWallet": "Перейдіть на гаманець, сумісний з EVM, і повторіть спробу (Ethereum, Polygon)",
714 "symbol": "символ",
715 "sync_all_wallets": "Синхронізувати всі гаманці",
716 + "sync_status_attempting_scan": "Спроба сканування",
717 "sync_status_attempting_sync": "СПРОБА СИНХРОНІЗАЦІЇ",
718 "sync_status_connected": "ПІДКЛЮЧЕНО",
719 "sync_status_connecting": "ПІДКЛЮЧЕННЯ",
720 "sync_status_failed_connect": "ВІДКЛЮЧЕНО",
721 "sync_status_not_connected": "НЕ ПІДКЛЮЧЕННИЙ",
717 - "sync_status_starting_scan": "Початок сканування",
722 + "sync_status_starting_scan": "Початок сканування (від ${height})",
723 "sync_status_starting_sync": "ПОЧАТОК СИНХРОНІЗАЦІЇ",
724 "sync_status_syncronized": "СИНХРОНІЗОВАНИЙ",
725 "sync_status_syncronizing": "СИНХРОНІЗАЦІЯ",
res/values/strings_ur.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "ٹوکن میں ترمیم کریں۔",
233 "electrum_address_disclaimer": "جب بھی آپ ایک کا استعمال کرتے ہیں تو ہم نئے پتے تیار کرتے ہیں، لیکن پچھلے پتے کام کرتے رہتے ہیں۔",
234 "email_address": "ای میل اڈریس",
235 + "enable_mempool_api": "درست فیسوں اور تاریخوں کے لئے میمپول API",
236 "enable_replace_by_fee": "فی فیس کو تبدیل کریں",
236 - "enable_silent_payments_scanning": "خاموش ادائیگیوں کو اسکیننگ کے قابل بنائیں",
237 + "enable_silent_payments_scanning": "خاموش ادائیگیوں کو اسکین کرنا شروع کریں ، جب تک کہ نوک نہ پہنچ جائے",
238 "enabled": "فعال",
239 "enter_amount": "رقم درج کریں۔",
240 "enter_backup_password": "یہاں بیک اپ پاس ورڈ درج کریں۔",
@@ -295,6 +296,7 @@
296 "failed_authentication": "ناکام تصدیق۔ ${state_error}",
297 "faq": "عمومی سوالات",
298 "features": "خصوصیات",
299 + "fee_rate": "فیس کی شرح",
300 "fetching": "لا رہا ہے۔",
301 "fiat_api": "Fiat API",
302 "fiat_balance": "فیاٹ بیلنس",
@@ -612,6 +614,7 @@
614 "send": "بھیجیں",
615 "send_address": "${cryptoCurrency} پتہ",
616 "send_amount": "رقم:",
617 + "send_change_to_you": "آپ کو تبدیل کریں:",
618 "send_creating_transaction": "لین دین کی تخلیق",
619 "send_error_currency": "کرنسی صرف نمبروں پر مشتمل ہو سکتی ہے۔",
620 "send_error_minimum_value": "رقم کی کم از کم قیمت 0.01 ہے۔",
@@ -678,6 +681,7 @@
681 "signature_invalid_error": "دستخط دیئے گئے پیغام کے لئے درست نہیں ہے",
682 "signTransaction": "۔ﮟﯾﺮﮐ ﻂﺨﺘﺳﺩ ﺮﭘ ﻦﯾﺩ ﻦﯿﻟ",
683 "signup_for_card_accept_terms": "کارڈ کے لیے سائن اپ کریں اور شرائط کو قبول کریں۔",
684 + "silent_payment": "خاموش ادائیگی",
685 "silent_payments": "خاموش ادائیگی",
686 "silent_payments_always_scan": "خاموش ادائیگی ہمیشہ اسکیننگ کریں",
687 "silent_payments_disclaimer": "نئے پتے نئی شناخت نہیں ہیں۔ یہ ایک مختلف لیبل کے ساتھ موجودہ شناخت کا دوبارہ استعمال ہے۔",
@@ -710,12 +714,13 @@
714 "switchToEVMCompatibleWallet": "(Ethereum, Polygon) ﮟﯾﺮﮐ ﺶﺷﻮﮐ ﮦﺭﺎﺑﻭﺩ ﺭﻭﺍ ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﭧﯿﻟﺍﻭ ﮯﻟﺍﻭ ﮯﻨﮭﮐﺭ ﺖﻘﺑﺎﻄﻣ ",
715 "symbol": "ﺖﻣﻼﻋ",
716 "sync_all_wallets": "تمام بٹوے کو ہم آہنگ کریں",
717 + "sync_status_attempting_scan": "اسکین کی کوشش کرنا",
718 "sync_status_attempting_sync": "ہم آہنگی کی کوشش کر رہا ہے۔",
719 "sync_status_connected": "منسلک",
720 "sync_status_connecting": "جڑ رہا ہے۔",
721 "sync_status_failed_connect": "منقطع",
722 "sync_status_not_connected": "منسلک نہیں",
718 - "sync_status_starting_scan": "اسکین شروع کرنا",
723 + "sync_status_starting_scan": "اسکین شروع کرنا (${height})",
724 "sync_status_starting_sync": "مطابقت پذیری شروع کر رہا ہے۔",
725 "sync_status_syncronized": "مطابقت پذیر",
726 "sync_status_syncronizing": "مطابقت پذیری",
res/values/strings_vi.arb
+10 -9
@@ -140,8 +140,8 @@
140 "confirm": "Xác nhận",
141 "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?",
142 "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?",
143 - "confirm_fee_deduction": "Xác nhận Khấu trừ Phí",
143 "confirm_fee_dedction_content": "Bạn có đồng ý trừ phí từ đầu ra không?",
144 + "confirm_fee_deduction": "Xác nhận Khấu trừ Phí",
145 "confirm_sending": "Xác nhận gửi",
146 "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",
147 "confirmations": "Xác nhận",
@@ -230,6 +230,7 @@
230 "edit_token": "Chỉnh sửa token",
231 "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",
232 "email_address": "Địa chỉ Email",
233 + "enable_mempool_api": "API Mempool cho các khoản phí và ngày chính xác",
234 "enable_replace_by_fee": "Bật Thay thế Bằng Phí",
235 "enable_silent_payments_scanning": "Bật quét thanh toán im lặng",
236 "enabled": "Đã bật",
@@ -298,7 +299,7 @@
299 "fiat_balance": "Số dư Fiat",
300 "field_required": "Trường này là bắt buộc",
301 "fill_code": "Vui lòng điền mã xác minh được gửi đến email của bạn",
301 - "filter_by": "Lọc theo",
302 + "filter_by": "Lọc theo",
303 "first_wallet_text": "Ví tuyệt vời cho Monero, Bitcoin, Ethereum, Litecoin, và Haven",
304 "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",
305 "fixed_rate": "Tỷ giá cố định",
@@ -398,7 +399,7 @@
399 "new_subaddress_label_name": "Tên nhãn",
400 "new_subaddress_title": "Địa chỉ mới",
401 "new_template": "Mẫu mới",
401 - "new_wallet": "Ví mới",
402 + "new_wallet": "Ví mới",
403 "newConnection": "Kết nối mới",
404 "no_cards_found": "Không tìm thấy thẻ",
405 "no_id_needed": "Không cần ID!",
@@ -498,7 +499,7 @@
499 "red_dark_theme": "Chủ đề tối đỏ",
500 "red_light_theme": "Chủ đề sáng đỏ",
501 "redeemed": "Đã đổi",
501 - "refund_address": "Địa chỉ hoàn tiền",
502 + "refund_address": "Địa chỉ hoàn tiền",
503 "reject": "Từ chối",
504 "remaining": "còn lại",
505 "remove": "Gỡ bỏ",
@@ -598,7 +599,7 @@
599 "seedtype": "Loại hạt giống",
600 "seedtype_legacy": "Di sản (25 từ)",
601 "seedtype_polyseed": "Polyseed (16 từ)",
601 - "seedtype_wownero": "Wownero (14 từ)",
602 + "seedtype_wownero": "Wownero (14 từ)",
603 "select_backup_file": "Chọn tệp sao lưu",
604 "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.",
605 "select_destination": "Vui lòng chọn đích cho tệp sao lưu.",
@@ -698,7 +699,7 @@
699 "support_description_guides": "Tài liệu và hỗ trợ cho các vấn đề phổ biến",
700 "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ợ",
701 "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",
701 - "support_title_guides": "Hướng dẫn Cake Wallet",
702 + "support_title_guides": "Hướng dẫn Cake Wallet",
703 "support_title_live_chat": "Hỗ trợ trực tiếp",
704 "support_title_other_links": "Liên kết hỗ trợ khác",
705 "sweeping_wallet": "Quét ví",
@@ -712,7 +713,7 @@
713 "sync_status_connecting": "ĐANG KẾT NỐI",
714 "sync_status_failed_connect": "ĐÃ NGẮT KẾT NỐI",
715 "sync_status_not_connected": "CHƯA KẾT NỐI",
715 - "sync_status_starting_scan": "ĐANG BẮT ĐẦU QUÉT",
716 + "sync_status_starting_scan": "ĐANG BẮT ĐẦU QUÉT (${height})",
717 "sync_status_starting_sync": "ĐANG BẮT ĐẦU ĐỒNG BỘ",
718 "sync_status_syncronized": "ĐÃ ĐỒNG BỘ",
719 "sync_status_syncronizing": "ĐANG ĐỒNG BỘ",
@@ -798,7 +799,7 @@
799 "trongrid_history": "Lịch sử TronGrid",
800 "trusted": "Đã tin cậy",
801 "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ẻ.",
801 - "tx_commit_failed": "Giao dịch không thành công. Vui lòng liên hệ với hỗ trợ.",
802 + "tx_commit_failed": "Giao dịch không thành công. Vui lòng liên hệ với hỗ trợ.",
803 "tx_invalid_input": "Bạn đang sử dụng loại đầu vào sai cho loại thanh toán này",
804 "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.",
805 "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 @@
898 "you_will_get": "Chuyển đổi thành",
899 "you_will_send": "Chuyển đổi từ",
900 "yy": "YY"
900 -}
901 +}
\ No newline at end of file
res/values/strings_yo.arb
+7 -2
@@ -233,8 +233,9 @@
233 "edit_token": "Ṣatunkọ àmi",
234 "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ẹ̀.",
235 "email_address": "Àdírẹ́sì ímeèlì",
236 + "enable_mempool_api": "Mempool API fun awọn owo deede ati awọn ọjọ",
237 "enable_replace_by_fee": "Mu ki o rọpo",
237 - "enable_silent_payments_scanning": "Mu ki awọn sisanwo ipalọlọ",
238 + "enable_silent_payments_scanning": "Bẹrẹ awọn sisanwo ipalọlọ, titi ti o fi de opin",
239 "enabled": "Wọ́n tíwọn ti tan",
240 "enter_amount": "Tẹ̀ iye",
241 "enter_backup_password": "Tẹ̀ ọ̀rọ̀ aṣínà ti ẹ̀dà ḿbí",
@@ -296,6 +297,7 @@
297 "failed_authentication": "Ìfẹ̀rílàdí pipòfo. ${state_error}",
298 "faq": "Àwọn ìbéèrè l'a máa ń bèèrè",
299 "features": "Awọn ẹya",
300 + "fee_rate": "Oṣuwọn owo ọya",
301 "fetching": "ń wá",
302 "fiat_api": "Ojú ètò áàpù owó tí ìjọba pàṣẹ wa lò",
303 "fiat_balance": "Fiat Iwontunws.funfun",
@@ -611,6 +613,7 @@
613 "send": "Ránṣẹ́",
614 "send_address": "${cryptoCurrency} àdírẹ́sì",
615 "send_amount": "Iye:",
616 + "send_change_to_you": "Yipada, si ọ:",
617 "send_creating_transaction": "Ńṣe àránṣẹ́",
618 "send_error_currency": "Ó yẹ kí òǹkà dá wà nínu iye",
619 "send_error_minimum_value": "Ránṣẹ́ owó kò kéré dé 0.01",
@@ -677,6 +680,7 @@
680 "signature_invalid_error": "Ibuwọlu ko wulo fun ifiranṣẹ ti a fun",
681 "signTransaction": "Wole Idunadura",
682 "signup_for_card_accept_terms": "Ẹ f'orúkọ sílẹ̀ láti gba káàdì àti àjọrò.",
683 + "silent_payment": "Isanwo dakẹ",
684 "silent_payments": "Awọn sisanwo ipalọlọ",
685 "silent_payments_always_scan": "Ṣeto awọn sisanwo ipalọlọ nigbagbogbo n ṣatunṣe",
686 "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 @@
713 "switchToEVMCompatibleWallet": "Jọwọ yipada si apamọwọ ibaramu EVM ki o tun gbiyanju lẹẹkansi (Ethereum, Polygon)",
714 "symbol": "Aami",
715 "sync_all_wallets": "Muṣiṣẹpọ gbogbo awọn Woleti",
716 + "sync_status_attempting_scan": "Igbiyanju ọlọjẹ",
717 "sync_status_attempting_sync": "Ń GBÌYÀNJÚ MÚDỌ́GBA",
718 "sync_status_connected": "TI DÁRAPỌ̀ MỌ́",
719 "sync_status_connecting": "Ń DÁRAPỌ̀ MỌ́",
720 "sync_status_failed_connect": "ÌKÀNPỌ̀ TI KÚ",
721 "sync_status_not_connected": "KÒ TI DÁRAPỌ̀ MỌ́ Ọ",
717 - "sync_status_starting_scan": "Bibẹrẹ ọlọjẹ",
722 + "sync_status_starting_scan": "Ibẹrẹ ọlọjẹ (lati ${height})",
723 "sync_status_starting_sync": "Ń BẸ̀RẸ̀ RẸ́",
724 "sync_status_syncronized": "TI MÚDỌ́GBA",
725 "sync_status_syncronizing": "Ń MÚDỌ́GBA",
res/values/strings_zh.arb
+7 -2
@@ -232,8 +232,9 @@
232 "edit_token": "编辑令牌",
233 "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效",
234 "email_address": "电子邮件地址",
235 + "enable_mempool_api": "Mempool API获得准确的费用和日期",
236 "enable_replace_by_fee": "启用by-Fee替换",
236 - "enable_silent_payments_scanning": "启用无声付款扫描",
237 + "enable_silent_payments_scanning": "开始扫描无声付款,直到达到提示",
238 "enabled": "启用",
239 "enter_amount": "输入金额",
240 "enter_backup_password": "在此处输入備用密码",
@@ -295,6 +296,7 @@
296 "failed_authentication": "身份验证失败. ${state_error}",
297 "faq": "FAQ",
298 "features": "特征",
299 + "fee_rate": "费率",
300 "fetching": "正在获取",
301 "fiat_api": "法币API",
302 "fiat_balance": "法币余额",
@@ -610,6 +612,7 @@
612 "send": "发送",
613 "send_address": "${cryptoCurrency} 地址",
614 "send_amount": "金额:",
615 + "send_change_to_you": "改变,向您:",
616 "send_creating_transaction": "创建交易",
617 "send_error_currency": "货币只能包含数字",
618 "send_error_minimum_value": "最小金额为0.01",
@@ -676,6 +679,7 @@
679 "signature_invalid_error": "签名对于给出的消息无效",
680 "signTransaction": "签署交易",
681 "signup_for_card_accept_terms": "注册卡并接受条款。",
682 + "silent_payment": "无声付款",
683 "silent_payments": "无声付款",
684 "silent_payments_always_scan": "设置无声付款总是扫描",
685 "silent_payments_disclaimer": "新地址不是新的身份。这是重复使用具有不同标签的现有身份。",
@@ -708,12 +712,13 @@
712 "switchToEVMCompatibleWallet": "请切换到 EVM 兼容钱包并重试(以太坊、Polygon)",
713 "symbol": "象征",
714 "sync_all_wallets": "同步所有钱包",
715 + "sync_status_attempting_scan": "尝试扫描",
716 "sync_status_attempting_sync": "嘗試同步",
717 "sync_status_connected": "已连接",
718 "sync_status_connecting": "连接中",
719 "sync_status_failed_connect": "断线",
720 "sync_status_not_connected": "未连接",
716 - "sync_status_starting_scan": "开始扫描",
721 + "sync_status_starting_scan": "启动扫描(来自 ${height})",
722 "sync_status_starting_sync": "开始同步",
723 "sync_status_syncronized": "已同步",
724 "sync_status_syncronizing": "正在同步",
tool/configure.dart
+5 -2
@@ -116,7 +116,7 @@ import 'package:cw_bitcoin/bitcoin_address_record.dart';
116 import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
117 import 'package:cw_bitcoin/litecoin_wallet_service.dart';
118 import 'package:cw_core/get_height_by_date.dart';
119 -import 'package:cw_bitcoin/script_hash.dart';
119 +import 'package:cw_core/transaction_info.dart';
120 import 'package:cw_bitcoin/bitcoin_hardware_wallet_service.dart';
121 import 'package:mobx/mobx.dart';
122 """;
@@ -211,7 +211,8 @@ abstract class Bitcoin {
211 int getEstimatedFeeWithFeeRate(Object wallet, int feeRate, int? amount,
212 {int? outputsCount, int? size});
213 int feeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size});
214 - int getHeightByDate({required DateTime date});
214 + Future<bool> checkIfMempoolAPIIsEnabled(Object wallet);
215 + Future<int> getHeightByDate({required DateTime date, bool? bitcoinMempoolAPIEnabled});
216 Future<void> rescan(Object wallet, {required int height, bool? doSingleScan});
217 Future<bool> getNodeIsElectrsSPEnabled(Object wallet);
218 void deleteSilentPaymentAddress(Object wallet, String address);
@@ -220,6 +221,8 @@ abstract class Bitcoin {
221
222 void setLedger(WalletBase wallet, Ledger ledger, LedgerDevice device);
223 Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
224 + List<Output> updateOutputs(PendingTransaction pendingTransaction, List<Output> outputs);
225 + bool txIsReceivedSilentPayment(TransactionInfo txInfo);
226 }
227 """;
228