From 276cb3695a6a5f8124d97c8f730037fe8ae094f9 Mon Sep 17 00:00:00 2001 From: shreerang6921 <68148922+shreerang6921@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:08:02 +0530 Subject: [PATCH] Use existing ethereum accounts while connecting wallet with dapp (#39) * Use existing accounts while pairing with dapp * Listen for events emitted from dapp on every render * Handle review changes --- App.tsx | 49 +++++++++++----- components/PairingModal.tsx | 8 +-- components/SignModal.tsx | 6 +- types.ts | 2 + utils/wallet-connect/EIP155Requests.ts | 57 ++++-------------- utils/wallet-connect/EIP155Wallet.ts | 64 --------------------- utils/wallet-connect/Helpers.ts | 18 +++++- utils/wallet-connect/WalletConnectUtils.tsx | 13 +++-- 8 files changed, 80 insertions(+), 137 deletions(-) delete mode 100644 utils/wallet-connect/EIP155Wallet.ts diff --git a/App.tsx b/App.tsx index f9cc566..4e2147c 100644 --- a/App.tsx +++ b/App.tsx @@ -12,16 +12,18 @@ import QRScanner from './components/QRScanner'; import PairingModal from './components/PairingModal'; import SignModal from './components/SignModal'; import WalletConnect from './components/WalletConnect'; - import { StackParamsList } from './types'; import useInitialization, { web3wallet, } from './utils/wallet-connect/WalletConnectUtils'; import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Lib'; +import { retrieveAccounts } from './utils/accounts'; const Stack = createNativeStackNavigator(); const App = (): React.JSX.Element => { + useInitialization(); + const [modalVisible, setModalVisible] = useState(false); //TODO: Remove any const [currentProposal, setCurrentProposal] = useState< @@ -30,8 +32,7 @@ const App = (): React.JSX.Element => { const [requestSession, setRequestSession] = useState(); const [requestEventData, setRequestEventData] = useState(); const [signModalVisible, setSignModalVisible] = useState(false); - - useInitialization(); + const [currentEthAddresses, setCurrentEthAddresses] = useState([]); const onSessionProposal = useCallback( (proposal: SignClientTypes.EventArguments['session_proposal']) => { @@ -65,6 +66,20 @@ const App = (): React.JSX.Element => { //TODO: Investigate dependancies }); + useEffect(() => { + const fetchEthAccounts = async () => { + const { ethLoadedAccounts } = await retrieveAccounts(); + + if (ethLoadedAccounts) { + const ethAddreses = ethLoadedAccounts.map(account => account.address); + setCurrentEthAddresses(ethAddreses); + } + }; + + fetchEthAccounts(); + // TODO: Use context to maintain accounts state + }, [modalVisible]); + const linking = { prefixes: ['https://www.laconic-wallet.com'], config: { @@ -125,19 +140,23 @@ const App = (): React.JSX.Element => { }} /> - - + <> + + + ); }; diff --git a/components/PairingModal.tsx b/components/PairingModal.tsx index 0a89247..5d575a7 100644 --- a/components/PairingModal.tsx +++ b/components/PairingModal.tsx @@ -4,16 +4,14 @@ import { Button, Text } from 'react-native-paper'; import { PairingModalProps } from '../types'; import styles from '../styles/stylesheet'; -import { - currentETHAddress, - web3wallet, -} from '../utils/wallet-connect/WalletConnectUtils'; +import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils'; import { SessionTypes } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; const PairingModal = ({ visible, + currentEthAddresses, currentProposal, setCurrentProposal, setModalVisible, @@ -32,7 +30,7 @@ const PairingModal = ({ Object.keys(requiredNamespaces).forEach(key => { const accounts: string[] = []; requiredNamespaces[key].chains!.map((chain: any) => { - [currentETHAddress].map(acc => accounts.push(`${chain}:${acc}`)); + currentEthAddresses.map(acc => accounts.push(`${chain}:${acc}`)); }); namespaces[key] = { diff --git a/components/SignModal.tsx b/components/SignModal.tsx index 6b96cc2..1c6eab9 100644 --- a/components/SignModal.tsx +++ b/components/SignModal.tsx @@ -17,6 +17,7 @@ const SignModal = ({ setModalVisible, requestEvent, requestSession, + currentEthAddresses, }: SignModalProps) => { if (!requestEvent || !requestSession) { return null; @@ -33,7 +34,10 @@ const SignModal = ({ const onApprove = async () => { if (requestEvent) { - const response = await approveEIP155Request(requestEvent); + const response = await approveEIP155Request( + requestEvent, + currentEthAddresses, + ); await web3wallet.respondSessionRequest({ topic, response, diff --git a/types.ts b/types.ts index 4134eee..38dcc0c 100644 --- a/types.ts +++ b/types.ts @@ -90,6 +90,7 @@ export type PathState = { export interface PairingModalProps { visible: boolean; setModalVisible: (arg1: boolean) => void; + currentEthAddresses: string[]; currentProposal: | SignClientTypes.EventArguments['session_proposal'] | undefined; @@ -103,4 +104,5 @@ export interface SignModalProps { setModalVisible: (arg1: boolean) => void; requestSession: any; requestEvent: SignClientTypes.EventArguments['session_request'] | undefined; + currentEthAddresses: string[]; } diff --git a/utils/wallet-connect/EIP155Requests.ts b/utils/wallet-connect/EIP155Requests.ts index 3c033c5..e46df18 100644 --- a/utils/wallet-connect/EIP155Requests.ts +++ b/utils/wallet-connect/EIP155Requests.ts @@ -1,63 +1,30 @@ // Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a -import { - EIP155_CHAINS, - EIP155_SIGNING_METHODS, - TEIP155Chain, -} from './EIP155Lib'; -import { eip155Wallets } from './EIP155Wallet'; -import { - getSignParamsMessage, - getSignTypedDataParamsData, - getWalletAddressFromParams, -} from './Helpers'; + import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'; import { SignClientTypes } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; -import { providers } from 'ethers'; -import { currentETHAddress } from './WalletConnectUtils'; + +import { EIP155_SIGNING_METHODS } from './EIP155Lib'; +import { getSignParamsMessage, getAccountNumberFromParams } from './Helpers'; +import { signEthMessage } from '../sign-message'; export async function approveEIP155Request( requestEvent: SignClientTypes.EventArguments['session_request'], + currentEthAddresses: string[], ) { const { params, id } = requestEvent; - const { chainId, request } = params; - const wallet = - eip155Wallets[getWalletAddressFromParams([currentETHAddress], params)]; + const { request } = params; + const counterId = await getAccountNumberFromParams( + currentEthAddresses, + params, + ); switch (request.method) { case EIP155_SIGNING_METHODS.PERSONAL_SIGN: - case EIP155_SIGNING_METHODS.ETH_SIGN: const message = getSignParamsMessage(request.params); - const signedMessage = await wallet.signMessage(message); + const signedMessage = await signEthMessage(message, counterId); return formatJsonRpcResult(id, signedMessage); - case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA: - case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3: - case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4: - const { - domain, - types, - message: data, - } = getSignTypedDataParamsData(request.params); - // https://github.com/ethers-io/ethers.js/issues/687#issuecomment-714069471 - delete types.EIP712Domain; - const signedData = await wallet._signTypedData(domain, types, data); - return formatJsonRpcResult(id, signedData); - - case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION: - const provider = new providers.JsonRpcProvider( - EIP155_CHAINS[chainId as TEIP155Chain].rpc, - ); - const sendTransaction = request.params[0]; - const connectedWallet = wallet.connect(provider); - const { hash } = await connectedWallet.sendTransaction(sendTransaction); - return formatJsonRpcResult(id, hash); - - case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION: - const signTransaction = request.params[0]; - const signature = await wallet.signTransaction(signTransaction); - return formatJsonRpcResult(id, signature); - default: throw new Error(getSdkError('INVALID_METHOD').message); } diff --git a/utils/wallet-connect/EIP155Wallet.ts b/utils/wallet-connect/EIP155Wallet.ts deleted file mode 100644 index 9f4c187..0000000 --- a/utils/wallet-connect/EIP155Wallet.ts +++ /dev/null @@ -1,64 +0,0 @@ -// https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a -// TODO: check and remove if not used - -import AsyncStorage from '@react-native-async-storage/async-storage'; -import EIP155Lib from './EIP155Lib'; - -export let wallet1: EIP155Lib; -export let wallet2: EIP155Lib; -export let eip155Wallets: Record; -export let eip155Addresses: string[]; - -export let address1: string; -let address2: string; - -/** - * Utilities - */ -export const setLocalStorage = async (mnemonic: any) => { - try { - const value = await AsyncStorage.setItem('EIP155_MNEMONIC_1', mnemonic); - if (value !== null) { - return value; - } - } catch (e) { - console.log('setLocalStorage Error:', e); - } -}; - -export const getLocalStorage = async () => { - try { - const value = await AsyncStorage.getItem('EIP155_MNEMONIC_1'); - if (value !== null) { - return value; - } - } catch (e) { - console.log('getLocalStorage Error:', e); - } -}; - -// Function to create or restore a wallet -export async function createOrRestoreEIP155Wallet() { - let mnemonic1 = await getLocalStorage(); - - if (mnemonic1) { - wallet1 = EIP155Lib.init({ mnemonic: mnemonic1 }); - } else { - wallet1 = EIP155Lib.init({}); - } - - // @notice / Warning!!! : This is a test wallet, do not use it for real transactions - setLocalStorage(wallet1?.getMnemonic()); - address1 = wallet1.getAddress(); - - eip155Wallets = { - [address1]: wallet1, - [address2]: wallet2, - }; - eip155Addresses = Object.keys(eip155Wallets); - - return { - eip155Wallets, - eip155Addresses, - }; -} diff --git a/utils/wallet-connect/Helpers.ts b/utils/wallet-connect/Helpers.ts index e8ace04..fb082b7 100644 --- a/utils/wallet-connect/Helpers.ts +++ b/utils/wallet-connect/Helpers.ts @@ -1,5 +1,6 @@ // Taken from https://medium.com/walletconnect/how-to-build-a-wallet-in-react-native-with-the-web3wallet-sdk-b6f57bf02f9a +import { retrieveAccounts } from '../accounts'; import { EIP155_CHAINS, TEIP155Chain } from './EIP155Lib'; import { utils } from 'ethers'; @@ -64,7 +65,10 @@ export function getSignTypedDataParamsData(params: string[]) { * Get our address from params checking if params string contains one * of our wallet addresses */ -export function getWalletAddressFromParams(addresses: string[], params: any) { +export async function getAccountNumberFromParams( + addresses: string[], + params: any, +) { const paramsString = JSON.stringify(params); let address = ''; @@ -74,7 +78,17 @@ export function getWalletAddressFromParams(addresses: string[], params: any) { } }); - return address; + const { ethLoadedAccounts } = await retrieveAccounts(); + + const currentAccount = ethLoadedAccounts!.find( + account => account.address === address, + ); + + if (!currentAccount) { + throw new Error('Account with given adress not found'); + } + + return currentAccount.counterId; } /** diff --git a/utils/wallet-connect/WalletConnectUtils.tsx b/utils/wallet-connect/WalletConnectUtils.tsx index 03c4839..800fead 100644 --- a/utils/wallet-connect/WalletConnectUtils.tsx +++ b/utils/wallet-connect/WalletConnectUtils.tsx @@ -7,14 +7,17 @@ import { Web3Wallet, IWeb3Wallet } from '@walletconnect/web3wallet'; export let web3wallet: IWeb3Wallet; export let core: ICore; -export let currentETHAddress: string; +export let currentETHAddresses: string[]; +export let currentCosmosAddresses: string[]; import { useState, useCallback, useEffect } from 'react'; -import { createOrRestoreEIP155Wallet } from './EIP155Wallet'; +import { retrieveAccounts } from '../accounts'; -async function createWeb3Wallet() { - const { eip155Addresses } = await createOrRestoreEIP155Wallet(); - currentETHAddress = eip155Addresses[0]; +export async function createWeb3Wallet() { + const { ethLoadedAccounts } = await retrieveAccounts(); + currentETHAddresses = ethLoadedAccounts + ? ethLoadedAccounts.map(ethAccount => ethAccount.address) + : []; // TODO: Move to dotenv const ENV_PROJECT_ID = 'c97365bf9f06d12a7488de36240b0ff4';