CW-589-WalletConnect-Connections-Independent (#1361)

* chore: Create cw_solana package and clean up files * feat: Add Solana Wallet - Create, Restore form seed, restore from Key, Restore from QR, Send, Receive, transaction history, spl tokens * fix: Make transactions file specific to solana only for solana transactions * chore: Revert inject app details script * fix: Fix issue with node and switch current node to main beta instead of testnet * fix: Fix merge conflicts and adjust migration version * fix: Fetch spl token error Signed-off-by: Blazebrain <davidadegoke16@gmail.com> * fix: Diplay and activate spl tokens bug * fix: Review and fixes * fix: reverted formatting for cryptocurrency class * fix: Review comments, split sending flow into signing and sending separately, fix issues * fix: Revert throwing unimplenented error * chore: Fix comment * chore: Fix comment * fix: Errors in flow * Update provider_types.dart [skip ci] * fix: Issues with solana wallet * Update solana_wallet.dart [skip ci] * fix: Review comments * fix: Date time config * fix: Revert bash script for app details * fix: Error with balance, displaying fees, fixing sent or received identifier bug, displaying token symbol with token transaction item in transactions list * fix: Issues with address validation when sending spl tokens and walletconnect initial setup * fix: Issues with sending, fetching transactions history, almost wrapping up walletconnect * fix: Adjust imports that would affect monerocom building successfully * fix: Refine transaction direction and continue work on walletconnect * feat: Display SPL token transfers in the transaction history and finally settle the transaction direction * fix: Delay in transactions history dispaly, show native token transactions first, then process spl token transactions * feat: Switch node and revert solana chain id to previous id * fix: Remove print statement * fix: Remove await for transactions, fetch all transaction histories instantly and adjust solana send success message * chore: Code refactoring and streamlined wallet type check for solana send success message * fix: Make timeout error for node silent and add spl token images * fix: Still trying to figure out what's wrong * feat: Make walletconnect connections independent to wallet * fix: Add proper return type to method * fix: Alphabetizing translation files --------- Signed-off-by: Blazebrain <davidadegoke16@gmail.com> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

Adegoke David committed Apr 12, 2024 at 01:33 UTC 7abe5735c0d03f65a0b3576170e8814e159b3a0f
4 files changed +84 -10
lib/core/wallet_connect/web3wallet_service.dart
+79 -9
@@ -1,10 +1,12 @@
1 import 'dart:async';
2 +import 'dart:convert';
3 import 'dart:developer';
4 import 'dart:typed_data';
5
6 import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart';
7 import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_service.dart';
8 import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
9 +import 'package:cake_wallet/entities/preferences_key.dart';
10 import 'package:cake_wallet/generated/i18n.dart';
11 import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
12 import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
@@ -19,6 +21,7 @@ import 'package:cw_core/wallet_type.dart';
21 import 'package:eth_sig_util/eth_sig_util.dart';
22 import 'package:flutter/material.dart';
23 import 'package:mobx/mobx.dart';
24 +import 'package:shared_preferences/shared_preferences.dart';
25 import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
26
27 import 'chain_service/solana/solana_chain_id.dart';
@@ -32,6 +35,7 @@ class Web3WalletService = Web3WalletServiceBase with _$Web3WalletService;
35
36 abstract class Web3WalletServiceBase with Store {
37 final AppStore appStore;
38 + final SharedPreferences sharedPreferences;
39 final BottomSheetService _bottomSheetHandler;
40 final WalletConnectKeyService walletKeyService;
41
@@ -52,7 +56,8 @@ abstract class Web3WalletServiceBase with Store {
56 @observable
57 ObservableList<StoredCacao> auth;
58
55 - Web3WalletServiceBase(this._bottomSheetHandler, this.walletKeyService, this.appStore)
59 + Web3WalletServiceBase(
60 + this._bottomSheetHandler, this.walletKeyService, this.appStore, this.sharedPreferences)
61 : pairings = ObservableList<PairingInfo>(),
62 sessions = ObservableList<SessionData>(),
63 auth = ObservableList<StoredCacao>(),
@@ -191,13 +196,6 @@ abstract class Web3WalletServiceBase with Store {
196 _refreshPairings();
197 }
198
194 - @action
195 - void _refreshPairings() {
196 - pairings.clear();
197 - final allPairings = _web3Wallet.pairings.getAll();
198 - pairings.addAll(allPairings);
199 - }
200 -
199 Future<void> _onSessionProposalError(SessionProposalErrorEvent? args) async {
200 log(args.toString());
201 }
@@ -260,14 +258,37 @@ abstract class Web3WalletServiceBase with Store {
258 }
259 }
260
261 + @action
262 + void _refreshPairings() {
263 + print('Refreshing pairings');
264 + pairings.clear();
265 +
266 + final allPairings = _web3Wallet.pairings.getAll();
267 +
268 + final keyForWallet = getKeyForStoringTopicsForWallet();
269 +
270 + final currentTopicsForWallet = getPairingTopicsForWallet(keyForWallet);
271 +
272 + final filteredPairings =
273 + allPairings.where((pairing) => currentTopicsForWallet.contains(pairing.topic)).toList();
274 +
275 + pairings.addAll(filteredPairings);
276 + }
277 +
278 void _onPairingCreate(PairingEvent? args) {
279 log('Pairing Create Event: $args');
280 }
281
282 @action
268 - void _onSessionConnect(SessionConnect? args) {
283 + Future<void> _onSessionConnect(SessionConnect? args) async {
284 if (args != null) {
285 + log('Session Connected $args');
286 +
287 + await savePairingTopicToLocalStorage(args.session.pairingTopic);
288 +
289 sessions.add(args.session);
290 +
291 + _refreshPairings();
292 }
293 }
294
@@ -335,4 +356,53 @@ abstract class Web3WalletServiceBase with Store {
356 List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
357 return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
358 }
359 +
360 + String getKeyForStoringTopicsForWallet() {
361 + List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
362 +
363 + final keyForPairingTopic =
364 + PreferencesKey.walletConnectPairingTopicsListForWallet(chainKeys.first.publicKey);
365 +
366 + return keyForPairingTopic;
367 + }
368 +
369 + List<String> getPairingTopicsForWallet(String key) {
370 + // Get the JSON-encoded string from shared preferences
371 + final jsonString = sharedPreferences.getString(key);
372 +
373 + // If the string is null, return an empty list
374 + if (jsonString == null) {
375 + return [];
376 + }
377 +
378 + // Decode the JSON string to a list of strings
379 + final List<dynamic> jsonList = jsonDecode(jsonString) as List<dynamic>;
380 +
381 + // Cast each item to a string
382 + return jsonList.map((item) => item as String).toList();
383 + }
384 +
385 + Future<void> savePairingTopicToLocalStorage(String pairingTopic) async {
386 + // Get key specific to the current wallet
387 + final key = getKeyForStoringTopicsForWallet();
388 +
389 + // Get all pairing topics attached to this key
390 + final pairingTopicsForWallet = getPairingTopicsForWallet(key);
391 +
392 + print(pairingTopicsForWallet);
393 +
394 + bool isPairingTopicAlreadySaved = pairingTopicsForWallet.contains(pairingTopic);
395 + print('Is Pairing Topic Saved: $isPairingTopicAlreadySaved');
396 +
397 + if (!isPairingTopicAlreadySaved) {
398 + // Update the list with the most recent pairing topic
399 + pairingTopicsForWallet.add(pairingTopic);
400 +
401 + // Convert the list of updated pairing topics to a JSON-encoded string
402 + final jsonString = jsonEncode(pairingTopicsForWallet);
403 +
404 + // Save the encoded string to shared preferences
405 + await sharedPreferences.setString(key, jsonString);
406 + }
407 + }
408 }
lib/di.dart
+1
@@ -493,6 +493,7 @@ Future<void> setup({
493 getIt.get<BottomSheetService>(),
494 getIt.get<WalletConnectKeyService>(),
495 appStore,
496 + getIt.get<SharedPreferences>()
497 );
498 web3WalletService.create();
499 return web3WalletService;
lib/entities/preferences_key.dart
+3
@@ -75,4 +75,7 @@ class PreferencesKey {
75 static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard';
76 static const isNewInstall = 'is_new_install';
77 static const serviceStatusShaKey = 'service_status_sha_key';
78 + static const walletConnectPairingTopicsList = 'wallet_connect_pairing_topics_list';
79 + static String walletConnectPairingTopicsListForWallet(String publicKey) =>
80 + '${PreferencesKey.walletConnectPairingTopicsList}_${publicKey}';
81 }
lib/src/screens/wallet_connect/widgets/pairing_item_widget.dart
+1 -1
@@ -30,7 +30,7 @@ class PairingItemWidget extends StatelessWidget {
30 leading: CakeImageWidget(
31 imageUrl: metadata.icons.isNotEmpty ? metadata.icons[0]: null,
32 displayOnError: CircleAvatar(
33 - backgroundImage: AssetImage('assets/images/default_icon.png'),
33 + backgroundImage: AssetImage('assets/images/walletconnect_logo.png'),
34 ),
35 ),
36 title: Text(