CW-1615: Harden walletconnect auth (#3547)

* fix android CI * fix: harden walletconnect auth so a connected session won't transfer on dApp when wallet is switched within the app * refactor: improve session mgmt and better error handling, also added a loader to the listing page * feat: switch to newer id for solana dapps connections and fix requests not triggering

David Adegoke committed Aug 26, 2026 at 04:45 UTC 06e75551a77325539eabc4a0f27fb1df033e6b8a
39 files changed +495 -114
lib/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart
+192 -21
@@ -1,3 +1,4 @@
1 +import "dart:async";
2 import 'dart:convert';
3
4 import 'package:cake_wallet/di.dart';
@@ -5,6 +6,7 @@ import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
6 import 'package:cake_wallet/generated/i18n.dart';
7 import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
8 import 'package:cw_core/crypto_currency.dart';
9 +import "package:cw_core/utils/print_verbose.dart";
10 import 'package:cw_core/utils/proxy_wrapper.dart';
11 import 'package:eth_sig_util/eth_sig_util.dart';
12 import 'package:eth_sig_util/util/utils.dart';
@@ -18,6 +20,7 @@ import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wall
20 import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
21 import 'package:cake_wallet/src/screens/wallet_connect/utils/eth_utils.dart';
22 import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
23 +import "package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart";
24 import 'package:cake_wallet/store/app_store.dart';
25 import 'package:cake_wallet/.secrets.g.dart' as secrets;
26 import 'package:cake_wallet/evm/evm.dart';
@@ -82,7 +85,9 @@ class EvmChainServiceImpl {
85 if (appStore.wallet != null && isEVMCompatibleChain(appStore.wallet!.type)) {
86 final walletClient = evm?.getWeb3Client(appStore.wallet!);
87
85 - if (walletClient != null) return walletClient;
88 + if (walletClient != null) {
89 + return walletClient;
90 + }
91 }
92
93 final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
@@ -93,8 +98,18 @@ class EvmChainServiceImpl {
98 Future<void> personalSign(String topic, dynamic parameters) async {
99 debugPrint('personalSign request: $parameters');
100
96 - final pRequest = walletKit.pendingRequests.getAll().last;
101 + final pRequest = _pendingRequest(topic, EVMSupportedMethods.personalSign.name);
102 + if (pRequest == null) {
103 + return;
104 + }
105 +
106 final address = EthUtils.getAddressFromSessionRequest(pRequest);
107 +
108 + if (!_isRequestAuthorized(topic, requestAddress: address)) {
109 + await _rejectUnauthorizedRequest(topic, pRequest.id);
110 + return;
111 + }
112 +
113 final data = EthUtils.getDataFromSessionRequest(pRequest);
114 final message = EthUtils.getUtf8Message(data.toString());
115 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -104,6 +119,7 @@ class EvmChainServiceImpl {
119 method: pRequest.method,
120 chainId: pRequest.chainId,
121 address: address,
122 + topic: topic,
123 transportType: pRequest.transportType.name,
124 verifyContext: pRequest.verifyContext,
125 );
@@ -141,8 +157,18 @@ class EvmChainServiceImpl {
157 Future<void> ethSign(String topic, dynamic parameters) async {
158 debugPrint('ethSign request: $parameters');
159
144 - final pRequest = walletKit.pendingRequests.getAll().last;
160 + final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSign.name);
161 + if (pRequest == null) {
162 + return;
163 + }
164 +
165 final address = EthUtils.getAddressFromSessionRequest(pRequest);
166 +
167 + if (!_isRequestAuthorized(topic, requestAddress: address)) {
168 + await _rejectUnauthorizedRequest(topic, pRequest.id);
169 + return;
170 + }
171 +
172 final data = EthUtils.getDataFromSessionRequest(pRequest);
173 final message = EthUtils.getUtf8Message(data.toString());
174 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -152,6 +178,7 @@ class EvmChainServiceImpl {
178 method: pRequest.method,
179 chainId: pRequest.chainId,
180 address: address,
181 + topic: topic,
182 transportType: pRequest.transportType.name,
183 verifyContext: pRequest.verifyContext,
184 );
@@ -189,8 +216,18 @@ class EvmChainServiceImpl {
216 Future<void> ethSignTypedData(String topic, dynamic parameters) async {
217 debugPrint('ethSignTypedData request: $parameters');
218
192 - final pRequest = walletKit.pendingRequests.getAll().last;
219 + final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTypedData.name);
220 + if (pRequest == null) {
221 + return;
222 + }
223 +
224 final address = EthUtils.getAddressFromSessionRequest(pRequest);
225 +
226 + if (!_isRequestAuthorized(topic, requestAddress: address)) {
227 + await _rejectUnauthorizedRequest(topic, pRequest.id);
228 + return;
229 + }
230 +
231 final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
232 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
233
@@ -199,6 +236,7 @@ class EvmChainServiceImpl {
236 method: pRequest.method,
237 chainId: pRequest.chainId,
238 address: address,
239 + topic: topic,
240 transportType: pRequest.transportType.name,
241 verifyContext: pRequest.verifyContext,
242 );
@@ -236,8 +274,18 @@ class EvmChainServiceImpl {
274
275 final permitRequestMessage = await extractPermitData(parameters);
276
239 - final pRequest = walletKit.pendingRequests.getAll().last;
277 + final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTypedDataV4.name);
278 + if (pRequest == null) {
279 + return;
280 + }
281 +
282 final address = EthUtils.getAddressFromSessionRequest(pRequest);
283 +
284 + if (!_isRequestAuthorized(topic, requestAddress: address)) {
285 + await _rejectUnauthorizedRequest(topic, pRequest.id);
286 + return;
287 + }
288 +
289 final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
290 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
291
@@ -246,6 +294,7 @@ class EvmChainServiceImpl {
294 method: pRequest.method,
295 chainId: pRequest.chainId,
296 address: address,
297 + topic: topic,
298 transportType: pRequest.transportType.name,
299 verifyContext: pRequest.verifyContext,
300 );
@@ -280,10 +329,22 @@ class EvmChainServiceImpl {
329 Future<void> ethSignTransaction(String topic, dynamic parameters) async {
330 debugPrint('ethSignTransaction request: $parameters');
331
283 - final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
332 + final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTransaction.name);
333 + if (pRequest == null) {
334 + return;
335 + }
336 +
337 final data = EthUtils.getTransactionFromSessionRequest(pRequest);
338
286 - if (data == null) return;
339 + if (data == null) {
340 + _respondMalformedRequest(topic, pRequest.id);
341 + return;
342 + }
343 +
344 + if (!_isRequestAuthorized(topic, requestAddress: data['from']?.toString())) {
345 + await _rejectUnauthorizedRequest(topic, pRequest.id);
346 + return;
347 + }
348
349 final address = EthUtils.getAddressFromSessionRequest(pRequest);
350 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -293,6 +354,7 @@ class EvmChainServiceImpl {
354 method: pRequest.method,
355 chainId: pRequest.chainId,
356 address: address,
357 + topic: topic,
358 transportType: pRequest.transportType.name,
359 verifyContext: pRequest.verifyContext,
360 );
@@ -333,10 +395,21 @@ class EvmChainServiceImpl {
395
396 Future<void> ethSendTransaction(String topic, dynamic parameters) async {
397 debugPrint('ethSendTransaction request: $parameters');
336 - final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
398 + final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSendTransaction.name);
399 + if (pRequest == null) {
400 + return;
401 + }
402
403 final data = EthUtils.getTransactionFromSessionRequest(pRequest);
339 - if (data == null) return;
404 + if (data == null) {
405 + _respondMalformedRequest(topic, pRequest.id);
406 + return;
407 + }
408 +
409 + if (!_isRequestAuthorized(topic, requestAddress: data['from']?.toString())) {
410 + await _rejectUnauthorizedRequest(topic, pRequest.id);
411 + return;
412 + }
413
414 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
415
@@ -344,6 +417,7 @@ class EvmChainServiceImpl {
417 data,
418 method: pRequest.method,
419 chainId: pRequest.chainId,
420 + topic: topic,
421 transportType: pRequest.transportType.name,
422 verifyContext: pRequest.verifyContext,
423 );
@@ -379,6 +453,77 @@ class EvmChainServiceImpl {
453 _handleResponseForTopic(topic, response);
454 }
455
456 + void _respondMalformedRequest(String topic, int requestId) {
457 + final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
458 + _handleResponseForTopic(
459 + topic,
460 + JsonRpcResponse(
461 + id: requestId,
462 + jsonrpc: "2.0",
463 + error: JsonRpcError(code: error.code, message: error.message),
464 + ),
465 + );
466 + }
467 +
468 + SessionRequest? _pendingRequest(String topic, String method) {
469 + final matches = walletKit.pendingRequests
470 + .getAll()
471 + .where((request) => request.topic == topic && request.method == method);
472 +
473 + return matches.isEmpty ? null : matches.last;
474 + }
475 +
476 + bool _isRequestAuthorized(String topic, {String? requestAddress}) {
477 + final wallet = appStore.wallet;
478 + if (wallet == null) {
479 + return false;
480 + }
481 +
482 + final keys = wcKeyService.getKeysForChain(wallet);
483 + if (keys.isEmpty) {
484 + return false;
485 + }
486 +
487 + final walletAddress = keys.first.publicKey;
488 +
489 + if (!MethodsUtils.isSessionOwnedByWallet(walletKit.sessions.get(topic), walletAddress)) {
490 + return false;
491 + }
492 +
493 + if (requestAddress != null && !MethodsUtils.isSameAccount(requestAddress, walletAddress)) {
494 + return false;
495 + }
496 +
497 + return true;
498 + }
499 +
500 + Future<void> _rejectUnauthorizedRequest(String topic, int requestId) async {
501 + unawaited(
502 + bottomSheetService.queueBottomSheet(
503 + isModalDismissible: true,
504 + widget: BottomSheetMessageDisplayWidget(
505 + message: S.current.wc_request_for_different_wallet,
506 + ),
507 + ),
508 + );
509 +
510 + try {
511 + await walletKit.respondSessionRequest(
512 + topic: topic,
513 + response: JsonRpcResponse(
514 + id: requestId,
515 + jsonrpc: "2.0",
516 + error: const JsonRpcError(
517 + code: 4100,
518 + message: "The requested account has not been authorized by the user.",
519 + ),
520 + ),
521 + );
522 + } catch (e) {
523 + printV("rejectUnauthorizedRequest: $e");
524 + }
525 + }
526 +
527 void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
528 final session = walletKit.sessions.get(topic);
529
@@ -388,7 +533,9 @@ class EvmChainServiceImpl {
533 response: response,
534 );
535
391 - if (session == null) return;
536 + if (session == null) {
537 + return;
538 + }
539
540 MethodsUtils.handleRedirect(
541 topic,
@@ -397,7 +544,9 @@ class EvmChainServiceImpl {
544 response.error == null,
545 );
546 } on ReownSignError catch (error) {
400 - if (session == null) return;
547 + if (session == null) {
548 + return;
549 + }
550
551 MethodsUtils.handleRedirect(
552 topic,
@@ -413,6 +562,7 @@ class EvmChainServiceImpl {
562 String? method,
563 String? chainId,
564 String? address,
565 + String? topic,
566 VerifyContext? verifyContext,
567 required String transportType,
568 }) async {
@@ -456,6 +606,7 @@ class EvmChainServiceImpl {
606 method: method,
607 chainId: chainId,
608 address: address ?? transaction.from?.hex ?? '',
609 + topic: topic,
610 transportType: transportType,
611 verifyContext: verifyContext,
612 extraModels: feeRows,
@@ -472,13 +623,17 @@ class EvmChainServiceImpl {
623 String nativeSymbol,
624 ) {
625 final gasLimit = transaction.maxGas;
475 - if (gasLimit == null || gasLimit <= 0) return const [];
626 + if (gasLimit == null || gasLimit <= 0) {
627 + return const [];
628 + }
629
630 final gasLimitBig = BigInt.from(gasLimit);
631 final isEip1559 = transaction.isEIP1559;
632 final perGasWei =
633 isEip1559 ? transaction.maxFeePerGas?.getInWei : transaction.gasPrice?.getInWei;
481 - if (perGasWei == null || perGasWei <= BigInt.zero) return const [];
634 + if (perGasWei == null || perGasWei <= BigInt.zero) {
635 + return const [];
636 + }
637
638 final feeWei = gasLimitBig * perGasWei;
639 final feeNative = feeWei.toDouble() / 1e18;
@@ -500,19 +655,25 @@ class EvmChainServiceImpl {
655 ) {
656 final cryptoPart = '${_formatNativeAmount(feeNative)} $nativeSymbol';
657
503 - if (nativeCurrency == null) return cryptoPart;
658 + if (nativeCurrency == null) {
659 + return cryptoPart;
660 + }
661
662 try {
663 final fiatStore = getIt.get<FiatConversionStore>();
664 final price = fiatStore.prices[nativeCurrency];
508 - if (price == null || price <= 0) return cryptoPart;
665 + if (price == null || price <= 0) {
666 + return cryptoPart;
667 + }
668
669 final fiatSymbol = appStore.settingsStore.fiatCurrency.title;
670 final fiatValue = calculateFiatAmount(
671 price: price,
672 cryptoAmount: feeNative.toString(),
673 );
515 - if (fiatValue.isEmpty || fiatValue == '0.00') return cryptoPart;
674 + if (fiatValue.isEmpty || fiatValue == '0.00') {
675 + return cryptoPart;
676 + }
677
678 return '$cryptoPart (~ $fiatValue $fiatSymbol)';
679 } catch (_) {
@@ -521,14 +682,20 @@ class EvmChainServiceImpl {
682 }
683
684 String _formatNativeAmount(double value) {
524 - if (value == 0) return '0';
525 - if (value >= 0.0001) return value.toStringAsFixed(6);
685 + if (value == 0) {
686 + return '0';
687 + }
688 + if (value >= 0.0001) {
689 + return value.toStringAsFixed(6);
690 + }
691 return value.toStringAsExponential(4);
692 }
693
694 Future<Transaction> _ensureWCTransactionHasGasLimit(Transaction transaction) async {
695 final hasGasLimit = transaction.maxGas != null && transaction.maxGas! > 0;
531 - if (hasGasLimit) return transaction;
696 + if (hasGasLimit) {
697 + return transaction;
698 + }
699
700 final hint = transaction.gasPrice ?? transaction.maxFeePerGas ?? await ethClient.getGasPrice();
701
@@ -689,7 +856,9 @@ $messageDetails''';
856 final fieldType = field['type'] as String;
857 final value = message[field['name'] as String];
858
692 - if (value == null) continue;
859 + if (value == null) {
860 + continue;
861 + }
862
863 if (types.containsKey(fieldType)) {
864 final nestedFields = types[fieldType] as List<dynamic>;
@@ -714,7 +883,9 @@ $messageDetails''';
883 }
884
885 String _toCamelCase(String input) {
717 - if (input.isEmpty) return input;
886 + if (input.isEmpty) {
887 + return input;
888 + }
889 return input[0].toUpperCase() + input.substring(1).toLowerCase();
890 }
891
lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart
+4 -2
@@ -1,4 +1,4 @@
1 -enum SolanaChainId { mainnet, devnet, testnet }
1 +enum SolanaChainId { mainnet, mainnetLegacy, devnet, testnet }
2
3 extension SolanaChainIdX on SolanaChainId {
4 String chain() {
@@ -6,8 +6,10 @@ extension SolanaChainIdX on SolanaChainId {
6
7 switch (this) {
8 case SolanaChainId.mainnet:
9 + name = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
10 + break;
11 + case SolanaChainId.mainnetLegacy:
12 name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
10 - // '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
13 break;
14 case SolanaChainId.devnet:
15 name = 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1';
lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_service.dart
+86 -3
@@ -1,16 +1,20 @@
1 +import "dart:async";
2 import 'dart:convert';
3
4 import 'package:blockchain_utils/base58/base58.dart';
5 import 'package:blockchain_utils/blockchain_utils.dart' as blockchain_utils;
6 import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_supported_methods.dart';
7 +import "package:cw_core/utils/print_verbose.dart";
8 import 'package:flutter/material.dart';
9 import 'package:on_chain/solana/solana.dart';
10 import 'package:reown_walletkit/reown_walletkit.dart';
11
12 +import "package:cake_wallet/generated/i18n.dart";
13 import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
14 import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart';
15 import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
16 import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
17 +import "package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart";
18 import 'package:cake_wallet/store/app_store.dart';
19
20 class SolanaChainService {
@@ -47,7 +51,16 @@ class SolanaChainService {
51 Future<void> solanaSignMessage(String topic, dynamic parameters) async {
52 debugPrint('solanaSignMessage request: $parameters');
53
50 - final pRequest = walletKit.pendingRequests.getAll().last;
54 + final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignMessage.name);
55 + if (pRequest == null) {
56 + return;
57 + }
58 +
59 + if (!_isRequestAuthorized(topic)) {
60 + await _rejectUnauthorizedRequest(topic, pRequest.id);
61 + return;
62 + }
63 +
64 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
65
66 try {
@@ -65,6 +78,7 @@ class SolanaChainService {
78 method: pRequest.method,
79 chainId: pRequest.chainId,
80 address: privateKey.publicKey().toAddress().address,
81 + topic: topic,
82 transportType: pRequest.transportType.name,
83 );
84
@@ -95,7 +109,16 @@ class SolanaChainService {
109 Future<void> solanaSignTransaction(String topic, dynamic parameters) async {
110 debugPrint('solanaSignTransaction: ${jsonEncode(parameters)}');
111
98 - final pRequest = walletKit.pendingRequests.getAll().last;
112 + final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignTransaction.name);
113 + if (pRequest == null) {
114 + return;
115 + }
116 +
117 + if (!_isRequestAuthorized(topic)) {
118 + await _rejectUnauthorizedRequest(topic, pRequest.id);
119 + return;
120 + }
121 +
122 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
123
124 try {
@@ -130,6 +153,7 @@ class SolanaChainService {
153 method: pRequest.method,
154 chainId: pRequest.chainId,
155 address: privateKey.publicKey().toAddress().address,
156 + topic: topic,
157 transportType: pRequest.transportType.name,
158 );
159
@@ -160,7 +184,16 @@ class SolanaChainService {
184 Future<void> solanaSignAllTransaction(String topic, dynamic parameters) async {
185 debugPrint('solanaSignAllTransaction: ${jsonEncode(parameters)}');
186
163 - final pRequest = walletKit.pendingRequests.getAll().last;
187 + final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignAllTransaction.name);
188 + if (pRequest == null) {
189 + return;
190 + }
191 +
192 + if (!_isRequestAuthorized(topic)) {
193 + await _rejectUnauthorizedRequest(topic, pRequest.id);
194 + return;
195 + }
196 +
197 var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
198
199 try {
@@ -174,6 +207,7 @@ class SolanaChainService {
207 method: pRequest.method,
208 chainId: pRequest.chainId,
209 address: privateKey.publicKey().toAddress().address,
210 + topic: topic,
211 transportType: pRequest.transportType.name,
212 );
213
@@ -224,6 +258,55 @@ class SolanaChainService {
258 return SolanaPrivateKey.fromSeedHex(keys[0].privateKey);
259 }
260
261 + SessionRequest? _pendingRequest(String topic, String method) {
262 + final matches = walletKit.pendingRequests
263 + .getAll()
264 + .where((request) => request.topic == topic && request.method == method);
265 +
266 + return matches.isEmpty ? null : matches.last;
267 + }
268 +
269 + bool _isRequestAuthorized(String topic) {
270 + final wallet = appStore.wallet;
271 + if (wallet == null) {
272 + return false;
273 + }
274 +
275 + final keys = wcKeyService.getKeysForChain(wallet);
276 + if (keys.isEmpty) {
277 + return false;
278 + }
279 +
280 + return MethodsUtils.isSessionOwnedByWallet(walletKit.sessions.get(topic), keys.first.publicKey);
281 + }
282 +
283 + Future<void> _rejectUnauthorizedRequest(String topic, int requestId) async {
284 + unawaited(
285 + bottomSheetService.queueBottomSheet(
286 + isModalDismissible: true,
287 + widget: BottomSheetMessageDisplayWidget(
288 + message: S.current.wc_request_for_different_wallet,
289 + ),
290 + ),
291 + );
292 +
293 + try {
294 + await walletKit.respondSessionRequest(
295 + topic: topic,
296 + response: JsonRpcResponse(
297 + id: requestId,
298 + jsonrpc: "2.0",
299 + error: const JsonRpcError(
300 + code: 4100,
301 + message: "The requested account has not been authorized by the user.",
302 + ),
303 + ),
304 + );
305 + } catch (e) {
306 + printV("rejectUnauthorizedRequest: $e");
307 + }
308 + }
309 +
310 void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
311 final session = walletKit.sessions.get(topic);
312
lib/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart
+30 -24
@@ -43,30 +43,36 @@ class KeyServiceImpl implements WalletConnectKeyService {
43
44 @override
45 List<ChainKeyModel> getKeys(WalletBase wallet) {
46 - final keys = [
47 - ChainKeyModel(
48 - chains: [
49 - 'eip155:1',
50 - 'eip155:5',
51 - 'eip155:56',
52 - 'eip155:137',
53 - 'eip155:8453',
54 - 'eip155:42161',
55 - 'eip155:80001',
56 - ],
57 - privateKey: _getPrivateKeyForWallet(wallet),
58 - publicKey: _getPublicKeyForWallet(wallet),
59 - ),
60 - ChainKeyModel(
61 - chains: [
62 - 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ', // main-net
63 - 'solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K', // test-net
64 - ],
65 - privateKey: _getPrivateKeyForWallet(wallet),
66 - publicKey: _getPublicKeyForWallet(wallet),
67 - ),
68 - ];
69 - return keys;
46 + if (isEVMCompatibleChain(wallet.type)) {
47 + return [
48 + ChainKeyModel(
49 + chains: [
50 + 'eip155:1',
51 + 'eip155:56',
52 + 'eip155:137',
53 + 'eip155:8453',
54 + 'eip155:42161',
55 + ],
56 + privateKey: _getPrivateKeyForWallet(wallet),
57 + publicKey: _getPublicKeyForWallet(wallet),
58 + ),
59 + ];
60 + }
61 +
62 + if (wallet.type == WalletType.solana) {
63 + return [
64 + ChainKeyModel(
65 + chains: [
66 + 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // main-net
67 + 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ', // legacy main-net id older dapps still use
68 + ],
69 + privateKey: _getPrivateKeyForWallet(wallet),
70 + publicKey: _getPublicKeyForWallet(wallet),
71 + ),
72 + ];
73 + }
74 +
75 + return [];
76 }
77
78 @override
lib/src/screens/wallet_connect/services/walletkit_service.dart
+85 -58
@@ -3,7 +3,6 @@ import 'dart:convert';
3 import 'dart:typed_data';
4
5 import 'package:cw_core/utils/print_verbose.dart';
6 -import 'package:cw_core/wallet_type.dart';
6 import 'package:eth_sig_util/util/utils.dart';
7 import 'package:flutter/material.dart';
8 import 'package:mobx/mobx.dart';
@@ -42,7 +41,8 @@ abstract class WalletKitServiceBase with Store {
41 ) : pairings = ObservableList<PairingInfo>(),
42 sessions = ObservableList<SessionData>(),
43 auth = ObservableList<PendingSessionAuthRequest>(),
45 - isInitialized = false;
44 + isInitialized = false,
45 + isLoadingConnections = true;
46
47 final AppStore appStore;
48 final SharedPreferences sharedPreferences;
@@ -54,6 +54,9 @@ abstract class WalletKitServiceBase with Store {
54 @observable
55 bool isInitialized;
56
57 + @observable
58 + bool isLoadingConnections;
59 +
60 /// The list of requests from the dapp
61 @observable
62 ObservableList<PairingInfo> pairings;
@@ -91,33 +94,23 @@ abstract class WalletKitServiceBase with Store {
94 _walletKit.onSessionProposal.subscribe(_onSessionProposal);
95 _walletKit.onSessionProposalError.subscribe(_onSessionProposalError);
96 _walletKit.onSessionConnect.subscribe(_onSessionConnect);
94 - _walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
97 +
98 + if (isEVMCompatibleChain(appStore.wallet!.type)) {
99 + _walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
100 + }
101
102 _walletKit.pairings.onSync.subscribe(_onPairingsSync);
103 _walletKit.core.pairing.onPairingDelete.subscribe(_onPairingDelete);
104 _walletKit.core.pairing.onPairingExpire.subscribe(_onPairingDelete);
105
106 // Setup our accounts
101 - List<ChainKeyModel> chainKeys = walletKeyService.getKeys(appStore.wallet!);
107 + final chainKeys = walletKeyService.getKeys(appStore.wallet!);
108 for (final chainKey in chainKeys) {
109 for (final chainId in chainKey.chains) {
104 - if (isEVMCompatibleChain(appStore.wallet!.type)) {
105 - // Register account for all EVM chains (chainId is already in eip155:format)
106 - _walletKit.registerAccount(
107 - chainId: chainId,
108 - accountAddress: chainKey.publicKey,
109 - );
110 - } else {
111 - final chainNameSpace = getChainNameSpaceAndIdBasedOnWalletType(
112 - appStore.wallet!.type,
113 - );
114 - if (chainNameSpace == chainId) {
115 - _walletKit.registerAccount(
116 - chainId: chainId,
117 - accountAddress: chainKey.publicKey,
118 - );
119 - }
120 - }
110 + _walletKit.registerAccount(
111 + chainId: chainId,
112 + accountAddress: chainKey.publicKey,
113 + );
114 }
115 }
116 }
@@ -144,42 +137,43 @@ abstract class WalletKitServiceBase with Store {
137 }
138 }
139
147 - await _emitEvent();
148 -
140 _refreshPairings();
141
151 - sessions.clear();
152 - auth.clear();
142 + _reloadSessionsForCurrentWallet();
143
154 - final newSessions = _walletKit.sessions.getAll();
155 - sessions.addAll(newSessions);
144 + auth.clear();
145
146 final newAuthRequests = _walletKit.sessionAuthRequests.getAll();
147 auth.addAll(newAuthRequests);
148
160 - if (isEVMCompatibleChain(appStore.wallet!.type)) {
161 - for (final cId in EVMChainId.values) {
162 - EvmChainServiceImpl(
163 - reference: cId,
164 - appStore: appStore,
165 - wcKeyService: walletKeyService,
166 - bottomSheetService: _bottomSheetHandler,
167 - walletKit: _walletKit,
168 - );
169 - }
149 + isLoadingConnections = false;
150 + for (final cId in EVMChainId.values) {
151 + EvmChainServiceImpl(
152 + reference: cId,
153 + appStore: appStore,
154 + wcKeyService: walletKeyService,
155 + bottomSheetService: _bottomSheetHandler,
156 + walletKit: _walletKit,
157 + );
158 }
159
172 - if (appStore.wallet!.type == WalletType.solana) {
173 - for (final cId in SolanaChainId.values) {
174 - SolanaChainService(
175 - reference: cId,
176 - appStore: appStore,
177 - wcKeyService: walletKeyService,
178 - bottomSheetService: _bottomSheetHandler,
179 - walletKit: _walletKit,
180 - );
181 - }
160 + for (final cId in SolanaChainId.values) {
161 + SolanaChainService(
162 + reference: cId,
163 + appStore: appStore,
164 + wcKeyService: walletKeyService,
165 + bottomSheetService: _bottomSheetHandler,
166 + walletKit: _walletKit,
167 + );
168 }
169 +
170 + unawaited(() async {
171 + try {
172 + await _emitEvent();
173 + } catch (e) {
174 + printV("emitEvent failed: $e");
175 + }
176 + }());
177 }
178
179 @action
@@ -195,6 +189,10 @@ abstract class WalletKitServiceBase with Store {
189 for (var session in engineSessions) {
190 final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
191 for (var chain in chainKeys) {
192 + if (!MethodsUtils.isSessionOwnedByWallet(session, chain.publicKey)) {
193 + continue;
194 + }
195 +
196 for (var chainID in chain.chains) {
197 try {
198 final events = NamespaceUtils.getNamespacesEventsForChain(
@@ -228,8 +226,21 @@ abstract class WalletKitServiceBase with Store {
226 }
227
228 @action
231 - FutureOr<void> onDispose() {
232 - log('walletKit dispose');
229 + void resetConnectionsState() {
230 + sessions.clear();
231 + auth.clear();
232 + pairings.clear();
233 +
234 + isInitialized = false;
235 + isLoadingConnections = true;
236 + }
237 +
238 + @action
239 + Future<void> onDispose() async {
240 + log("walletKit dispose");
241 +
242 + resetConnectionsState();
243 +
244 _walletKit.core.removeLogListener(_logListener);
245
246 _walletKit.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid);
@@ -246,11 +257,11 @@ abstract class WalletKitServiceBase with Store {
257 _walletKit.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
258 _walletKit.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
259
249 - sessions.clear();
250 - auth.clear();
251 - pairings.clear();
252 -
253 - isInitialized = false;
260 + try {
261 + await _walletKit.core.relayClient.disconnect().timeout(const Duration(seconds: 3));
262 + } catch (e) {
263 + printV("walletKit relay disconnect: $e");
264 + }
265 }
266
267 ReownWalletKit get walletKit => _walletKit;
@@ -534,8 +545,7 @@ abstract class WalletKitServiceBase with Store {
545 }
546
547 await _removePairingTopicFromLocalStorage(topic);
537 - sessions.clear();
538 - sessions.addAll(_walletKit.sessions.getAll());
548 + _reloadSessionsForCurrentWallet();
549 _refreshPairings();
550 }
551
@@ -559,8 +569,7 @@ abstract class WalletKitServiceBase with Store {
569 printV('disconnectSession: $e');
570 }
571
562 - sessions.clear();
563 - sessions.addAll(_walletKit.sessions.getAll());
572 + _reloadSessionsForCurrentWallet();
573
574 if (pairingTopic != null &&
575 !_walletKit.sessions.getAll().any((s) => s.pairingTopic == pairingTopic)) {
@@ -619,6 +628,24 @@ abstract class WalletKitServiceBase with Store {
628 pairings.addAll(filteredPairings);
629 }
630
631 + @action
632 + void _reloadSessionsForCurrentWallet() {
633 + sessions.clear();
634 +
635 + final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
636 + if (chainKeys.isEmpty) {
637 + return;
638 + }
639 +
640 + final walletPublicKey = chainKeys.first.publicKey;
641 +
642 + sessions.addAll(
643 + _walletKit.sessions
644 + .getAll()
645 + .where((session) => MethodsUtils.isSessionOwnedByWallet(session, walletPublicKey)),
646 + );
647 + }
648 +
649 @action
650 List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
651 return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
lib/src/screens/wallet_connect/utils/method_utils.dart
+27 -3
@@ -11,9 +11,27 @@ import 'package:flutter/material.dart';
11 import 'package:reown_walletkit/reown_walletkit.dart';
12
13 class MethodsUtils {
14 - static final walletKit = getIt.get<WalletKitService>().walletKit;
14 + static ReownWalletKit get walletKit => getIt.get<WalletKitService>().walletKit;
15 static final bottomSheetService = getIt.get<BottomSheetService>();
16
17 + static bool isSessionOwnedByWallet(SessionData? session, String walletPublicKey) {
18 + if (session == null || walletPublicKey.isEmpty) {
19 + return false;
20 + }
21 +
22 + final accounts = session.namespaces.values.expand((namespace) => namespace.accounts);
23 +
24 + return accounts.any((account) => isSameAccount(account.split(":").last, walletPublicKey));
25 + }
26 +
27 + static bool isSameAccount(String a, String b) {
28 + if (a.startsWith("0x") && b.startsWith("0x")) {
29 + return a.toLowerCase() == b.toLowerCase();
30 + }
31 +
32 + return a == b;
33 + }
34 +
35 static const _transactionMethods = {
36 'eth_sendTransaction',
37 'eth_signTransaction',
@@ -28,13 +46,19 @@ class MethodsUtils {
46 String? method,
47 String? chainId,
48 String? address,
49 + String? topic,
50 required String transportType,
51 List<WCConnectionModel> extraModels = const [],
52 VerifyContext? verifyContext,
53 }) async {
54 final appStore = getIt.get<AppStore>();
36 - final pending = walletKit.pendingRequests.getAll();
37 - final session = pending.isNotEmpty ? walletKit.sessions.get(pending.last.topic) : null;
55 + SessionData? session;
56 + if (topic != null) {
57 + session = walletKit.sessions.get(topic);
58 + } else {
59 + final pending = walletKit.pendingRequests.getAll();
60 + session = pending.isNotEmpty ? walletKit.sessions.get(pending.last.topic) : null;
61 + }
62 final dAppMetadata = session?.peer.metadata;
63
64 final isTransaction = method != null && _transactionMethods.contains(method);
lib/src/screens/wallet_connect/wc_connections_listing_view.dart
+21
@@ -12,6 +12,7 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
12 import 'package:cake_wallet/utils/device_info.dart';
13 import 'package:cake_wallet/utils/permission_handler.dart';
14 import 'package:cake_wallet/utils/show_pop_up.dart';
15 +import "package:flutter/cupertino.dart";
16 import 'package:flutter/material.dart';
17 import 'package:flutter_mobx/flutter_mobx.dart';
18 import 'package:permission_handler/permission_handler.dart';
@@ -145,6 +146,26 @@ class WalletConnectConnectionsView extends StatelessWidget {
146 const SizedBox(height: 24),
147 Observer(
148 builder: (_) {
149 + if (walletKitService.isLoadingConnections) {
150 + return Padding(
151 + padding: const EdgeInsets.symmetric(vertical: 32),
152 + child: Center(
153 + child: Column(
154 + spacing: 12,
155 + children: [
156 + const CupertinoActivityIndicator(),
157 + Text(
158 + "${S.of(context).loading}...",
159 + style: theme.textTheme.bodyMedium?.copyWith(
160 + color: colors.onSurfaceVariant,
161 + ),
162 + ),
163 + ],
164 + ),
165 + ),
166 + );
167 + }
168 +
169 if (walletKitService.pairings.isEmpty) {
170 return Padding(
171 padding: const EdgeInsets.symmetric(vertical: 32),
lib/store/app_store.dart
+19 -3
@@ -1,5 +1,3 @@
1 -import "dart:async";
2 -
1 import "package:cake_wallet/core/amount_parsing_proxy.dart";
2 import "package:cake_wallet/di.dart";
3 import "package:cake_wallet/entities/preferences_key.dart";
@@ -60,13 +58,17 @@ abstract class AppStoreBase with Store {
58 Future<void> changeCurrentWallet(
59 WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
60 final changingToSameWalletType = this.wallet?.type == wallet.type;
61 + final previousWalletType = this.wallet?.type;
62
63 await this.wallet?.close(shouldCleanup: !changingToSameWalletType);
64 this.wallet = wallet;
65 this.wallet!.setExceptionHandler(ExceptionHandler.onError);
66
67 if (isWalletConnectCompatibleChain(wallet.type)) {
69 - unawaited(_setupWalletConnect());
68 + getIt.get<WalletKitService>().resetConnectionsState();
69 + _queueWalletConnectAction(_setupWalletConnect);
70 + } else if (previousWalletType != null && isWalletConnectCompatibleChain(previousWalletType)) {
71 + _queueWalletConnectAction(_disposeWalletConnect);
72 }
73 await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
74 await getIt
@@ -74,6 +76,12 @@ abstract class AppStoreBase with Store {
76 .setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
77 }
78
79 + Future<void> _lastWalletConnectAction = Future.value();
80 +
81 + void _queueWalletConnectAction(Future<void> Function() action) {
82 + _lastWalletConnectAction = _lastWalletConnectAction.then((_) => action());
83 + }
84 +
85 Future<void> _setupWalletConnect() async {
86 try {
87 final wcService = getIt.get<WalletKitService>();
@@ -84,4 +92,12 @@ abstract class AppStoreBase with Store {
92 printV("WalletConnect setup failed: $e\n$s");
93 }
94 }
95 +
96 + Future<void> _disposeWalletConnect() async {
97 + try {
98 + await getIt.get<WalletKitService>().onDispose();
99 + } catch (e) {
100 + printV("WalletConnect teardown failed: $e");
101 + }
102 + }
103 }
res/values/strings_ar.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "توقيع الرسائل والبيانات المكتوبة",
1422 "wc_permission_switch_chains": "قم بالتبديل وإضافة سلاسل EVM",
1423 "wc_permission_view_balance": "عرض رصيد محفظتك ونشاطك",
1424 + "wc_request_for_different_wallet": "تم تقديم هذا الطلب لمحفظة مختلفة. افتح المحفظة المتصلة بهذا التطبيق وحاول مرة أخرى.",
1425 "wc_scam_warning_message": "يبدو أن هذا الطلب مرسل من عملية احتيال معروفة. يرجى المضي قدما بحذر.",
1426 "wc_scam_warning_title": "تحذير!",
1427 "wc_scan_qr": "مسح QR",
res/values/strings_bg.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Подписвайте съобщения и въведени данни",
1422 "wc_permission_switch_chains": "Превключете и добавете EVM вериги",
1423 "wc_permission_view_balance": "Вижте баланса и активността на вашия портфейл",
1424 + "wc_request_for_different_wallet": "Тази заявка е направена за различен портфейл. Отворете портфейла, свързан с това приложение, и опитайте отново.",
1425 "wc_scam_warning_message": "Тази заявка изглежда е от известна измама. Моля, продължете с повишено внимание.",
1426 "wc_scam_warning_title": "ПРЕДУПРЕЖДЕНИЕ!",
1427 "wc_scan_qr": "Сканирайте QR",
res/values/strings_cs.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Podepisujte zprávy a zadaná data",
1422 "wc_permission_switch_chains": "Přepněte a přidejte řetězy EVM",
1423 "wc_permission_view_balance": "Prohlédněte si zůstatek a aktivitu v peněžence",
1424 + "wc_request_for_different_wallet": "Tento požadavek byl podán pro jinou peněženku. Otevřete peněženku připojenou k této aplikaci a zkuste to znovu.",
1425 "wc_scam_warning_message": "Zdá se, že tento požadavek pochází od známého podvodu. Postupujte prosím opatrně.",
1426 "wc_scam_warning_title": "VAROVÁNÍ!",
1427 "wc_scan_qr": "Naskenujte QR",
res/values/strings_de.arb
+1
@@ -1460,6 +1460,7 @@
1460 "wc_permission_sign_messages": "Nachrichten und strukturierte Daten signieren",
1461 "wc_permission_switch_chains": "EVM-Ketten wechseln und hinzufügen",
1462 "wc_permission_view_balance": "Kontostand und Aktivität Ihrer Wallet anzeigen",
1463 + "wc_request_for_different_wallet": "Diese Anfrage wurde für eine andere Wallet gestellt. Öffnen Sie die mit dieser App verbundene Wallet und versuchen Sie es erneut.",
1464 "wc_scam_warning_message": "Diese Anfrage scheint von einem bekannten Betrug zu stammen. Bitte gehen Sie vorsichtig vor.",
1465 "wc_scam_warning_title": "WARNUNG!",
1466 "wc_scan_qr": "QR scannen",
res/values/strings_en.arb
+1
@@ -1462,6 +1462,7 @@
1462 "wc_permission_sign_messages": "Sign messages and typed data",
1463 "wc_permission_switch_chains": "Switch and add EVM chains",
1464 "wc_permission_view_balance": "View your wallet balance and activity",
1465 + "wc_request_for_different_wallet": "This request was made for a different wallet. Open the wallet connected to this app and try again.",
1466 "wc_scam_warning_message": "This request appears to be from a known scam. Please proceed with caution.",
1467 "wc_scam_warning_title": "WARNING!",
1468 "wc_scan_qr": "Scan QR",
res/values/strings_es.arb
+1
@@ -1423,6 +1423,7 @@
1423 "wc_permission_sign_messages": "Firmar mensajes y datos escritos",
1424 "wc_permission_switch_chains": "Cambie y agregue cadenas EVM",
1425 "wc_permission_view_balance": "Ver el saldo y la actividad de su billetera",
1426 + "wc_request_for_different_wallet": "Esta solicitud se realizó para una billetera diferente. Abra la billetera conectada a esta aplicación e inténtelo nuevamente.",
1427 "wc_scam_warning_message": "Esta solicitud parece provenir de una estafa conocida. Proceda con precaución.",
1428 "wc_scam_warning_title": "¡ADVERTENCIA!",
1429 "wc_scan_qr": "Escanear QR",
res/values/strings_fa.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "پیام ها و داده های تایپ شده را امضا کنید",
1422 "wc_permission_switch_chains": "زنجیره های EVM را تغییر دهید و اضافه کنید",
1423 "wc_permission_view_balance": "موجودی و فعالیت کیف پول خود را مشاهده کنید",
1424 + "wc_request_for_different_wallet": "این درخواست برای یک کیف پول متفاوت انجام شده است. کیف پول متصل به این برنامه را باز کنید و دوباره امتحان کنید.",
1425 "wc_scam_warning_message": "به نظر می رسد این درخواست از یک کلاهبرداری شناخته شده باشد. لطفا با احتیاط ادامه دهید",
1426 "wc_scam_warning_title": "هشدار!",
1427 "wc_scan_qr": "اسکن QR",
res/values/strings_fr.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Signer les messages et les données saisies",
1422 "wc_permission_switch_chains": "Changer et ajouter des chaînes EVM",
1423 "wc_permission_view_balance": "Consultez le solde et l'activité de votre portefeuille",
1424 + "wc_request_for_different_wallet": "Cette demande a été faite pour un autre portefeuille. Ouvrez le portefeuille connecté à cette application et réessayez.",
1425 "wc_scam_warning_message": "Cette demande semble provenir d'une arnaque connue. Veuillez procéder avec prudence.",
1426 "wc_scam_warning_title": "AVERTISSEMENT!",
1427 "wc_scan_qr": "Scanner le QR",
res/values/strings_gn.arb
+1
@@ -1428,6 +1428,7 @@
1428 "wc_permission_sign_messages": "Marandu ofirma ha dato ojehaipyréva",
1429 "wc_permission_switch_chains": "Embohasa ha emoĩve umi cadena EVM rehegua",
1430 "wc_permission_view_balance": "Ehecha nde billetera saldo ha actividad",
1431 + "wc_request_for_different_wallet": "Ko mba’ejerure ojejapo peteĩ billetera iñambuéva rehe. Eipe’a pe billetera oñembojoajúva ko app-pe ha eñeha’ã jey.",
1432 "wc_scam_warning_message": "Ko pedido ojekuaa oúha peteî estafa ojekuaávagui. Por favor, peprocede ñeñangareko reheve.",
1433 "wc_scam_warning_title": "ÑEMONGYHYJE!",
1434 "wc_scan_qr": "Escanear QR",
res/values/strings_ha.arb
+1
@@ -1423,6 +1423,7 @@
1423 "wc_permission_sign_messages": "Sa hannu kan saƙonni da rubutattun bayanai",
1424 "wc_permission_switch_chains": "Canja kuma ƙara sarƙoƙin EVM",
1425 "wc_permission_view_balance": "Duba ma'auni na walat ɗin ku da aiki",
1426 + "wc_request_for_different_wallet": "An yi wannan buƙatar don wani walat ɗin daban. Bude walat ɗin da aka haɗa zuwa wannan app ɗin kuma a sake gwadawa.",
1427 "wc_scam_warning_message": "Wannan buƙatar ta bayyana daga wata zamba da aka sani. Da fatan za a ci gaba da taka tsantsan.",
1428 "wc_scam_warning_title": "GARGADI!",
1429 "wc_scan_qr": "Duba QR",
res/values/strings_hi.arb
+1
@@ -1423,6 +1423,7 @@
1423 "wc_permission_sign_messages": "संदेशों पर हस्ताक्षर करें और डेटा टाइप करें",
1424 "wc_permission_switch_chains": "स्विच करें और ईवीएम चेन जोड़ें",
1425 "wc_permission_view_balance": "अपना वॉलेट बैलेंस और गतिविधि देखें",
1426 + "wc_request_for_different_wallet": "यह अनुरोध एक अलग वॉलेट के लिए किया गया था. इस ऐप से जुड़ा वॉलेट खोलें और पुनः प्रयास करें।",
1427 "wc_scam_warning_message": "ऐसा प्रतीत होता है कि यह अनुरोध किसी ज्ञात घोटाले से आया है। कृपया सावधानी से आगे बढ़ें.",
1428 "wc_scam_warning_title": "चेतावनी!",
1429 "wc_scan_qr": "QR स्कैन करें",
res/values/strings_hr.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Potpisivati ​​poruke i upisane podatke",
1422 "wc_permission_switch_chains": "Prebacite i dodajte EVM lance",
1423 "wc_permission_view_balance": "Pogledajte svoj novčanik i aktivnost",
1424 + "wc_request_for_different_wallet": "Ovaj je zahtjev upućen za drugi novčanik. Otvorite novčanik povezan s ovom aplikacijom i pokušajte ponovno.",
1425 "wc_scam_warning_message": "Čini se da ovaj zahtjev potječe iz poznate prijevare. Molimo nastavite s oprezom.",
1426 "wc_scam_warning_title": "UPOZORENJE!",
1427 "wc_scan_qr": "Skeniraj QR",
res/values/strings_hy.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Ստորագրեք հաղորդագրությունները և մուտքագրված տվյալները",
1422 "wc_permission_switch_chains": "Միացրեք և ավելացրեք EVM շղթաներ",
1423 "wc_permission_view_balance": "Դիտեք ձեր դրամապանակի մնացորդը և գործունեությունը",
1424 + "wc_request_for_different_wallet": "Այս հարցումն արվել է այլ դրամապանակի համար: Բացեք այս հավելվածին միացված դրամապանակը և նորից փորձեք:",
1425 "wc_scam_warning_message": "Այս հարցումը, կարծես, հայտնի խարդախությունից է: Խնդրում ենք շարունակել զգուշությամբ:",
1426 "wc_scam_warning_title": "ԶԳՈՒՇԱՑՈՒՄ.",
1427 "wc_scan_qr": "Սկանավորել QR",
res/values/strings_id.arb
+1
@@ -1424,6 +1424,7 @@
1424 "wc_permission_sign_messages": "Menandatangani pesan dan mengetik data",
1425 "wc_permission_switch_chains": "Beralih dan tambahkan rantai EVM",
1426 "wc_permission_view_balance": "Lihat saldo dan aktivitas dompet Anda",
1427 + "wc_request_for_different_wallet": "Permintaan ini dibuat untuk dompet yang berbeda. Buka dompet yang terhubung ke aplikasi ini dan coba lagi.",
1428 "wc_scam_warning_message": "Permintaan ini tampaknya berasal dari penipuan yang diketahui. Silakan lanjutkan dengan hati-hati.",
1429 "wc_scam_warning_title": "PERINGATAN!",
1430 "wc_scan_qr": "Pindai QR",
res/values/strings_it.arb
+1
@@ -1422,6 +1422,7 @@
1422 "wc_permission_sign_messages": "Firmare messaggi e dati digitati",
1423 "wc_permission_switch_chains": "Cambia e aggiungi catene EVM",
1424 "wc_permission_view_balance": "Visualizza il saldo e l'attività del tuo portafoglio",
1425 + "wc_request_for_different_wallet": "Questa richiesta è stata effettuata per un portafoglio diverso. Apri il portafoglio connesso a questa app e riprova.",
1426 "wc_scam_warning_message": "Questa richiesta sembra provenire da una truffa nota. Si prega di procedere con cautela.",
1427 "wc_scam_warning_title": "AVVERTIMENTO!",
1428 "wc_scan_qr": "Scansione QR",
res/values/strings_ja.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "メッセージと入力されたデータに署名する",
1422 "wc_permission_switch_chains": "EVMチェーンの切り替えと追加",
1423 "wc_permission_view_balance": "ウォレットの残高とアクティビティを表示する",
1424 + "wc_request_for_different_wallet": "このリクエストは別のウォレットに対して行われました。このアプリに接続されているウォレットを開いて、もう一度お試しください。",
1425 "wc_scam_warning_message": "このリクエストは既知の詐欺によるものと思われます。慎重に進めてください。",
1426 "wc_scam_warning_title": "警告!",
1427 "wc_scan_qr": "QRをスキャン",
res/values/strings_ko.arb
+1
@@ -1420,6 +1420,7 @@
1420 "wc_permission_sign_messages": "메시지 및 입력된 데이터에 서명",
1421 "wc_permission_switch_chains": "EVM 체인 전환 및 추가",
1422 "wc_permission_view_balance": "지갑 잔액 및 활동 보기",
1423 + "wc_request_for_different_wallet": "이 요청은 다른 지갑에 대해 이루어졌습니다. 이 앱에 연결된 지갑을 열고 다시 시도해 보세요.",
1424 "wc_scam_warning_message": "이 요청은 알려진 사기에서 나온 것 같습니다. 주의해서 진행하시기 바랍니다.",
1425 "wc_scam_warning_title": "경고!",
1426 "wc_scan_qr": "QR 스캔",
res/values/strings_my.arb
+1
@@ -1420,6 +1420,7 @@
1420 "wc_permission_sign_messages": "မက်ဆေ့ချ်များကို လက်မှတ်ထိုးပြီး ဒေတာကို ရိုက်ထည့်ပါ။",
1421 "wc_permission_switch_chains": "EVM chain များကို ပြောင်းပြီး ထည့်ပါ",
1422 "wc_permission_view_balance": "သင့်ပိုက်ဆံအိတ်လက်ကျန်ငွေနှင့် လုပ်ဆောင်ချက်ကို ကြည့်ရှုပါ။",
1423 + "wc_request_for_different_wallet": "ဤတောင်းဆိုချက်ကို မတူညီသော ပိုက်ဆံအိတ်အတွက် ပြုလုပ်ထားပါသည်။ ဤအက်ပ်နှင့်ချိတ်ဆက်ထားသော ပိုက်ဆံအိတ်ကိုဖွင့်ပြီး ထပ်စမ်းကြည့်ပါ။",
1424 "wc_scam_warning_message": "ဤတောင်းဆိုချက်သည် လူသိများသော လိမ်လည်မှုတစ်ခုမှ ဖြစ်ပုံရသည်။ ကျေးဇူးပြု၍ သတိဖြင့် ဆက်လုပ်ပါ။",
1425 "wc_scam_warning_title": "သတိပေးချက်။",
1426 "wc_scan_qr": "QR ကိုစကင်န်ဖတ်ပါ။",
res/values/strings_nl.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Onderteken berichten en getypte gegevens",
1422 "wc_permission_switch_chains": "Schakel over en voeg EVM-ketens toe",
1423 "wc_permission_view_balance": "Bekijk je walletsaldo en activiteit",
1424 + "wc_request_for_different_wallet": "Dit verzoek is gedaan voor een andere portemonnee. Open de portemonnee die met deze app is verbonden en probeer het opnieuw.",
1425 "wc_scam_warning_message": "Dit verzoek lijkt afkomstig te zijn van een bekende oplichting. Ga alstublieft voorzichtig te werk.",
1426 "wc_scam_warning_title": "WAARSCHUWING!",
1427 "wc_scan_qr": "QR scannen",
res/values/strings_pl.arb
+1
@@ -1420,6 +1420,7 @@
1420 "wc_permission_sign_messages": "Podpisuj wiadomości i wpisywane dane",
1421 "wc_permission_switch_chains": "Przełącz i dodaj łańcuchy EVM",
1422 "wc_permission_view_balance": "Sprawdź saldo i aktywność swojego portfela",
1423 + "wc_request_for_different_wallet": "To żądanie dotyczyło innego portfela. Otwórz portfel połączony z tą aplikacją i spróbuj ponownie.",
1424 "wc_scam_warning_message": "Wygląda na to, że to żądanie pochodzi ze znanego oszustwa. Proszę postępować ostrożnie.",
1425 "wc_scam_warning_title": "OSTRZEŻENIE!",
1426 "wc_scan_qr": "Zeskanuj kod QR",
res/values/strings_pt.arb
+1
@@ -1423,6 +1423,7 @@
1423 "wc_permission_sign_messages": "Assinar mensagens e dados digitados",
1424 "wc_permission_switch_chains": "Alternar e adicionar cadeias EVM",
1425 "wc_permission_view_balance": "Veja o saldo e a atividade da sua carteira",
1426 + "wc_request_for_different_wallet": "Esta solicitação foi feita para uma carteira diferente. Abra a carteira conectada a este aplicativo e tente novamente.",
1427 "wc_scam_warning_message": "Esta solicitação parece ser de um golpe conhecido. Por favor, proceda com cautela.",
1428 "wc_scam_warning_title": "AVISO!",
1429 "wc_scan_qr": "Digitalize QR",
res/values/strings_pt_BR.arb
+1
@@ -1361,6 +1361,7 @@
1361 "wc_permission_sign_messages": "Assinar mensagens e dados digitados",
1362 "wc_permission_switch_chains": "Alternar e adicionar cadeias EVM",
1363 "wc_permission_view_balance": "Veja o saldo e a atividade da sua carteira",
1364 + "wc_request_for_different_wallet": "Esta solicitação foi feita para uma carteira diferente. Abra a carteira conectada a este aplicativo e tente novamente.",
1365 "wc_scam_warning_message": "Esta solicitação parece ser de um golpe conhecido. Por favor, proceda com cautela.",
1366 "wc_scam_warning_title": "AVISO!",
1367 "wc_scan_qr": "Digitalize QR",
res/values/strings_ru.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Подписывать сообщения и вводимые данные",
1422 "wc_permission_switch_chains": "Переключение и добавление цепочек EVM",
1423 "wc_permission_view_balance": "Просматривайте баланс и активность своего кошелька",
1424 + "wc_request_for_different_wallet": "Этот запрос был сделан для другого кошелька. Откройте кошелек, подключенный к этому приложению, и повторите попытку.",
1425 "wc_scam_warning_message": "Судя по всему, этот запрос поступил от известного мошенника. Пожалуйста, действуйте осторожно.",
1426 "wc_scam_warning_title": "ПРЕДУПРЕЖДЕНИЕ!",
1427 "wc_scan_qr": "Сканировать QR-код",
res/values/strings_th.arb
+1
@@ -1420,6 +1420,7 @@
1420 "wc_permission_sign_messages": "เซ็นข้อความและพิมพ์ข้อมูล",
1421 "wc_permission_switch_chains": "สลับและเพิ่มเชน EVM",
1422 "wc_permission_view_balance": "ดูยอดคงเหลือในกระเป๋าสตางค์และกิจกรรมของคุณ",
1423 + "wc_request_for_different_wallet": "คำขอนี้สร้างขึ้นสำหรับกระเป๋าเงินอื่น เปิดกระเป๋าเงินที่เชื่อมต่อกับแอพนี้แล้วลองอีกครั้ง",
1424 "wc_scam_warning_message": "ดูเหมือนว่าคำขอนี้มาจากกลโกงที่ทราบ โปรดดำเนินการด้วยความระมัดระวัง",
1425 "wc_scam_warning_title": "คำเตือน!",
1426 "wc_scan_qr": "สแกนคิวอาร์",
res/values/strings_tl.arb
+1
@@ -1420,6 +1420,7 @@
1420 "wc_permission_sign_messages": "Mag-sign ng mga mensahe at nai-type na data",
1421 "wc_permission_switch_chains": "Lumipat at magdagdag ng mga EVM chain",
1422 "wc_permission_view_balance": "Tingnan ang balanse at aktibidad ng iyong wallet",
1423 + "wc_request_for_different_wallet": "Ang kahilingang ito ay ginawa para sa ibang wallet. Buksan ang wallet na nakakonekta sa app na ito at subukang muli.",
1424 "wc_scam_warning_message": "Mukhang mula sa isang kilalang scam ang kahilingang ito. Mangyaring magpatuloy nang may pag-iingat.",
1425 "wc_scam_warning_title": "BABALA!",
1426 "wc_scan_qr": "I-scan ang QR",
res/values/strings_tr.arb
+1
@@ -1420,6 +1420,7 @@
1420 "wc_permission_sign_messages": "Mesajları ve yazılan verileri imzalayın",
1421 "wc_permission_switch_chains": "EVM zincirlerini değiştirin ve ekleyin",
1422 "wc_permission_view_balance": "Cüzdan bakiyenizi ve etkinliğinizi görüntüleyin",
1423 + "wc_request_for_different_wallet": "Bu istek farklı bir cüzdan için yapıldı. Bu uygulamaya bağlı cüzdanı açın ve tekrar deneyin.",
1424 "wc_scam_warning_message": "Bu isteğin bilinen bir dolandırıcılıktan geldiği anlaşılıyor. Lütfen dikkatli bir şekilde ilerleyin.",
1425 "wc_scam_warning_title": "UYARI!",
1426 "wc_scan_qr": "QR'yi tara",
res/values/strings_uk.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Підписуйте повідомлення та введені дані",
1422 "wc_permission_switch_chains": "Перемикайте та додавайте ланцюжки EVM",
1423 "wc_permission_view_balance": "Перегляньте свій баланс гаманця та активність",
1424 + "wc_request_for_different_wallet": "Цей запит було зроблено для іншого гаманця. Відкрийте гаманець, підключений до цієї програми, і повторіть спробу.",
1425 "wc_scam_warning_message": "Схоже, цей запит надійшов від відомого шахрая. Будь ласка, будьте обережні.",
1426 "wc_scam_warning_title": "УВАГА!",
1427 "wc_scan_qr": "Сканувати QR",
res/values/strings_ur.arb
+1
@@ -1422,6 +1422,7 @@
1422 "wc_permission_sign_messages": "پیغامات پر دستخط کریں اور ڈیٹا ٹائپ کریں۔",
1423 "wc_permission_switch_chains": "ای وی ایم چینز کو تبدیل کریں اور شامل کریں۔",
1424 "wc_permission_view_balance": "اپنے والیٹ کا بیلنس اور سرگرمی دیکھیں",
1425 + "wc_request_for_different_wallet": "یہ درخواست ایک مختلف بٹوے کے لیے کی گئی تھی۔ اس ایپ سے منسلک والیٹ کھولیں اور دوبارہ کوشش کریں۔",
1426 "wc_scam_warning_message": "یہ درخواست کسی معروف اسکام کی طرف سے معلوم ہوتی ہے۔ براہ کرم احتیاط کے ساتھ آگے بڑھیں۔",
1427 "wc_scam_warning_title": "وارننگ!",
1428 "wc_scan_qr": "QR اسکین کریں۔",
res/values/strings_vi.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Ký tin nhắn và dữ liệu có cấu trúc",
1422 "wc_permission_switch_chains": "Chuyển đổi và thêm chuỗi EVM",
1423 "wc_permission_view_balance": "Xem số dư và hoạt động ví của bạn",
1424 + "wc_request_for_different_wallet": "Yêu cầu này được thực hiện cho một ví khác. Hãy mở ví được kết nối với ứng dụng này và thử lại.",
1425 "wc_scam_warning_message": "Yêu cầu này có vẻ là từ một trò lừa đảo đã biết. Hãy tiến hành thận trọng.",
1426 "wc_scam_warning_title": "CẢNH BÁO!",
1427 "wc_scan_qr": "Quét QR",
res/values/strings_yo.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "Wole awọn ifiranṣẹ ati titẹ data",
1422 "wc_permission_switch_chains": "Yipada ki o si fi EVM dè",
1423 "wc_permission_view_balance": "Wo iwọntunwọnsi apamọwọ rẹ ati iṣẹ ṣiṣe",
1424 + "wc_request_for_different_wallet": "A ṣe ibeere yii fun apamọwọ ti o yatọ. Ṣii apamọwọ ti a ti sopọ si app yii ki o tun gbiyanju lẹẹkansi.",
1425 "wc_scam_warning_message": "Ibeere yii han lati wa lati itanjẹ ti a mọ. Jọwọ tẹsiwaju pẹlu iṣọra.",
1426 "wc_scam_warning_title": "IKILO!",
1427 "wc_scan_qr": "Ṣayẹwo QR",
res/values/strings_zh.arb
+1
@@ -1421,6 +1421,7 @@
1421 "wc_permission_sign_messages": "签署消息和键入的数据",
1422 "wc_permission_switch_chains": "切换并添加EVM链",
1423 "wc_permission_view_balance": "查看您的钱包余额和活动",
1424 + "wc_request_for_different_wallet": "此请求是针对不同的钱包提出的。打开连接到该应用程序的钱包并重试。",
1425 "wc_scam_warning_message": "此请求似乎来自一个已知的骗局。请谨慎行事。",
1426 "wc_scam_warning_title": "警告!",
1427 "wc_scan_qr": "扫描二维码",