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": "扫描二维码",