forked from cerc-io/laconic-wallet
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:
parent
150f10b91f
commit
276cb3695a
49
App.tsx
49
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<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>
|
||||
);
|
||||
};
|
||||
|
@ -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] = {
|
||||
|
@ -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,
|
||||
|
2
types.ts
2
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[];
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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';
|
||||
|
Loading…
Reference in New Issue
Block a user