fix: Better handle expired session and auth data for walletconnect (#3228)
* fix: Better handle expired session and auth data for walletconnect * fix: handle dApp disconnected sessions, reflecting the state locally * Update lib/src/screens/wallet_connect/services/walletkit_service.dart [skip ci --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
David Adegoke committed
May 20, 2026 at 17:22 UTC
d325ece6ea51cfe12c2260a55ab24761d16e67cb
1 file changed
+72
-15
lib/src/screens/wallet_connect/services/walletkit_service.dart
+72
-15
@@ -2,6 +2,7 @@ import 'dart:async';
2
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';
7
import 'package:eth_sig_util/util/utils.dart';
8
import 'package:flutter/material.dart';
@@ -149,6 +150,9 @@ abstract class WalletKitServiceBase with Store {
150
151
_refreshPairings();
152
153
+ sessions.clear();
154
+ auth.clear();
155
+
156
final newSessions = _walletKit.sessions.getAll();
157
sessions.addAll(newSessions);
158
@@ -185,12 +189,16 @@ abstract class WalletKitServiceBase with Store {
189
final isOnline = _walletKit.core.connectivity.isOnline.value;
190
if (!isOnline) {
191
await Future.delayed(const Duration(milliseconds: 500));
188
- _emitEvent();
192
+Future<void> _emitEvent({int retries = 0}) async {
193
+final isOnline = _walletKit.core.connectivity.isOnline.value;
194
+if (!isOnline && retries < 3) {
195
+await Future.delayed(const Duration(milliseconds: 500));
196
+ await _emitEvent(retries: ++retries);
197
return;
198
}
199
192
- final sessions = _walletKit.sessions.getAll();
193
- for (var session in sessions) {
200
+ final engineSessions = _walletKit.sessions.getAll();
201
+ for (var session in engineSessions) {
202
final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
203
for (var chain in chainKeys) {
204
for (var chainID in chain.chains) {
@@ -200,13 +208,12 @@ abstract class WalletKitServiceBase with Store {
208
namespaces: session.namespaces,
209
);
210
if (events.contains('accountsChanged')) {
203
- final chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
204
- _walletKit.emitSessionEvent(
211
+ await _walletKit.emitSessionEvent(
212
topic: session.topic,
213
chainId: chainID,
214
event: SessionEventParams(
215
name: 'accountsChanged',
209
- data: [chainKeys.first.publicKey],
216
+ data: [chain.publicKey],
217
),
218
);
219
}
@@ -215,6 +222,7 @@ abstract class WalletKitServiceBase with Store {
222
try {
223
await deletePairing(topic: session.pairingTopic);
224
} catch (_) {}
225
+ sessions.removeWhere((s) => s.topic == session.topic);
226
_refreshPairings();
227
}
228
} catch (_) {}
@@ -242,6 +250,10 @@ abstract class WalletKitServiceBase with Store {
250
_walletKit.core.pairing.onPairingDelete.unsubscribe(_onPairingDelete);
251
_walletKit.core.pairing.onPairingExpire.unsubscribe(_onPairingDelete);
252
253
+ sessions.clear();
254
+ auth.clear();
255
+ pairings.clear();
256
+
257
isInitialized = false;
258
}
259
@@ -511,23 +523,57 @@ abstract class WalletKitServiceBase with Store {
523
524
@action
525
Future<void> deletePairing({required String topic}) async {
514
- final topicSessions = sessions.where((element) => element.pairingTopic == topic);
526
+ final topicSessions =
527
+ sessions.where((element) => element.pairingTopic == topic).toList();
528
529
await _walletKit.core.pairing.disconnect(topic: topic);
530
for (var session in topicSessions) {
518
- await _walletKit.disconnectSession(
519
- topic: session.topic,
520
- reason: Errors.getSdkError(Errors.USER_DISCONNECTED).toSignError(),
521
- );
531
+ try {
532
+ await _walletKit.disconnectSession(
533
+ topic: session.topic,
534
+ reason: Errors.getSdkError(Errors.USER_DISCONNECTED).toSignError(),
535
+ );
536
+ } catch (_) {}
537
}
538
+
539
+ await _removePairingTopicFromLocalStorage(topic);
540
+ sessions.clear();
541
+ sessions.addAll(_walletKit.sessions.getAll());
542
+ _refreshPairings();
543
}
544
545
@action
546
Future<void> disconnectSession({required String topic}) async {
527
- await walletKit.disconnectSession(
528
- topic: topic,
529
- reason: Errors.getSdkError(Errors.USER_DISCONNECTED).toSignError(),
530
- );
547
+ String? pairingTopic;
548
+ for (final s in sessions) {
549
+ if (s.topic == topic) {
550
+ pairingTopic = s.pairingTopic;
551
+ break;
552
+ }
553
+ }
554
+ pairingTopic ??= _walletKit.sessions.get(topic)?.pairingTopic;
555
+
556
+ try {
557
+ await walletKit.disconnectSession(
558
+ topic: topic,
559
+ reason: Errors.getSdkError(Errors.USER_DISCONNECTED).toSignError(),
560
+ );
561
+ } catch (e) {
562
+ printV('disconnectSession: $e');
563
+ }
564
+
565
+ sessions.clear();
566
+ sessions.addAll(_walletKit.sessions.getAll());
567
+
568
+ if (pairingTopic != null &&
569
+ !_walletKit.sessions.getAll().any((s) => s.pairingTopic == pairingTopic)) {
570
+ await _removePairingTopicFromLocalStorage(pairingTopic);
571
+ try {
572
+ await _walletKit.core.pairing.disconnect(topic: pairingTopic);
573
+ } catch (_) {}
574
+ }
575
+
576
+ _refreshPairings();
577
}
578
579
@action
@@ -637,6 +683,17 @@ abstract class WalletKitServiceBase with Store {
683
return jsonList.map((item) => item as String).toList();
684
}
685
686
+ Future<void> _removePairingTopicFromLocalStorage(String pairingTopic) async {
687
+ final key = getKeyForStoringTopicsForWallet();
688
+ if (key.isEmpty) return;
689
+
690
+ final topics = getPairingTopicsForWallet(key);
691
+ if (!topics.contains(pairingTopic)) return;
692
+
693
+ topics.remove(pairingTopic);
694
+ await sharedPreferences.setString(key, jsonEncode(topics));
695
+ }
696
+
697
Future<void> savePairingTopicToLocalStorage(String pairingTopic) async {
698
// Get key specific to the current wallet
699
final key = getKeyForStoringTopicsForWallet();