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
This commit is contained in:
shreerang6921 2024-03-06 11:08:02 +05:30 committed by GitHub
parent 150f10b91f
commit 276cb3695a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 80 additions and 137 deletions

49
App.tsx
View File

@ -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<StackParamsList>();
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<any>();
const [requestEventData, setRequestEventData] = useState<any>();
const [signModalVisible, setSignModalVisible] = useState(false);
useInitialization();
const [currentEthAddresses, setCurrentEthAddresses] = useState<string[]>([]);
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 => {
}}
/>
</Stack.Navigator>
<PairingModal
visible={modalVisible}
setModalVisible={setModalVisible}
currentProposal={currentProposal}
setCurrentProposal={setCurrentProposal}
/>
<SignModal
visible={signModalVisible}
setModalVisible={setSignModalVisible}
requestEvent={requestEventData}
requestSession={requestSession}
/>
<>
<PairingModal
visible={modalVisible}
setModalVisible={setModalVisible}
currentProposal={currentProposal}
setCurrentProposal={setCurrentProposal}
currentEthAddresses={currentEthAddresses}
/>
<SignModal
visible={signModalVisible}
setModalVisible={setSignModalVisible}
requestEvent={requestEventData}
requestSession={requestSession}
currentEthAddresses={currentEthAddresses}
/>
</>
</NavigationContainer>
);
};

View File

@ -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] = {

View File

@ -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,

View File

@ -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[];
}

View File

@ -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);
}

View File

@ -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<string, EIP155Lib>;
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,
};
}

View File

@ -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;
}
/**

View File

@ -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';