From 7abe5735c0d03f65a0b3576170e8814e159b3a0f Mon Sep 17 00:00:00 2001 From: Adegoke David <64401859+Blazebrain@users.noreply.github.com> Date: Fri, 12 Apr 2024 01:33:43 +0100 Subject: [PATCH] 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 * 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 Co-authored-by: Omar Hatem --- .../wallet_connect/web3wallet_service.dart | 88 +++++++++++++++++-- lib/di.dart | 1 + lib/entities/preferences_key.dart | 3 + .../widgets/pairing_item_widget.dart | 2 +- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/lib/core/wallet_connect/web3wallet_service.dart b/lib/core/wallet_connect/web3wallet_service.dart index 66ccb2d76..adb516817 100644 --- a/lib/core/wallet_connect/web3wallet_service.dart +++ b/lib/core/wallet_connect/web3wallet_service.dart @@ -1,10 +1,12 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:developer'; import 'dart:typed_data'; import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart'; import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_service.dart'; import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart'; +import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart'; import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart'; @@ -19,6 +21,7 @@ import 'package:cw_core/wallet_type.dart'; import 'package:eth_sig_util/eth_sig_util.dart'; import 'package:flutter/material.dart'; import 'package:mobx/mobx.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'chain_service/solana/solana_chain_id.dart'; @@ -32,6 +35,7 @@ class Web3WalletService = Web3WalletServiceBase with _$Web3WalletService; abstract class Web3WalletServiceBase with Store { final AppStore appStore; + final SharedPreferences sharedPreferences; final BottomSheetService _bottomSheetHandler; final WalletConnectKeyService walletKeyService; @@ -52,7 +56,8 @@ abstract class Web3WalletServiceBase with Store { @observable ObservableList auth; - Web3WalletServiceBase(this._bottomSheetHandler, this.walletKeyService, this.appStore) + Web3WalletServiceBase( + this._bottomSheetHandler, this.walletKeyService, this.appStore, this.sharedPreferences) : pairings = ObservableList(), sessions = ObservableList(), auth = ObservableList(), @@ -191,13 +196,6 @@ abstract class Web3WalletServiceBase with Store { _refreshPairings(); } - @action - void _refreshPairings() { - pairings.clear(); - final allPairings = _web3Wallet.pairings.getAll(); - pairings.addAll(allPairings); - } - Future _onSessionProposalError(SessionProposalErrorEvent? args) async { log(args.toString()); } @@ -260,14 +258,37 @@ abstract class Web3WalletServiceBase with Store { } } + @action + void _refreshPairings() { + print('Refreshing pairings'); + pairings.clear(); + + final allPairings = _web3Wallet.pairings.getAll(); + + final keyForWallet = getKeyForStoringTopicsForWallet(); + + final currentTopicsForWallet = getPairingTopicsForWallet(keyForWallet); + + final filteredPairings = + allPairings.where((pairing) => currentTopicsForWallet.contains(pairing.topic)).toList(); + + pairings.addAll(filteredPairings); + } + void _onPairingCreate(PairingEvent? args) { log('Pairing Create Event: $args'); } @action - void _onSessionConnect(SessionConnect? args) { + Future _onSessionConnect(SessionConnect? args) async { if (args != null) { + log('Session Connected $args'); + + await savePairingTopicToLocalStorage(args.session.pairingTopic); + sessions.add(args.session); + + _refreshPairings(); } } @@ -335,4 +356,53 @@ abstract class Web3WalletServiceBase with Store { List getSessionsForPairingInfo(PairingInfo pairing) { return sessions.where((element) => element.pairingTopic == pairing.topic).toList(); } + + String getKeyForStoringTopicsForWallet() { + List chainKeys = walletKeyService.getKeysForChain(appStore.wallet!); + + final keyForPairingTopic = + PreferencesKey.walletConnectPairingTopicsListForWallet(chainKeys.first.publicKey); + + return keyForPairingTopic; + } + + List getPairingTopicsForWallet(String key) { + // Get the JSON-encoded string from shared preferences + final jsonString = sharedPreferences.getString(key); + + // If the string is null, return an empty list + if (jsonString == null) { + return []; + } + + // Decode the JSON string to a list of strings + final List jsonList = jsonDecode(jsonString) as List; + + // Cast each item to a string + return jsonList.map((item) => item as String).toList(); + } + + Future savePairingTopicToLocalStorage(String pairingTopic) async { + // Get key specific to the current wallet + final key = getKeyForStoringTopicsForWallet(); + + // Get all pairing topics attached to this key + final pairingTopicsForWallet = getPairingTopicsForWallet(key); + + print(pairingTopicsForWallet); + + bool isPairingTopicAlreadySaved = pairingTopicsForWallet.contains(pairingTopic); + print('Is Pairing Topic Saved: $isPairingTopicAlreadySaved'); + + if (!isPairingTopicAlreadySaved) { + // Update the list with the most recent pairing topic + pairingTopicsForWallet.add(pairingTopic); + + // Convert the list of updated pairing topics to a JSON-encoded string + final jsonString = jsonEncode(pairingTopicsForWallet); + + // Save the encoded string to shared preferences + await sharedPreferences.setString(key, jsonString); + } + } } diff --git a/lib/di.dart b/lib/di.dart index 5262a01e6..d78da638c 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -493,6 +493,7 @@ Future setup({ getIt.get(), getIt.get(), appStore, + getIt.get() ); web3WalletService.create(); return web3WalletService; diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index ba6d6ef4f..80a7acba1 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -75,4 +75,7 @@ class PreferencesKey { static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard'; static const isNewInstall = 'is_new_install'; static const serviceStatusShaKey = 'service_status_sha_key'; + static const walletConnectPairingTopicsList = 'wallet_connect_pairing_topics_list'; + static String walletConnectPairingTopicsListForWallet(String publicKey) => + '${PreferencesKey.walletConnectPairingTopicsList}_${publicKey}'; } diff --git a/lib/src/screens/wallet_connect/widgets/pairing_item_widget.dart b/lib/src/screens/wallet_connect/widgets/pairing_item_widget.dart index 0d425f904..518cf32f7 100644 --- a/lib/src/screens/wallet_connect/widgets/pairing_item_widget.dart +++ b/lib/src/screens/wallet_connect/widgets/pairing_item_widget.dart @@ -30,7 +30,7 @@ class PairingItemWidget extends StatelessWidget { leading: CakeImageWidget( imageUrl: metadata.icons.isNotEmpty ? metadata.icons[0]: null, displayOnError: CircleAvatar( - backgroundImage: AssetImage('assets/images/default_icon.png'), + backgroundImage: AssetImage('assets/images/walletconnect_logo.png'), ), ), title: Text(