CW-1615: Harden walletconnect auth (#3547)
What changed, and why it matters
This update fixes a security weakness in Cake Wallet's WalletConnect feature. Previously, if a user switched to a different wallet inside the app while still connected to a decentralized app (dApp), the dApp could keep sending signing or transaction requests that might be handled by the wrong wallet. The patch now checks that each incoming request truly belongs to the currently active wallet, rejects mismatched requests with a clear message, and refreshes or clears WalletConnect sessions when wallets are switched. It also updates Solana connection identifiers and improves loading/error feedback.
Review the authorization logic for completeness, especially edge cases where multiple accounts or chains are authorized in one session, and ensure the `_pendingRequest` matcher correctly handles concurrent requests with the same topic and method. Consider adding automated tests for wallet-switch scenarios and unauthorized request rejection.
Security signals we found
Authorization check added before signing/transaction approval
Session ownership verified against current wallet public key
Request address matched to wallet address before approval
Unauthorized WalletConnect requests rejected with 4100 error
WalletConnect state reset and sessions reloaded on wallet switch
Relay client disconnected on WalletConnect dispose
Topic/method-scoped pending request lookup replaces global last-request lookup
Solana chain ID updated and legacy ID retained for compatibility
Evidence from the diff
The commit hardens WalletConnect request handling in EVM and Solana chain services. It replaces the unsafe pattern of taking the last pending request (walletKit.pendingRequests.getAll().last) with a topic- and method-scoped lookup (_pendingRequest). Before any signing or transaction is shown to the user, it verifies the session and request address belong to the current wallet via MethodsUtils.isSessionOwnedByWallet and isSameAccount. Unauthorized requests are rejected with a 4100 JSON-RPC error and a bottom-sheet message. WalletKitService now reloads only sessions owned by the current wallet, resets state on wallet switch, and disconnects the relay on dispose. Solana chain IDs are updated to the newer mainnet identifier while keeping the legacy one for compatibility.
Changed components
WalletConnect EVM chain serviceWalletConnect Solana chain serviceWalletConnect key serviceWalletKit serviceWalletConnect method utilitiesWalletConnect connections listing UIApp store wallet switching logicLocalized WalletConnect stringsInspect captured patch +495 / −114
diff --git a/lib/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart b/lib/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart
index c8618d85..e30fc2e5 100644
--- a/lib/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart
+++ b/lib/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart
@@ -1,3 +1,4 @@
+import "dart:async";
import 'dart:convert';
import 'package:cake_wallet/di.dart';
@@ -5,6 +6,7 @@ import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cw_core/crypto_currency.dart';
+import "package:cw_core/utils/print_verbose.dart";
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:eth_sig_util/util/utils.dart';
@@ -18,6 +20,7 @@ import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wall
import 'package:cake_wallet/src/screens/wallet_connect/models/wc_connection_model.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/eth_utils.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
+import "package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart";
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/evm/evm.dart';
@@ -82,7 +85,9 @@ class EvmChainServiceImpl {
if (appStore.wallet != null && isEVMCompatibleChain(appStore.wallet!.type)) {
final walletClient = evm?.getWeb3Client(appStore.wallet!);
- if (walletClient != null) return walletClient;
+ if (walletClient != null) {
+ return walletClient;
+ }
}
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
@@ -93,8 +98,18 @@ class EvmChainServiceImpl {
Future<void> personalSign(String topic, dynamic parameters) async {
debugPrint('personalSign request: $parameters');
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, EVMSupportedMethods.personalSign.name);
+ if (pRequest == null) {
+ return;
+ }
+
final address = EthUtils.getAddressFromSessionRequest(pRequest);
+
+ if (!_isRequestAuthorized(topic, requestAddress: address)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
final data = EthUtils.getDataFromSessionRequest(pRequest);
final message = EthUtils.getUtf8Message(data.toString());
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -104,6 +119,7 @@ class EvmChainServiceImpl {
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
+ topic: topic,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
@@ -141,8 +157,18 @@ class EvmChainServiceImpl {
Future<void> ethSign(String topic, dynamic parameters) async {
debugPrint('ethSign request: $parameters');
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSign.name);
+ if (pRequest == null) {
+ return;
+ }
+
final address = EthUtils.getAddressFromSessionRequest(pRequest);
+
+ if (!_isRequestAuthorized(topic, requestAddress: address)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
final data = EthUtils.getDataFromSessionRequest(pRequest);
final message = EthUtils.getUtf8Message(data.toString());
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -152,6 +178,7 @@ class EvmChainServiceImpl {
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
+ topic: topic,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
@@ -189,8 +216,18 @@ class EvmChainServiceImpl {
Future<void> ethSignTypedData(String topic, dynamic parameters) async {
debugPrint('ethSignTypedData request: $parameters');
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTypedData.name);
+ if (pRequest == null) {
+ return;
+ }
+
final address = EthUtils.getAddressFromSessionRequest(pRequest);
+
+ if (!_isRequestAuthorized(topic, requestAddress: address)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -199,6 +236,7 @@ class EvmChainServiceImpl {
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
+ topic: topic,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
@@ -236,8 +274,18 @@ class EvmChainServiceImpl {
final permitRequestMessage = await extractPermitData(parameters);
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTypedDataV4.name);
+ if (pRequest == null) {
+ return;
+ }
+
final address = EthUtils.getAddressFromSessionRequest(pRequest);
+
+ if (!_isRequestAuthorized(topic, requestAddress: address)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
final data = EthUtils.getDataFromSessionRequest(pRequest) as String;
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -246,6 +294,7 @@ class EvmChainServiceImpl {
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
+ topic: topic,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
@@ -280,10 +329,22 @@ class EvmChainServiceImpl {
Future<void> ethSignTransaction(String topic, dynamic parameters) async {
debugPrint('ethSignTransaction request: $parameters');
- final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSignTransaction.name);
+ if (pRequest == null) {
+ return;
+ }
+
final data = EthUtils.getTransactionFromSessionRequest(pRequest);
- if (data == null) return;
+ if (data == null) {
+ _respondMalformedRequest(topic, pRequest.id);
+ return;
+ }
+
+ if (!_isRequestAuthorized(topic, requestAddress: data['from']?.toString())) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
final address = EthUtils.getAddressFromSessionRequest(pRequest);
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -293,6 +354,7 @@ class EvmChainServiceImpl {
method: pRequest.method,
chainId: pRequest.chainId,
address: address,
+ topic: topic,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
@@ -333,10 +395,21 @@ class EvmChainServiceImpl {
Future<void> ethSendTransaction(String topic, dynamic parameters) async {
debugPrint('ethSendTransaction request: $parameters');
- final SessionRequest pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, EVMSupportedMethods.ethSendTransaction.name);
+ if (pRequest == null) {
+ return;
+ }
final data = EthUtils.getTransactionFromSessionRequest(pRequest);
- if (data == null) return;
+ if (data == null) {
+ _respondMalformedRequest(topic, pRequest.id);
+ return;
+ }
+
+ if (!_isRequestAuthorized(topic, requestAddress: data['from']?.toString())) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
@@ -344,6 +417,7 @@ class EvmChainServiceImpl {
data,
method: pRequest.method,
chainId: pRequest.chainId,
+ topic: topic,
transportType: pRequest.transportType.name,
verifyContext: pRequest.verifyContext,
);
@@ -379,6 +453,77 @@ class EvmChainServiceImpl {
_handleResponseForTopic(topic, response);
}
+ void _respondMalformedRequest(String topic, int requestId) {
+ final error = Errors.getSdkError(Errors.MALFORMED_REQUEST_PARAMS);
+ _handleResponseForTopic(
+ topic,
+ JsonRpcResponse(
+ id: requestId,
+ jsonrpc: "2.0",
+ error: JsonRpcError(code: error.code, message: error.message),
+ ),
+ );
+ }
+
+ SessionRequest? _pendingRequest(String topic, String method) {
+ final matches = walletKit.pendingRequests
+ .getAll()
+ .where((request) => request.topic == topic && request.method == method);
+
+ return matches.isEmpty ? null : matches.last;
+ }
+
+ bool _isRequestAuthorized(String topic, {String? requestAddress}) {
+ final wallet = appStore.wallet;
+ if (wallet == null) {
+ return false;
+ }
+
+ final keys = wcKeyService.getKeysForChain(wallet);
+ if (keys.isEmpty) {
+ return false;
+ }
+
+ final walletAddress = keys.first.publicKey;
+
+ if (!MethodsUtils.isSessionOwnedByWallet(walletKit.sessions.get(topic), walletAddress)) {
+ return false;
+ }
+
+ if (requestAddress != null && !MethodsUtils.isSameAccount(requestAddress, walletAddress)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ Future<void> _rejectUnauthorizedRequest(String topic, int requestId) async {
+ unawaited(
+ bottomSheetService.queueBottomSheet(
+ isModalDismissible: true,
+ widget: BottomSheetMessageDisplayWidget(
+ message: S.current.wc_request_for_different_wallet,
+ ),
+ ),
+ );
+
+ try {
+ await walletKit.respondSessionRequest(
+ topic: topic,
+ response: JsonRpcResponse(
+ id: requestId,
+ jsonrpc: "2.0",
+ error: const JsonRpcError(
+ code: 4100,
+ message: "The requested account has not been authorized by the user.",
+ ),
+ ),
+ );
+ } catch (e) {
+ printV("rejectUnauthorizedRequest: $e");
+ }
+ }
+
void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
final session = walletKit.sessions.get(topic);
@@ -388,7 +533,9 @@ class EvmChainServiceImpl {
response: response,
);
- if (session == null) return;
+ if (session == null) {
+ return;
+ }
MethodsUtils.handleRedirect(
topic,
@@ -397,7 +544,9 @@ class EvmChainServiceImpl {
response.error == null,
);
} on ReownSignError catch (error) {
- if (session == null) return;
+ if (session == null) {
+ return;
+ }
MethodsUtils.handleRedirect(
topic,
@@ -413,6 +562,7 @@ class EvmChainServiceImpl {
String? method,
String? chainId,
String? address,
+ String? topic,
VerifyContext? verifyContext,
required String transportType,
}) async {
@@ -456,6 +606,7 @@ class EvmChainServiceImpl {
method: method,
chainId: chainId,
address: address ?? transaction.from?.hex ?? '',
+ topic: topic,
transportType: transportType,
verifyContext: verifyContext,
extraModels: feeRows,
@@ -472,13 +623,17 @@ class EvmChainServiceImpl {
String nativeSymbol,
) {
final gasLimit = transaction.maxGas;
- if (gasLimit == null || gasLimit <= 0) return const [];
+ if (gasLimit == null || gasLimit <= 0) {
+ return const [];
+ }
final gasLimitBig = BigInt.from(gasLimit);
final isEip1559 = transaction.isEIP1559;
final perGasWei =
isEip1559 ? transaction.maxFeePerGas?.getInWei : transaction.gasPrice?.getInWei;
- if (perGasWei == null || perGasWei <= BigInt.zero) return const [];
+ if (perGasWei == null || perGasWei <= BigInt.zero) {
+ return const [];
+ }
final feeWei = gasLimitBig * perGasWei;
final feeNative = feeWei.toDouble() / 1e18;
@@ -500,19 +655,25 @@ class EvmChainServiceImpl {
) {
final cryptoPart = '${_formatNativeAmount(feeNative)} $nativeSymbol';
- if (nativeCurrency == null) return cryptoPart;
+ if (nativeCurrency == null) {
+ return cryptoPart;
+ }
try {
final fiatStore = getIt.get<FiatConversionStore>();
final price = fiatStore.prices[nativeCurrency];
- if (price == null || price <= 0) return cryptoPart;
+ if (price == null || price <= 0) {
+ return cryptoPart;
+ }
final fiatSymbol = appStore.settingsStore.fiatCurrency.title;
final fiatValue = calculateFiatAmount(
price: price,
cryptoAmount: feeNative.toString(),
);
- if (fiatValue.isEmpty || fiatValue == '0.00') return cryptoPart;
+ if (fiatValue.isEmpty || fiatValue == '0.00') {
+ return cryptoPart;
+ }
return '$cryptoPart (~ $fiatValue $fiatSymbol)';
} catch (_) {
@@ -521,14 +682,20 @@ class EvmChainServiceImpl {
}
String _formatNativeAmount(double value) {
- if (value == 0) return '0';
- if (value >= 0.0001) return value.toStringAsFixed(6);
+ if (value == 0) {
+ return '0';
+ }
+ if (value >= 0.0001) {
+ return value.toStringAsFixed(6);
+ }
return value.toStringAsExponential(4);
}
Future<Transaction> _ensureWCTransactionHasGasLimit(Transaction transaction) async {
final hasGasLimit = transaction.maxGas != null && transaction.maxGas! > 0;
- if (hasGasLimit) return transaction;
+ if (hasGasLimit) {
+ return transaction;
+ }
final hint = transaction.gasPrice ?? transaction.maxFeePerGas ?? await ethClient.getGasPrice();
@@ -689,7 +856,9 @@ $messageDetails''';
final fieldType = field['type'] as String;
final value = message[field['name'] as String];
- if (value == null) continue;
+ if (value == null) {
+ continue;
+ }
if (types.containsKey(fieldType)) {
final nestedFields = types[fieldType] as List<dynamic>;
@@ -714,7 +883,9 @@ $messageDetails''';
}
String _toCamelCase(String input) {
- if (input.isEmpty) return input;
+ if (input.isEmpty) {
+ return input;
+ }
return input[0].toUpperCase() + input.substring(1).toLowerCase();
}
diff --git a/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart b/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart
index c5a3c9d2..a4012cd5 100644
--- a/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart
+++ b/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart
@@ -1,4 +1,4 @@
-enum SolanaChainId { mainnet, devnet, testnet }
+enum SolanaChainId { mainnet, mainnetLegacy, devnet, testnet }
extension SolanaChainIdX on SolanaChainId {
String chain() {
@@ -6,8 +6,10 @@ extension SolanaChainIdX on SolanaChainId {
switch (this) {
case SolanaChainId.mainnet:
+ name = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
+ break;
+ case SolanaChainId.mainnetLegacy:
name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
- // '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';
break;
case SolanaChainId.devnet:
name = 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1';
diff --git a/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_service.dart b/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_service.dart
index b5d12f35..dfba2bf5 100644
--- a/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_service.dart
+++ b/lib/src/screens/wallet_connect/services/chain_service/solana/solana_chain_service.dart
@@ -1,16 +1,20 @@
+import "dart:async";
import 'dart:convert';
import 'package:blockchain_utils/base58/base58.dart';
import 'package:blockchain_utils/blockchain_utils.dart' as blockchain_utils;
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_supported_methods.dart';
+import "package:cw_core/utils/print_verbose.dart";
import 'package:flutter/material.dart';
import 'package:on_chain/solana/solana.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
+import "package:cake_wallet/generated/i18n.dart";
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/chain_service/solana/solana_chain_id.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
+import "package:cake_wallet/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_message_display_widget.dart";
import 'package:cake_wallet/store/app_store.dart';
class SolanaChainService {
@@ -47,7 +51,16 @@ class SolanaChainService {
Future<void> solanaSignMessage(String topic, dynamic parameters) async {
debugPrint('solanaSignMessage request: $parameters');
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignMessage.name);
+ if (pRequest == null) {
+ return;
+ }
+
+ if (!_isRequestAuthorized(topic)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
try {
@@ -65,6 +78,7 @@ class SolanaChainService {
method: pRequest.method,
chainId: pRequest.chainId,
address: privateKey.publicKey().toAddress().address,
+ topic: topic,
transportType: pRequest.transportType.name,
);
@@ -95,7 +109,16 @@ class SolanaChainService {
Future<void> solanaSignTransaction(String topic, dynamic parameters) async {
debugPrint('solanaSignTransaction: ${jsonEncode(parameters)}');
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignTransaction.name);
+ if (pRequest == null) {
+ return;
+ }
+
+ if (!_isRequestAuthorized(topic)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
try {
@@ -130,6 +153,7 @@ class SolanaChainService {
method: pRequest.method,
chainId: pRequest.chainId,
address: privateKey.publicKey().toAddress().address,
+ topic: topic,
transportType: pRequest.transportType.name,
);
@@ -160,7 +184,16 @@ class SolanaChainService {
Future<void> solanaSignAllTransaction(String topic, dynamic parameters) async {
debugPrint('solanaSignAllTransaction: ${jsonEncode(parameters)}');
- final pRequest = walletKit.pendingRequests.getAll().last;
+ final pRequest = _pendingRequest(topic, SolanaSupportedMethods.solSignAllTransaction.name);
+ if (pRequest == null) {
+ return;
+ }
+
+ if (!_isRequestAuthorized(topic)) {
+ await _rejectUnauthorizedRequest(topic, pRequest.id);
+ return;
+ }
+
var response = JsonRpcResponse(id: pRequest.id, jsonrpc: '2.0');
try {
@@ -174,6 +207,7 @@ class SolanaChainService {
method: pRequest.method,
chainId: pRequest.chainId,
address: privateKey.publicKey().toAddress().address,
+ topic: topic,
transportType: pRequest.transportType.name,
);
@@ -224,6 +258,55 @@ class SolanaChainService {
return SolanaPrivateKey.fromSeedHex(keys[0].privateKey);
}
+ SessionRequest? _pendingRequest(String topic, String method) {
+ final matches = walletKit.pendingRequests
+ .getAll()
+ .where((request) => request.topic == topic && request.method == method);
+
+ return matches.isEmpty ? null : matches.last;
+ }
+
+ bool _isRequestAuthorized(String topic) {
+ final wallet = appStore.wallet;
+ if (wallet == null) {
+ return false;
+ }
+
+ final keys = wcKeyService.getKeysForChain(wallet);
+ if (keys.isEmpty) {
+ return false;
+ }
+
+ return MethodsUtils.isSessionOwnedByWallet(walletKit.sessions.get(topic), keys.first.publicKey);
+ }
+
+ Future<void> _rejectUnauthorizedRequest(String topic, int requestId) async {
+ unawaited(
+ bottomSheetService.queueBottomSheet(
+ isModalDismissible: true,
+ widget: BottomSheetMessageDisplayWidget(
+ message: S.current.wc_request_for_different_wallet,
+ ),
+ ),
+ );
+
+ try {
+ await walletKit.respondSessionRequest(
+ topic: topic,
+ response: JsonRpcResponse(
+ id: requestId,
+ jsonrpc: "2.0",
+ error: const JsonRpcError(
+ code: 4100,
+ message: "The requested account has not been authorized by the user.",
+ ),
+ ),
+ );
+ } catch (e) {
+ printV("rejectUnauthorizedRequest: $e");
+ }
+ }
+
void _handleResponseForTopic(String topic, JsonRpcResponse<dynamic> response) async {
final session = walletKit.sessions.get(topic);
diff --git a/lib/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart b/lib/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart
index 38772da1..4d09213d 100644
--- a/lib/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart
+++ b/lib/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart
@@ -43,30 +43,36 @@ class KeyServiceImpl implements WalletConnectKeyService {
@override
List<ChainKeyModel> getKeys(WalletBase wallet) {
- final keys = [
- ChainKeyModel(
- chains: [
- 'eip155:1',
- 'eip155:5',
- 'eip155:56',
- 'eip155:137',
- 'eip155:8453',
- 'eip155:42161',
- 'eip155:80001',
- ],
- privateKey: _getPrivateKeyForWallet(wallet),
- publicKey: _getPublicKeyForWallet(wallet),
- ),
- ChainKeyModel(
- chains: [
- 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ', // main-net
- 'solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K', // test-net
- ],
- privateKey: _getPrivateKeyForWallet(wallet),
- publicKey: _getPublicKeyForWallet(wallet),
- ),
- ];
- return keys;
+ if (isEVMCompatibleChain(wallet.type)) {
+ return [
+ ChainKeyModel(
+ chains: [
+ 'eip155:1',
+ 'eip155:56',
+ 'eip155:137',
+ 'eip155:8453',
+ 'eip155:42161',
+ ],
+ privateKey: _getPrivateKeyForWallet(wallet),
+ publicKey: _getPublicKeyForWallet(wallet),
+ ),
+ ];
+ }
+
+ if (wallet.type == WalletType.solana) {
+ return [
+ ChainKeyModel(
+ chains: [
+ 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // main-net
+ 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ', // legacy main-net id older dapps still use
+ ],
+ privateKey: _getPrivateKeyForWallet(wallet),
+ publicKey: _getPublicKeyForWallet(wallet),
+ ),
+ ];
+ }
+
+ return [];
}
@override
diff --git a/lib/src/screens/wallet_connect/services/walletkit_service.dart b/lib/src/screens/wallet_connect/services/walletkit_service.dart
index aa3c2630..09c1432f 100644
--- a/lib/src/screens/wallet_connect/services/walletkit_service.dart
+++ b/lib/src/screens/wallet_connect/services/walletkit_service.dart
@@ -3,7 +3,6 @@ import 'dart:convert';
import 'dart:typed_data';
import 'package:cw_core/utils/print_verbose.dart';
-import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
@@ -42,7 +41,8 @@ abstract class WalletKitServiceBase with Store {
) : pairings = ObservableList<PairingInfo>(),
sessions = ObservableList<SessionData>(),
auth = ObservableList<PendingSessionAuthRequest>(),
- isInitialized = false;
+ isInitialized = false,
+ isLoadingConnections = true;
final AppStore appStore;
final SharedPreferences sharedPreferences;
@@ -54,6 +54,9 @@ abstract class WalletKitServiceBase with Store {
@observable
bool isInitialized;
+ @observable
+ bool isLoadingConnections;
+
/// The list of requests from the dapp
@observable
ObservableList<PairingInfo> pairings;
@@ -91,33 +94,23 @@ abstract class WalletKitServiceBase with Store {
_walletKit.onSessionProposal.subscribe(_onSessionProposal);
_walletKit.onSessionProposalError.subscribe(_onSessionProposalError);
_walletKit.onSessionConnect.subscribe(_onSessionConnect);
- _walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
+
+ if (isEVMCompatibleChain(appStore.wallet!.type)) {
+ _walletKit.onSessionAuthRequest.subscribe(_onSessionAuthRequest);
+ }
_walletKit.pairings.onSync.subscribe(_onPairingsSync);
_walletKit.core.pairing.onPairingDelete.subscribe(_onPairingDelete);
_walletKit.core.pairing.onPairingExpire.subscribe(_onPairingDelete);
// Setup our accounts
- List<ChainKeyModel> chainKeys = walletKeyService.getKeys(appStore.wallet!);
+ final chainKeys = walletKeyService.getKeys(appStore.wallet!);
for (final chainKey in chainKeys) {
for (final chainId in chainKey.chains) {
- if (isEVMCompatibleChain(appStore.wallet!.type)) {
- // Register account for all EVM chains (chainId is already in eip155:format)
- _walletKit.registerAccount(
- chainId: chainId,
- accountAddress: chainKey.publicKey,
- );
- } else {
- final chainNameSpace = getChainNameSpaceAndIdBasedOnWalletType(
- appStore.wallet!.type,
- );
- if (chainNameSpace == chainId) {
- _walletKit.registerAccount(
- chainId: chainId,
- accountAddress: chainKey.publicKey,
- );
- }
- }
+ _walletKit.registerAccount(
+ chainId: chainId,
+ accountAddress: chainKey.publicKey,
+ );
}
}
}
@@ -144,42 +137,43 @@ abstract class WalletKitServiceBase with Store {
}
}
- await _emitEvent();
-
_refreshPairings();
- sessions.clear();
- auth.clear();
+ _reloadSessionsForCurrentWallet();
- final newSessions = _walletKit.sessions.getAll();
- sessions.addAll(newSessions);
+ auth.clear();
final newAuthRequests = _walletKit.sessionAuthRequests.getAll();
auth.addAll(newAuthRequests);
- if (isEVMCompatibleChain(appStore.wallet!.type)) {
- for (final cId in EVMChainId.values) {
- EvmChainServiceImpl(
- reference: cId,
- appStore: appStore,
- wcKeyService: walletKeyService,
- bottomSheetService: _bottomSheetHandler,
- walletKit: _walletKit,
- );
- }
+ isLoadingConnections = false;
+ for (final cId in EVMChainId.values) {
+ EvmChainServiceImpl(
+ reference: cId,
+ appStore: appStore,
+ wcKeyService: walletKeyService,
+ bottomSheetService: _bottomSheetHandler,
+ walletKit: _walletKit,
+ );
}
- if (appStore.wallet!.type == WalletType.solana) {
- for (final cId in SolanaChainId.values) {
- SolanaChainService(
- reference: cId,
- appStore: appStore,
- wcKeyService: walletKeyService,
- bottomSheetService: _bottomSheetHandler,
- walletKit: _walletKit,
- );
- }
+ for (final cId in SolanaChainId.values) {
+ SolanaChainService(
+ reference: cId,
+ appStore: appStore,
+ wcKeyService: walletKeyService,
+ bottomSheetService: _bottomSheetHandler,
+ walletKit: _walletKit,
+ );
}
+
+ unawaited(() async {
+ try {
+ await _emitEvent();
+ } catch (e) {
+ printV("emitEvent failed: $e");
+ }
+ }());
}
@action
@@ -195,6 +189,10 @@ abstract class WalletKitServiceBase with Store {
for (var session in engineSessions) {
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
for (var chain in chainKeys) {
+ if (!MethodsUtils.isSessionOwnedByWallet(session, chain.publicKey)) {
+ continue;
+ }
+
for (var chainID in chain.chains) {
try {
final events = NamespaceUtils.getNamespacesEventsForChain(
@@ -228,8 +226,21 @@ abstract class WalletKitServiceBase with Store {
}
@action
- FutureOr<void> onDispose() {
- log('walletKit dispose');
+ void resetConnectionsState() {
+ sessions.clear();
+ auth.clear();
+ pairings.clear();
+
+ isInitialized = false;
+ isLoadingConnections = true;
+ }
+
+ @action
+ Future<void> onDispose() async {
+ log("walletKit dispose");
+
+ resetConnectionsState();
+
_walletKit.core.removeLogListener(_logListener);
_walletKit.core.pairing.onPairingInvalid.unsubscribe(_onPairingInvalid);
@@ -246,11 +257,11 @@ abstract class WalletKitServiceBase with Store {
_walletKit.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
_walletKit.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
- sessions.clear();
- auth.clear();
- pairings.clear();
-
- isInitialized = false;
+ try {
+ await _walletKit.core.relayClient.disconnect().timeout(const Duration(seconds: 3));
+ } catch (e) {
+ printV("walletKit relay disconnect: $e");
+ }
}
ReownWalletKit get walletKit => _walletKit;
@@ -534,8 +545,7 @@ abstract class WalletKitServiceBase with Store {
}
await _removePairingTopicFromLocalStorage(topic);
- sessions.clear();
- sessions.addAll(_walletKit.sessions.getAll());
+ _reloadSessionsForCurrentWallet();
_refreshPairings();
}
@@ -559,8 +569,7 @@ abstract class WalletKitServiceBase with Store {
printV('disconnectSession: $e');
}
- sessions.clear();
- sessions.addAll(_walletKit.sessions.getAll());
+ _reloadSessionsForCurrentWallet();
if (pairingTopic != null &&
!_walletKit.sessions.getAll().any((s) => s.pairingTopic == pairingTopic)) {
@@ -619,6 +628,24 @@ abstract class WalletKitServiceBase with Store {
pairings.addAll(filteredPairings);
}
+ @action
+ void _reloadSessionsForCurrentWallet() {
+ sessions.clear();
+
+ final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
+ if (chainKeys.isEmpty) {
+ return;
+ }
+
+ final walletPublicKey = chainKeys.first.publicKey;
+
+ sessions.addAll(
+ _walletKit.sessions
+ .getAll()
+ .where((session) => MethodsUtils.isSessionOwnedByWallet(session, walletPublicKey)),
+ );
+ }
+
@action
List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
diff --git a/lib/src/screens/wallet_connect/utils/method_utils.dart b/lib/src/screens/wallet_connect/utils/method_utils.dart
index 78a11f87..9a0e83a5 100644
--- a/lib/src/screens/wallet_connect/utils/method_utils.dart
+++ b/lib/src/screens/wallet_connect/utils/method_utils.dart
@@ -11,9 +11,27 @@ import 'package:flutter/material.dart';
import 'package:reown_walletkit/reown_walletkit.dart';
class MethodsUtils {
- static final walletKit = getIt.get<WalletKitService>().walletKit;
+ static ReownWalletKit get walletKit => getIt.get<WalletKitService>().walletKit;
static final bottomSheetService = getIt.get<BottomSheetService>();
+ static bool isSessionOwnedByWallet(SessionData? session, String walletPublicKey) {
+ if (session == null || walletPublicKey.isEmpty) {
+ return false;
+ }
+
+ final accounts = session.namespaces.values.expand((namespace) => namespace.accounts);
+
+ return accounts.any((account) => isSameAccount(account.split(":").last, walletPublicKey));
+ }
+
+ static bool isSameAccount(String a, String b) {
+ if (a.startsWith("0x") && b.startsWith("0x")) {
+ return a.toLowerCase() == b.toLowerCase();
+ }
+
+ return a == b;
+ }
+
static const _transactionMethods = {
'eth_sendTransaction',
'eth_signTransaction',
@@ -28,13 +46,19 @@ class MethodsUtils {
String? method,
String? chainId,
String? address,
+ String? topic,
required String transportType,
List<WCConnectionModel> extraModels = const [],
VerifyContext? verifyContext,
}) async {
final appStore = getIt.get<AppStore>();
- final pending = walletKit.pendingRequests.getAll();
- final session = pending.isNotEmpty ? walletKit.sessions.get(pending.last.topic) : null;
+ SessionData? session;
+ if (topic != null) {
+ session = walletKit.sessions.get(topic);
+ } else {
+ final pending = walletKit.pendingRequests.getAll();
+ session = pending.isNotEmpty ? walletKit.sessions.get(pending.last.topic) : null;
+ }
final dAppMetadata = session?.peer.metadata;
final isTransaction = method != null && _transactionMethods.contains(method);
diff --git a/lib/src/screens/wallet_connect/wc_connections_listing_view.dart b/lib/src/screens/wallet_connect/wc_connections_listing_view.dart
index b422b801..f688994c 100644
--- a/lib/src/screens/wallet_connect/wc_connections_listing_view.dart
+++ b/lib/src/screens/wallet_connect/wc_connections_listing_view.dart
@@ -12,6 +12,7 @@ import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/permission_handler.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
+import "package:flutter/cupertino.dart";
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:permission_handler/permission_handler.dart';
@@ -145,6 +146,26 @@ class WalletConnectConnectionsView extends StatelessWidget {
const SizedBox(height: 24),
Observer(
builder: (_) {
+ if (walletKitService.isLoadingConnections) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: 32),
+ child: Center(
+ child: Column(
+ spacing: 12,
+ children: [
+ const CupertinoActivityIndicator(),
+ Text(
+ "${S.of(context).loading}...",
+ style: theme.textTheme.bodyMedium?.copyWith(
+ color: colors.onSurfaceVariant,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
if (walletKitService.pairings.isEmpty) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 32),
diff --git a/lib/store/app_store.dart b/lib/store/app_store.dart
index 85a9bbba..706a9a0e 100644
--- a/lib/store/app_store.dart
+++ b/lib/store/app_store.dart
@@ -1,5 +1,3 @@
-import "dart:async";
-
import "package:cake_wallet/core/amount_parsing_proxy.dart";
import "package:cake_wallet/di.dart";
import "package:cake_wallet/entities/preferences_key.dart";
@@ -60,13 +58,17 @@ abstract class AppStoreBase with Store {
Future<void> changeCurrentWallet(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
final changingToSameWalletType = this.wallet?.type == wallet.type;
+ final previousWalletType = this.wallet?.type;
await this.wallet?.close(shouldCleanup: !changingToSameWalletType);
this.wallet = wallet;
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
if (isWalletConnectCompatibleChain(wallet.type)) {
- unawaited(_setupWalletConnect());
+ getIt.get<WalletKitService>().resetConnectionsState();
+ _queueWalletConnectAction(_setupWalletConnect);
+ } else if (previousWalletType != null && isWalletConnectCompatibleChain(previousWalletType)) {
+ _queueWalletConnectAction(_disposeWalletConnect);
}
await getIt.get<SharedPreferences>().setString(PreferencesKey.currentWalletName, wallet.name);
await getIt
@@ -74,6 +76,12 @@ abstract class AppStoreBase with Store {
.setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type));
}
+ Future<void> _lastWalletConnectAction = Future.value();
+
+ void _queueWalletConnectAction(Future<void> Function() action) {
+ _lastWalletConnectAction = _lastWalletConnectAction.then((_) => action());
+ }
+
Future<void> _setupWalletConnect() async {
try {
final wcService = getIt.get<WalletKitService>();
@@ -84,4 +92,12 @@ abstract class AppStoreBase with Store {
printV("WalletConnect setup failed: $e\n$s");
}
}
+
+ Future<void> _disposeWalletConnect() async {
+ try {
+ await getIt.get<WalletKitService>().onDispose();
+ } catch (e) {
+ printV("WalletConnect teardown failed: $e");
+ }
+ }
}
diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb
index 24f50159..3b13b21d 100644
--- a/res/values/strings_ar.arb
+++ b/res/values/strings_ar.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "توقيع الرسائل والبيانات المكتوبة",
"wc_permission_switch_chains": "قم بالتبديل وإضافة سلاسل EVM",
"wc_permission_view_balance": "عرض رصيد محفظتك ونشاطك",
+ "wc_request_for_different_wallet": "تم تقديم هذا الطلب لمحفظة مختلفة. افتح المحفظة المتصلة بهذا التطبيق وحاول مرة أخرى.",
"wc_scam_warning_message": "يبدو أن هذا الطلب مرسل من عملية احتيال معروفة. يرجى المضي قدما بحذر.",
"wc_scam_warning_title": "تحذير!",
"wc_scan_qr": "مسح QR",
diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb
index b443d1af..c9486893 100644
--- a/res/values/strings_bg.arb
+++ b/res/values/strings_bg.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Подписвайте съобщения и въведени данни",
"wc_permission_switch_chains": "Превключете и добавете EVM вериги",
"wc_permission_view_balance": "Вижте баланса и активността на вашия портфейл",
+ "wc_request_for_different_wallet": "Тази заявка е направена за различен портфейл. Отворете портфейла, свързан с това приложение, и опитайте отново.",
"wc_scam_warning_message": "Тази заявка изглежда е от известна измама. Моля, продължете с повишено внимание.",
"wc_scam_warning_title": "ПРЕДУПРЕЖДЕНИЕ!",
"wc_scan_qr": "Сканирайте QR",
diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb
index f62daa6d..2e68008b 100644
--- a/res/values/strings_cs.arb
+++ b/res/values/strings_cs.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Podepisujte zprávy a zadaná data",
"wc_permission_switch_chains": "Přepněte a přidejte řetězy EVM",
"wc_permission_view_balance": "Prohlédněte si zůstatek a aktivitu v peněžence",
+ "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.",
"wc_scam_warning_message": "Zdá se, že tento požadavek pochází od známého podvodu. Postupujte prosím opatrně.",
"wc_scam_warning_title": "VAROVÁNÍ!",
"wc_scan_qr": "Naskenujte QR",
diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb
index dd7abc18..8044948e 100644
--- a/res/values/strings_de.arb
+++ b/res/values/strings_de.arb
@@ -1460,6 +1460,7 @@
"wc_permission_sign_messages": "Nachrichten und strukturierte Daten signieren",
"wc_permission_switch_chains": "EVM-Ketten wechseln und hinzufügen",
"wc_permission_view_balance": "Kontostand und Aktivität Ihrer Wallet anzeigen",
+ "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.",
"wc_scam_warning_message": "Diese Anfrage scheint von einem bekannten Betrug zu stammen. Bitte gehen Sie vorsichtig vor.",
"wc_scam_warning_title": "WARNUNG!",
"wc_scan_qr": "QR scannen",
diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb
index 9c04a21c..b208f683 100644
--- a/res/values/strings_en.arb
+++ b/res/values/strings_en.arb
@@ -1462,6 +1462,7 @@
"wc_permission_sign_messages": "Sign messages and typed data",
"wc_permission_switch_chains": "Switch and add EVM chains",
"wc_permission_view_balance": "View your wallet balance and activity",
+ "wc_request_for_different_wallet": "This request was made for a different wallet. Open the wallet connected to this app and try again.",
"wc_scam_warning_message": "This request appears to be from a known scam. Please proceed with caution.",
"wc_scam_warning_title": "WARNING!",
"wc_scan_qr": "Scan QR",
diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb
index 78321bd2..ac702c0f 100644
--- a/res/values/strings_es.arb
+++ b/res/values/strings_es.arb
@@ -1423,6 +1423,7 @@
"wc_permission_sign_messages": "Firmar mensajes y datos escritos",
"wc_permission_switch_chains": "Cambie y agregue cadenas EVM",
"wc_permission_view_balance": "Ver el saldo y la actividad de su billetera",
+ "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.",
"wc_scam_warning_message": "Esta solicitud parece provenir de una estafa conocida. Proceda con precaución.",
"wc_scam_warning_title": "¡ADVERTENCIA!",
"wc_scan_qr": "Escanear QR",
diff --git a/res/values/strings_fa.arb b/res/values/strings_fa.arb
index cf886a43..17f55785 100644
--- a/res/values/strings_fa.arb
+++ b/res/values/strings_fa.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "پیام ها و داده های تایپ شده را امضا کنید",
"wc_permission_switch_chains": "زنجیره های EVM را تغییر دهید و اضافه کنید",
"wc_permission_view_balance": "موجودی و فعالیت کیف پول خود را مشاهده کنید",
+ "wc_request_for_different_wallet": "این درخواست برای یک کیف پول متفاوت انجام شده است. کیف پول متصل به این برنامه را باز کنید و دوباره امتحان کنید.",
"wc_scam_warning_message": "به نظر می رسد این درخواست از یک کلاهبرداری شناخته شده باشد. لطفا با احتیاط ادامه دهید",
"wc_scam_warning_title": "هشدار!",
"wc_scan_qr": "اسکن QR",
diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb
index d3f135c8..a8c8df56 100644
--- a/res/values/strings_fr.arb
+++ b/res/values/strings_fr.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Signer les messages et les données saisies",
"wc_permission_switch_chains": "Changer et ajouter des chaînes EVM",
"wc_permission_view_balance": "Consultez le solde et l'activité de votre portefeuille",
+ "wc_request_for_different_wallet": "Cette demande a été faite pour un autre portefeuille. Ouvrez le portefeuille connecté à cette application et réessayez.",
"wc_scam_warning_message": "Cette demande semble provenir d'une arnaque connue. Veuillez procéder avec prudence.",
"wc_scam_warning_title": "AVERTISSEMENT!",
"wc_scan_qr": "Scanner le QR",
diff --git a/res/values/strings_gn.arb b/res/values/strings_gn.arb
index 551e16d4..c86512e7 100644
--- a/res/values/strings_gn.arb
+++ b/res/values/strings_gn.arb
@@ -1428,6 +1428,7 @@
"wc_permission_sign_messages": "Marandu ofirma ha dato ojehaipyréva",
"wc_permission_switch_chains": "Embohasa ha emoĩve umi cadena EVM rehegua",
"wc_permission_view_balance": "Ehecha nde billetera saldo ha actividad",
+ "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.",
"wc_scam_warning_message": "Ko pedido ojekuaa oúha peteî estafa ojekuaávagui. Por favor, peprocede ñeñangareko reheve.",
"wc_scam_warning_title": "ÑEMONGYHYJE!",
"wc_scan_qr": "Escanear QR",
diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb
index ea901d7c..29cda58b 100644
--- a/res/values/strings_ha.arb
+++ b/res/values/strings_ha.arb
@@ -1423,6 +1423,7 @@
"wc_permission_sign_messages": "Sa hannu kan saƙonni da rubutattun bayanai",
"wc_permission_switch_chains": "Canja kuma ƙara sarƙoƙin EVM",
"wc_permission_view_balance": "Duba ma'auni na walat ɗin ku da aiki",
+ "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.",
"wc_scam_warning_message": "Wannan buƙatar ta bayyana daga wata zamba da aka sani. Da fatan za a ci gaba da taka tsantsan.",
"wc_scam_warning_title": "GARGADI!",
"wc_scan_qr": "Duba QR",
diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb
index 15edf008..13d18ae1 100644
--- a/res/values/strings_hi.arb
+++ b/res/values/strings_hi.arb
@@ -1423,6 +1423,7 @@
"wc_permission_sign_messages": "संदेशों पर हस्ताक्षर करें और डेटा टाइप करें",
"wc_permission_switch_chains": "स्विच करें और ईवीएम चेन जोड़ें",
"wc_permission_view_balance": "अपना वॉलेट बैलेंस और गतिविधि देखें",
+ "wc_request_for_different_wallet": "यह अनुरोध एक अलग वॉलेट के लिए किया गया था. इस ऐप से जुड़ा वॉलेट खोलें और पुनः प्रयास करें।",
"wc_scam_warning_message": "ऐसा प्रतीत होता है कि यह अनुरोध किसी ज्ञात घोटाले से आया है। कृपया सावधानी से आगे बढ़ें.",
"wc_scam_warning_title": "चेतावनी!",
"wc_scan_qr": "QR स्कैन करें",
diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb
index 2d99234e..0e4f55c4 100644
--- a/res/values/strings_hr.arb
+++ b/res/values/strings_hr.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Potpisivati poruke i upisane podatke",
"wc_permission_switch_chains": "Prebacite i dodajte EVM lance",
"wc_permission_view_balance": "Pogledajte svoj novčanik i aktivnost",
+ "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.",
"wc_scam_warning_message": "Čini se da ovaj zahtjev potječe iz poznate prijevare. Molimo nastavite s oprezom.",
"wc_scam_warning_title": "UPOZORENJE!",
"wc_scan_qr": "Skeniraj QR",
diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb
index f1a209c9..e45a24dc 100644
--- a/res/values/strings_hy.arb
+++ b/res/values/strings_hy.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Ստորագրեք հաղորդագրությունները և մուտքագրված տվյալները",
"wc_permission_switch_chains": "Միացրեք և ավելացրեք EVM շղթաներ",
"wc_permission_view_balance": "Դիտեք ձեր դրամապանակի մնացորդը և գործունեությունը",
+ "wc_request_for_different_wallet": "Այս հարցումն արվել է այլ դրամապանակի համար: Բացեք այս հավելվածին միացված դրամապանակը և նորից փորձեք:",
"wc_scam_warning_message": "Այս հարցումը, կարծես, հայտնի խարդախությունից է: Խնդրում ենք շարունակել զգուշությամբ:",
"wc_scam_warning_title": "ԶԳՈՒՇԱՑՈՒՄ.",
"wc_scan_qr": "Սկանավորել QR",
diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb
index c1fea5b4..478dc7d6 100644
--- a/res/values/strings_id.arb
+++ b/res/values/strings_id.arb
@@ -1424,6 +1424,7 @@
"wc_permission_sign_messages": "Menandatangani pesan dan mengetik data",
"wc_permission_switch_chains": "Beralih dan tambahkan rantai EVM",
"wc_permission_view_balance": "Lihat saldo dan aktivitas dompet Anda",
+ "wc_request_for_different_wallet": "Permintaan ini dibuat untuk dompet yang berbeda. Buka dompet yang terhubung ke aplikasi ini dan coba lagi.",
"wc_scam_warning_message": "Permintaan ini tampaknya berasal dari penipuan yang diketahui. Silakan lanjutkan dengan hati-hati.",
"wc_scam_warning_title": "PERINGATAN!",
"wc_scan_qr": "Pindai QR",
diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb
index d7ae0b9c..1fc6ff17 100644
--- a/res/values/strings_it.arb
+++ b/res/values/strings_it.arb
@@ -1422,6 +1422,7 @@
"wc_permission_sign_messages": "Firmare messaggi e dati digitati",
"wc_permission_switch_chains": "Cambia e aggiungi catene EVM",
"wc_permission_view_balance": "Visualizza il saldo e l'attività del tuo portafoglio",
+ "wc_request_for_different_wallet": "Questa richiesta è stata effettuata per un portafoglio diverso. Apri il portafoglio connesso a questa app e riprova.",
"wc_scam_warning_message": "Questa richiesta sembra provenire da una truffa nota. Si prega di procedere con cautela.",
"wc_scam_warning_title": "AVVERTIMENTO!",
"wc_scan_qr": "Scansione QR",
diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb
index e9708e48..b6836bf6 100644
--- a/res/values/strings_ja.arb
+++ b/res/values/strings_ja.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "メッセージと入力されたデータに署名する",
"wc_permission_switch_chains": "EVMチェーンの切り替えと追加",
"wc_permission_view_balance": "ウォレットの残高とアクティビティを表示する",
+ "wc_request_for_different_wallet": "このリクエストは別のウォレットに対して行われました。このアプリに接続されているウォレットを開いて、もう一度お試しください。",
"wc_scam_warning_message": "このリクエストは既知の詐欺によるものと思われます。慎重に進めてください。",
"wc_scam_warning_title": "警告!",
"wc_scan_qr": "QRをスキャン",
diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb
index 35dd2e70..852be390 100644
--- a/res/values/strings_ko.arb
+++ b/res/values/strings_ko.arb
@@ -1420,6 +1420,7 @@
"wc_permission_sign_messages": "메시지 및 입력된 데이터에 서명",
"wc_permission_switch_chains": "EVM 체인 전환 및 추가",
"wc_permission_view_balance": "지갑 잔액 및 활동 보기",
+ "wc_request_for_different_wallet": "이 요청은 다른 지갑에 대해 이루어졌습니다. 이 앱에 연결된 지갑을 열고 다시 시도해 보세요.",
"wc_scam_warning_message": "이 요청은 알려진 사기에서 나온 것 같습니다. 주의해서 진행하시기 바랍니다.",
"wc_scam_warning_title": "경고!",
"wc_scan_qr": "QR 스캔",
diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb
index 990a568e..879e8382 100644
--- a/res/values/strings_my.arb
+++ b/res/values/strings_my.arb
@@ -1420,6 +1420,7 @@
"wc_permission_sign_messages": "မက်ဆေ့ချ်များကို လက်မှတ်ထိုးပြီး ဒေတာကို ရိုက်ထည့်ပါ။",
"wc_permission_switch_chains": "EVM chain များကို ပြောင်းပြီး ထည့်ပါ",
"wc_permission_view_balance": "သင့်ပိုက်ဆံအိတ်လက်ကျန်ငွေနှင့် လုပ်ဆောင်ချက်ကို ကြည့်ရှုပါ။",
+ "wc_request_for_different_wallet": "ဤတောင်းဆိုချက်ကို မတူညီသော ပိုက်ဆံအိတ်အတွက် ပြုလုပ်ထားပါသည်။ ဤအက်ပ်နှင့်ချိတ်ဆက်ထားသော ပိုက်ဆံအိတ်ကိုဖွင့်ပြီး ထပ်စမ်းကြည့်ပါ။",
"wc_scam_warning_message": "ဤတောင်းဆိုချက်သည် လူသိများသော လိမ်လည်မှုတစ်ခုမှ ဖြစ်ပုံရသည်။ ကျေးဇူးပြု၍ သတိဖြင့် ဆက်လုပ်ပါ။",
"wc_scam_warning_title": "သတိပေးချက်။",
"wc_scan_qr": "QR ကိုစကင်န်ဖတ်ပါ။",
diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb
index 0671d7e1..9f7bc6d2 100644
--- a/res/values/strings_nl.arb
+++ b/res/values/strings_nl.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Onderteken berichten en getypte gegevens",
"wc_permission_switch_chains": "Schakel over en voeg EVM-ketens toe",
"wc_permission_view_balance": "Bekijk je walletsaldo en activiteit",
+ "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.",
"wc_scam_warning_message": "Dit verzoek lijkt afkomstig te zijn van een bekende oplichting. Ga alstublieft voorzichtig te werk.",
"wc_scam_warning_title": "WAARSCHUWING!",
"wc_scan_qr": "QR scannen",
diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb
index e0de2a83..013896b1 100644
--- a/res/values/strings_pl.arb
+++ b/res/values/strings_pl.arb
@@ -1420,6 +1420,7 @@
"wc_permission_sign_messages": "Podpisuj wiadomości i wpisywane dane",
"wc_permission_switch_chains": "Przełącz i dodaj łańcuchy EVM",
"wc_permission_view_balance": "Sprawdź saldo i aktywność swojego portfela",
+ "wc_request_for_different_wallet": "To żądanie dotyczyło innego portfela. Otwórz portfel połączony z tą aplikacją i spróbuj ponownie.",
"wc_scam_warning_message": "Wygląda na to, że to żądanie pochodzi ze znanego oszustwa. Proszę postępować ostrożnie.",
"wc_scam_warning_title": "OSTRZEŻENIE!",
"wc_scan_qr": "Zeskanuj kod QR",
diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb
index d9204e34..c3ab4bae 100644
--- a/res/values/strings_pt.arb
+++ b/res/values/strings_pt.arb
@@ -1423,6 +1423,7 @@
"wc_permission_sign_messages": "Assinar mensagens e dados digitados",
"wc_permission_switch_chains": "Alternar e adicionar cadeias EVM",
"wc_permission_view_balance": "Veja o saldo e a atividade da sua carteira",
+ "wc_request_for_different_wallet": "Esta solicitação foi feita para uma carteira diferente. Abra a carteira conectada a este aplicativo e tente novamente.",
"wc_scam_warning_message": "Esta solicitação parece ser de um golpe conhecido. Por favor, proceda com cautela.",
"wc_scam_warning_title": "AVISO!",
"wc_scan_qr": "Digitalize QR",
diff --git a/res/values/strings_pt_BR.arb b/res/values/strings_pt_BR.arb
index d703a3ec..c552992e 100644
--- a/res/values/strings_pt_BR.arb
+++ b/res/values/strings_pt_BR.arb
@@ -1361,6 +1361,7 @@
"wc_permission_sign_messages": "Assinar mensagens e dados digitados",
"wc_permission_switch_chains": "Alternar e adicionar cadeias EVM",
"wc_permission_view_balance": "Veja o saldo e a atividade da sua carteira",
+ "wc_request_for_different_wallet": "Esta solicitação foi feita para uma carteira diferente. Abra a carteira conectada a este aplicativo e tente novamente.",
"wc_scam_warning_message": "Esta solicitação parece ser de um golpe conhecido. Por favor, proceda com cautela.",
"wc_scam_warning_title": "AVISO!",
"wc_scan_qr": "Digitalize QR",
diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb
index aeb56f31..ca12a089 100644
--- a/res/values/strings_ru.arb
+++ b/res/values/strings_ru.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Подписывать сообщения и вводимые данные",
"wc_permission_switch_chains": "Переключение и добавление цепочек EVM",
"wc_permission_view_balance": "Просматривайте баланс и активность своего кошелька",
+ "wc_request_for_different_wallet": "Этот запрос был сделан для другого кошелька. Откройте кошелек, подключенный к этому приложению, и повторите попытку.",
"wc_scam_warning_message": "Судя по всему, этот запрос поступил от известного мошенника. Пожалуйста, действуйте осторожно.",
"wc_scam_warning_title": "ПРЕДУПРЕЖДЕНИЕ!",
"wc_scan_qr": "Сканировать QR-код",
diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb
index 44096cbd..818a8f6c 100644
--- a/res/values/strings_th.arb
+++ b/res/values/strings_th.arb
@@ -1420,6 +1420,7 @@
"wc_permission_sign_messages": "เซ็นข้อความและพิมพ์ข้อมูล",
"wc_permission_switch_chains": "สลับและเพิ่มเชน EVM",
"wc_permission_view_balance": "ดูยอดคงเหลือในกระเป๋าสตางค์และกิจกรรมของคุณ",
+ "wc_request_for_different_wallet": "คำขอนี้สร้างขึ้นสำหรับกระเป๋าเงินอื่น เปิดกระเป๋าเงินที่เชื่อมต่อกับแอพนี้แล้วลองอีกครั้ง",
"wc_scam_warning_message": "ดูเหมือนว่าคำขอนี้มาจากกลโกงที่ทราบ โปรดดำเนินการด้วยความระมัดระวัง",
"wc_scam_warning_title": "คำเตือน!",
"wc_scan_qr": "สแกนคิวอาร์",
diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb
index bdb4d46a..374cb161 100644
--- a/res/values/strings_tl.arb
+++ b/res/values/strings_tl.arb
@@ -1420,6 +1420,7 @@
"wc_permission_sign_messages": "Mag-sign ng mga mensahe at nai-type na data",
"wc_permission_switch_chains": "Lumipat at magdagdag ng mga EVM chain",
"wc_permission_view_balance": "Tingnan ang balanse at aktibidad ng iyong wallet",
+ "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.",
"wc_scam_warning_message": "Mukhang mula sa isang kilalang scam ang kahilingang ito. Mangyaring magpatuloy nang may pag-iingat.",
"wc_scam_warning_title": "BABALA!",
"wc_scan_qr": "I-scan ang QR",
diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb
index 67684f6d..82b27c80 100644
--- a/res/values/strings_tr.arb
+++ b/res/values/strings_tr.arb
@@ -1420,6 +1420,7 @@
"wc_permission_sign_messages": "Mesajları ve yazılan verileri imzalayın",
"wc_permission_switch_chains": "EVM zincirlerini değiştirin ve ekleyin",
"wc_permission_view_balance": "Cüzdan bakiyenizi ve etkinliğinizi görüntüleyin",
+ "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.",
"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.",
"wc_scam_warning_title": "UYARI!",
"wc_scan_qr": "QR'yi tara",
diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb
index 14fa38f5..6558649f 100644
--- a/res/values/strings_uk.arb
+++ b/res/values/strings_uk.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Підписуйте повідомлення та введені дані",
"wc_permission_switch_chains": "Перемикайте та додавайте ланцюжки EVM",
"wc_permission_view_balance": "Перегляньте свій баланс гаманця та активність",
+ "wc_request_for_different_wallet": "Цей запит було зроблено для іншого гаманця. Відкрийте гаманець, підключений до цієї програми, і повторіть спробу.",
"wc_scam_warning_message": "Схоже, цей запит надійшов від відомого шахрая. Будь ласка, будьте обережні.",
"wc_scam_warning_title": "УВАГА!",
"wc_scan_qr": "Сканувати QR",
diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb
index ba77da2b..f241478a 100644
--- a/res/values/strings_ur.arb
+++ b/res/values/strings_ur.arb
@@ -1422,6 +1422,7 @@
"wc_permission_sign_messages": "پیغامات پر دستخط کریں اور ڈیٹا ٹائپ کریں۔",
"wc_permission_switch_chains": "ای وی ایم چینز کو تبدیل کریں اور شامل کریں۔",
"wc_permission_view_balance": "اپنے والیٹ کا بیلنس اور سرگرمی دیکھیں",
+ "wc_request_for_different_wallet": "یہ درخواست ایک مختلف بٹوے کے لیے کی گئی تھی۔ اس ایپ سے منسلک والیٹ کھولیں اور دوبارہ کوشش کریں۔",
"wc_scam_warning_message": "یہ درخواست کسی معروف اسکام کی طرف سے معلوم ہوتی ہے۔ براہ کرم احتیاط کے ساتھ آگے بڑھیں۔",
"wc_scam_warning_title": "وارننگ!",
"wc_scan_qr": "QR اسکین کریں۔",
diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb
index 41b269d4..594657af 100644
--- a/res/values/strings_vi.arb
+++ b/res/values/strings_vi.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Ký tin nhắn và dữ liệu có cấu trúc",
"wc_permission_switch_chains": "Chuyển đổi và thêm chuỗi EVM",
"wc_permission_view_balance": "Xem số dư và hoạt động ví của bạn",
+ "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.",
"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.",
"wc_scam_warning_title": "CẢNH BÁO!",
"wc_scan_qr": "Quét QR",
diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb
index 15f858b9..def4de26 100644
--- a/res/values/strings_yo.arb
+++ b/res/values/strings_yo.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "Wole awọn ifiranṣẹ ati titẹ data",
"wc_permission_switch_chains": "Yipada ki o si fi EVM dè",
"wc_permission_view_balance": "Wo iwọntunwọnsi apamọwọ rẹ ati iṣẹ ṣiṣe",
+ "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.",
"wc_scam_warning_message": "Ibeere yii han lati wa lati itanjẹ ti a mọ. Jọwọ tẹsiwaju pẹlu iṣọra.",
"wc_scam_warning_title": "IKILO!",
"wc_scan_qr": "Ṣayẹwo QR",
diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb
index 71173502..91e88581 100644
--- a/res/values/strings_zh.arb
+++ b/res/values/strings_zh.arb
@@ -1421,6 +1421,7 @@
"wc_permission_sign_messages": "签署消息和键入的数据",
"wc_permission_switch_chains": "切换并添加EVM链",
"wc_permission_view_balance": "查看您的钱包余额和活动",
+ "wc_request_for_different_wallet": "此请求是针对不同的钱包提出的。打开连接到该应用程序的钱包并重试。",
"wc_scam_warning_message": "此请求似乎来自一个已知的骗局。请谨慎行事。",
"wc_scam_warning_title": "警告!",
"wc_scan_qr": "扫描二维码",
Why this scored 72/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.