CW-584-WalletConnect-For-Solana (#1362)

* 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 * Sync with remote * feat: First run for walletconnect for solana * chore: Add ankr api key to secrets * remove duplicate transaction [skip ci] --------- Signed-off-by: Blazebrain <davidadegoke16@gmail.com> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

Adegoke David committed Apr 9, 2024 at 01:26 UTC f9679fecbeaacbbf3d4694a14a00cf47e5262448
6 files changed +40 -18
.github/workflows/pr_test_build.yml
+1
@@ -139,6 +139,7 @@ jobs:
139 echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
140 echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
141 echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
142 + echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
143 echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
144 echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
145 echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
lib/core/wallet_connect/chain_service/solana/solana_chain_id.dart
+11 -8
@@ -2,8 +2,8 @@ import 'solana_chain_service.dart';
2
3 enum SolanaChainId {
4 mainnet,
5 - testnet,
6 - devnet,
5 + // testnet,
6 + // devnet,
7 }
8
9 extension SolanaChainIdX on SolanaChainId {
@@ -13,13 +13,16 @@ extension SolanaChainIdX on SolanaChainId {
13 switch (this) {
14 case SolanaChainId.mainnet:
15 name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
16 + // solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
17 break;
17 - case SolanaChainId.testnet:
18 - name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K';
19 - break;
20 - case SolanaChainId.devnet:
21 - name = '';
22 - break;
18 + // case SolanaChainId.devnet:
19 + // name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K';
20 + // // solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
21 + // break;
22 + // case SolanaChainId.testnet:
23 + // name = '';
24 + // // solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z
25 + // break;
26 }
27
28 return '${SolanaChainServiceImpl.namespace}:$name';
lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart
+8 -6
@@ -43,7 +43,7 @@ class SolanaChainServiceImpl implements ChainService {
43 SolanaClient(
44 rpcUrl: rpcUrl,
45 websocketUrl: Uri.parse(webSocketUrl),
46 - timeout: const Duration(minutes: 2),
46 + timeout: const Duration(minutes: 5),
47 ) {
48 for (final String event in getEvents()) {
49 wallet.registerEventEmitter(chainId: getChainId(), event: event);
@@ -72,7 +72,7 @@ class SolanaChainServiceImpl implements ChainService {
72
73 @override
74 List<String> getEvents() {
75 - return [''];
75 + return ['chainChanged', 'accountsChanged'];
76 }
77
78 Future<String?> requestAuthorization(String? text) async {
@@ -100,8 +100,7 @@ class SolanaChainServiceImpl implements ChainService {
100 Future<String> solanaSignTransaction(String topic, dynamic parameters) async {
101 log('received solana sign transaction request $parameters');
102
103 - final solanaSignTx =
104 - SolanaSignTransaction.fromJson(parameters as Map<String, dynamic>);
103 + final solanaSignTx = SolanaSignTransaction.fromJson(parameters as Map<String, dynamic>);
104
105 final String? authError = await requestAuthorization('Confirm request to sign transaction?');
106
@@ -122,10 +121,13 @@ class SolanaChainServiceImpl implements ChainService {
121 return '';
122 }
123
125 - String signature = sign.signatures.first.toBase58();
124 + String signature = await solanaClient.sendAndConfirmTransaction(
125 + message: message,
126 + signers: [ownerKeyPair!],
127 + commitment: Commitment.confirmed,
128 + );
129
130 print(signature);
128 - print(signature.runtimeType);
131
132 bottomSheetService.queueBottomSheet(
133 isModalDismissible: true,
lib/core/wallet_connect/web3wallet_service.dart
+18 -4
@@ -133,13 +133,27 @@ abstract class Web3WalletServiceBase with Store {
133 if (appStore.wallet!.type == WalletType.solana) {
134 for (final cId in SolanaChainId.values) {
135 final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
136 - final rpcUri = node.uri;
137 - final webSocketUri = 'wss://${node.uriRaw}/ws${node.uri.path}';
136 +
137 + Uri? rpcUri;
138 + String webSocketUrl;
139 + bool isModifiedNodeUri = false;
140 +
141 + if (node.uriRaw == 'rpc.ankr.com') {
142 + isModifiedNodeUri = true;
143 +
144 + //A better way to handle this instead of adding this to the general secrets?
145 + String ankrApiKey = secrets.ankrApiKey;
146 +
147 + rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
148 + webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
149 + } else {
150 + webSocketUrl = 'wss://${node.uriRaw}';
151 + }
152
153 SolanaChainServiceImpl(
154 reference: cId,
141 - rpcUrl: rpcUri,
142 - webSocketUrl: webSocketUri,
155 + rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri,
156 + webSocketUrl: webSocketUrl,
157 wcKeyService: walletKeyService,
158 bottomSheetService: _bottomSheetHandler,
159 wallet: _web3Wallet,
lib/reactions/wallet_connect.dart
+1
@@ -16,6 +16,7 @@ bool isWalletConnectCompatibleChain(WalletType walletType) {
16 switch (walletType) {
17 case WalletType.polygon:
18 case WalletType.ethereum:
19 + case WalletType.solana:
20 return true;
21 default:
22 return false;
tool/utils/secret_key.dart
+1
@@ -37,6 +37,7 @@ class SecretKey {
37 SecretKey('exchangeHelperApiKey', () => ''),
38 SecretKey('walletConnectProjectId', () => ''),
39 SecretKey('moralisApiKey', () => ''),
40 + SecretKey('ankrApiKey', () => ''),
41 ];
42
43 static final evmChainsSecrets = [