From f9679fecbeaacbbf3d4694a14a00cf47e5262448 Mon Sep 17 00:00:00 2001 From: Adegoke David <64401859+Blazebrain@users.noreply.github.com> Date: Tue, 9 Apr 2024 01:26:11 +0100 Subject: [PATCH] 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 * 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 Co-authored-by: Omar Hatem --- .github/workflows/pr_test_build.yml | 1 + .../chain_service/solana/solana_chain_id.dart | 19 +++++++++------- .../solana/solana_chain_service.dart | 14 +++++++----- .../wallet_connect/web3wallet_service.dart | 22 +++++++++++++++---- lib/reactions/wallet_connect.dart | 1 + tool/utils/secret_key.dart | 1 + 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index db9870412..dc231df42 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -139,6 +139,7 @@ jobs: echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart + echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart diff --git a/lib/core/wallet_connect/chain_service/solana/solana_chain_id.dart b/lib/core/wallet_connect/chain_service/solana/solana_chain_id.dart index bdc8a7d20..ed80a4f3f 100644 --- a/lib/core/wallet_connect/chain_service/solana/solana_chain_id.dart +++ b/lib/core/wallet_connect/chain_service/solana/solana_chain_id.dart @@ -2,8 +2,8 @@ import 'solana_chain_service.dart'; enum SolanaChainId { mainnet, - testnet, - devnet, + // testnet, + // devnet, } extension SolanaChainIdX on SolanaChainId { @@ -13,13 +13,16 @@ extension SolanaChainIdX on SolanaChainId { switch (this) { case SolanaChainId.mainnet: name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ'; + // solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp break; - case SolanaChainId.testnet: - name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K'; - break; - case SolanaChainId.devnet: - name = ''; - break; + // case SolanaChainId.devnet: + // name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K'; + // // solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 + // break; + // case SolanaChainId.testnet: + // name = ''; + // // solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z + // break; } return '${SolanaChainServiceImpl.namespace}:$name'; diff --git a/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart b/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart index f5c696be6..efbf9df74 100644 --- a/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart +++ b/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart @@ -43,7 +43,7 @@ class SolanaChainServiceImpl implements ChainService { SolanaClient( rpcUrl: rpcUrl, websocketUrl: Uri.parse(webSocketUrl), - timeout: const Duration(minutes: 2), + timeout: const Duration(minutes: 5), ) { for (final String event in getEvents()) { wallet.registerEventEmitter(chainId: getChainId(), event: event); @@ -72,7 +72,7 @@ class SolanaChainServiceImpl implements ChainService { @override List getEvents() { - return ['']; + return ['chainChanged', 'accountsChanged']; } Future requestAuthorization(String? text) async { @@ -100,8 +100,7 @@ class SolanaChainServiceImpl implements ChainService { Future solanaSignTransaction(String topic, dynamic parameters) async { log('received solana sign transaction request $parameters'); - final solanaSignTx = - SolanaSignTransaction.fromJson(parameters as Map); + final solanaSignTx = SolanaSignTransaction.fromJson(parameters as Map); final String? authError = await requestAuthorization('Confirm request to sign transaction?'); @@ -122,10 +121,13 @@ class SolanaChainServiceImpl implements ChainService { return ''; } - String signature = sign.signatures.first.toBase58(); + String signature = await solanaClient.sendAndConfirmTransaction( + message: message, + signers: [ownerKeyPair!], + commitment: Commitment.confirmed, + ); print(signature); - print(signature.runtimeType); bottomSheetService.queueBottomSheet( isModalDismissible: true, diff --git a/lib/core/wallet_connect/web3wallet_service.dart b/lib/core/wallet_connect/web3wallet_service.dart index 4c71abe48..66ccb2d76 100644 --- a/lib/core/wallet_connect/web3wallet_service.dart +++ b/lib/core/wallet_connect/web3wallet_service.dart @@ -133,13 +133,27 @@ abstract class Web3WalletServiceBase with Store { if (appStore.wallet!.type == WalletType.solana) { for (final cId in SolanaChainId.values) { final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type); - final rpcUri = node.uri; - final webSocketUri = 'wss://${node.uriRaw}/ws${node.uri.path}'; + + Uri? rpcUri; + String webSocketUrl; + bool isModifiedNodeUri = false; + + if (node.uriRaw == 'rpc.ankr.com') { + isModifiedNodeUri = true; + + //A better way to handle this instead of adding this to the general secrets? + String ankrApiKey = secrets.ankrApiKey; + + rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey'); + webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey'; + } else { + webSocketUrl = 'wss://${node.uriRaw}'; + } SolanaChainServiceImpl( reference: cId, - rpcUrl: rpcUri, - webSocketUrl: webSocketUri, + rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri, + webSocketUrl: webSocketUrl, wcKeyService: walletKeyService, bottomSheetService: _bottomSheetHandler, wallet: _web3Wallet, diff --git a/lib/reactions/wallet_connect.dart b/lib/reactions/wallet_connect.dart index f4487123e..ca908bc65 100644 --- a/lib/reactions/wallet_connect.dart +++ b/lib/reactions/wallet_connect.dart @@ -16,6 +16,7 @@ bool isWalletConnectCompatibleChain(WalletType walletType) { switch (walletType) { case WalletType.polygon: case WalletType.ethereum: + case WalletType.solana: return true; default: return false; diff --git a/tool/utils/secret_key.dart b/tool/utils/secret_key.dart index 8fedbb12a..5d5e61cec 100644 --- a/tool/utils/secret_key.dart +++ b/tool/utils/secret_key.dart @@ -37,6 +37,7 @@ class SecretKey { SecretKey('exchangeHelperApiKey', () => ''), SecretKey('walletConnectProjectId', () => ''), SecretKey('moralisApiKey', () => ''), + SecretKey('ankrApiKey', () => ''), ]; static final evmChainsSecrets = [