Retrieve accounts on reload (#29)

* Display HD path on sign message page

* Create component for displaying account details

* Add retrieve accounts function

* Load accounts after closing app

* Fix the retrieve accounts function

* Use hdpath instead of id

* Check if keystore is empty while retrieving accounts

* Add spinner when accounts are being fetched

* Display complete hd paths after reloading the app

* Remove any return type

* Store public key and address

* Modify sign message function to use path

* Fix the add accounts functionality
This commit is contained in:
IshaVenikar
2024-02-22 11:32:25 +05:30
committed by GitHub
parent 01373697f4
commit 783758be39
11 changed files with 235 additions and 139 deletions
+65 -23
View File
@@ -8,6 +8,7 @@ import { HDNode } from 'ethers/lib/utils';
import {
setInternetCredentials,
resetInternetCredentials,
getInternetCredentials,
} from 'react-native-keychain';
import { Account, WalletDetails } from '../types';
@@ -18,6 +19,7 @@ import {
getHDPath,
getMnemonic,
getNextAccountId,
getPathKey,
resetKeyServers,
updateAccountIndices,
updateGlobalCounter,
@@ -33,11 +35,13 @@ const createWallet = async (): Promise<WalletDetails> => {
const cosmosNode = hdNode.derivePath("m/44'/118'/0'/0/0");
const ethAddress = ethNode.address;
const cosmosAddress = (await getCosmosAccounts(mnemonic, `0'/0/0`)).data
const cosmosAddress = (await getCosmosAccounts(mnemonic, "0'/0/0")).data
.address;
const ethAccountInfo = `${`0'/0/0`},${ethNode.privateKey}`;
const cosmosAccountInfo = `${`0'/0/0`},${cosmosNode.privateKey}`;
const ethAccountInfo = `${"0'/0/0"},${ethNode.privateKey},${ethNode.publicKey
},${ethAddress}`;
const cosmosAccountInfo = `${"0'/0/0"},${cosmosNode.privateKey},${cosmosNode.publicKey
},${cosmosAddress}`;
await Promise.all([
setInternetCredentials(
@@ -82,26 +86,20 @@ const addAccount = async (network: string): Promise<Account | undefined> => {
const mnemonic = await getMnemonic();
const hdNode = HDNode.fromMnemonic(mnemonic);
const id = await getNextAccountId(network);
const hdPath = getHDPath(network, id);
const hdPath = getHDPath(network, `0'/0/${id}`);
const node = hdNode.derivePath(hdPath);
const pubKey = node.publicKey;
const address = await getAddress(network, mnemonic, id);
const address = await getAddress(network, mnemonic, `0'/0/${id}`);
await updateAccountIndices(network, id);
const { accountCounter, counterId } = await updateGlobalCounter(network);
const { counterId } = await updateGlobalCounter(network);
await Promise.all([
resetInternetCredentials(`${network}:globalCounter`),
setInternetCredentials(
`${network}:globalCounter`,
`${network}Global`,
accountCounter,
),
setInternetCredentials(
`${network}:keyServer:${counterId}`,
`${network}:pathKey:${counterId}`,
`0'/0/${id},${node.privateKey}`,
`0'/0/${id},${node.privateKey},${node.publicKey},${address}`,
),
]);
@@ -125,20 +123,13 @@ const addAccountFromHDPath = async (
const { privKey, pubKey, address, network } = account;
const { accountCounter, counterId } = await updateGlobalCounter(network);
const updatedAccountCounter = `${accountCounter},${counterId.toString()}`;
const counterId = (await updateGlobalCounter(network)).counterId;
await Promise.all([
resetInternetCredentials(`${network}:globalCounter`),
setInternetCredentials(
`${network}:globalCounter`,
`${network}Global`,
updatedAccountCounter,
),
setInternetCredentials(
`${network}:keyServer:${counterId}`,
`${network}:pathKey:${counterId}`,
`${path},${privKey}`,
`${path},${privKey},${pubKey},${address}`,
),
]);
@@ -148,6 +139,51 @@ const addAccountFromHDPath = async (
}
};
const retrieveAccountsForNetwork = async (
network: string,
count: string,
): Promise<Account[]> => {
const elementsArray = count.split(',');
const loadedAccounts = await Promise.all(
elementsArray.map(async i => {
const pubKey = (await getPathKey(network, Number(i))).pubKey;
const address = (await getPathKey(network, Number(i))).address;
const path = (await getPathKey(network, Number(i))).path;
const hdPath = getHDPath(network, path);
const account: Account = {
counterId: Number(i),
pubKey: pubKey,
address: address,
hdPath: hdPath,
};
return account;
}),
);
return loadedAccounts;
};
const retrieveAccounts = async (): Promise<{
ethLoadedAccounts?: Account[];
cosmosLoadedAccounts?: Account[];
}> => {
const ethServer = await getInternetCredentials('eth:globalCounter');
const ethCounter = ethServer && ethServer.password;
const cosmosServer = await getInternetCredentials('cosmos:globalCounter');
const cosmosCounter = cosmosServer && cosmosServer.password;
const ethLoadedAccounts = ethCounter
? await retrieveAccountsForNetwork('eth', ethCounter)
: undefined;
const cosmosLoadedAccounts = cosmosCounter
? await retrieveAccountsForNetwork('cosmos', cosmosCounter)
: undefined;
return { ethLoadedAccounts, cosmosLoadedAccounts };
};
const resetWallet = async () => {
try {
await Promise.all([
@@ -165,4 +201,10 @@ const resetWallet = async () => {
}
};
export { createWallet, addAccount, addAccountFromHDPath, resetWallet };
export {
createWallet,
addAccount,
addAccountFromHDPath,
retrieveAccounts,
resetWallet,
};
@@ -13,13 +13,13 @@ const signMessage = async ({
network,
accountId,
}: SignMessageParams): Promise<string | undefined> => {
const hdPath = (await getPathKey(network, accountId)).hdPath;
const path = (await getPathKey(network, accountId)).path;
switch (network) {
case 'eth':
return await signEthMessage(message, accountId);
case 'cosmos':
return await signCosmosMessage(message, hdPath);
return await signCosmosMessage(message, path);
default:
throw new Error('Invalid wallet type');
}
@@ -43,11 +43,11 @@ const signEthMessage = async (
const signCosmosMessage = async (
message: string,
hdPath: string,
path: string,
): Promise<string | undefined> => {
try {
const mnemonic = await getMnemonic();
const cosmosAccount = await getCosmosAccounts(mnemonic, hdPath);
const cosmosAccount = await getCosmosAccounts(mnemonic, path);
const address = cosmosAccount.data.address;
const cosmosSignature = await cosmosAccount.cosmosWallet.signAmino(
address,
+17 -10
View File
@@ -23,21 +23,21 @@ const getMnemonic = async (): Promise<string> => {
return mnemonic;
};
const getHDPath = (network: string, id: number): string => {
return network === 'eth' ? `m/44'/60'/0'/0/${id}` : `m/44'/118'/0'/0/${id}`;
const getHDPath = (network: string, path: string): string => {
return network === 'eth' ? `m/44'/60'/${path}` : `m/44'/118'/${path}`;
};
const getAddress = async (
network: string,
mnemonic: string,
id: number,
path: string,
): Promise<string> => {
switch (network) {
case 'eth':
return HDNode.fromMnemonic(mnemonic).derivePath(`m/44'/60'/0'/0/${id}`)
return HDNode.fromMnemonic(mnemonic).derivePath(`m/44'/60'/${path}`)
.address;
case 'cosmos':
return (await getCosmosAccounts(mnemonic, `0'/0/${id}`)).data.address;
return (await getCosmosAccounts(mnemonic, `${path}`)).data.address;
default:
throw new Error('Invalid wallet type');
}
@@ -45,10 +45,10 @@ const getAddress = async (
const getCosmosAccounts = async (
mnemonic: string,
hdPath: string,
path: string,
): Promise<{ cosmosWallet: Secp256k1HdWallet; data: AccountData }> => {
const cosmosWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
hdPaths: [stringToPath(`m/44'/118'/${hdPath}`)],
hdPaths: [stringToPath(`m/44'/118'/${path}`)],
});
const accountsData = await cosmosWallet.getAccounts();
@@ -100,7 +100,12 @@ const accountInfoFromHDPath = async (
const getPathKey = async (
network: string,
accountId: number,
): Promise<{ hdPath: string; privKey: string }> => {
): Promise<{
path: string;
privKey: string;
pubKey: string;
address: string;
}> => {
const pathKeyStore = await getInternetCredentials(
`${network}:keyServer:${accountId}`,
);
@@ -111,10 +116,12 @@ const getPathKey = async (
const pathKeyVal = pathKeyStore.password;
const pathkey = pathKeyVal.split(',');
const hdPath = pathkey[0];
const path = pathkey[0];
const privKey = pathkey[1];
const pubKey = pathkey[2];
const address = pathkey[3];
return { hdPath, privKey };
return { path, privKey, pubKey, address };
};
const getGlobalCounter = async (