Hard-code the prefix of the hd paths and refactor functions

This commit is contained in:
IshaVenikar 2024-02-21 10:08:27 +05:30
parent 63edfdd990
commit 9a6e52de90
10 changed files with 494 additions and 418 deletions

View File

@ -6,7 +6,7 @@ import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { AccountsProps, StackParamsList, Account } from '../types';
import { addAccount } from '../utils';
import { addAccount } from '../utils/Accounts';
import styles from '../styles/stylesheet';
import HDPathDialog from './HDPathDialog';
@ -23,6 +23,7 @@ const Accounts: React.FC<AccountsProps> = ({
const [expanded, setExpanded] = useState(false);
const [isAccountCreating, setIsAccountCreating] = useState(false);
const [hdDialog, setHdDialog] = useState(false);
const [pathCode, setPathCode] = useState('');
const handlePress = () => setExpanded(!expanded);
@ -67,6 +68,7 @@ const Accounts: React.FC<AccountsProps> = ({
hideDialog={() => setHdDialog(false)}
updateAccounts={updateAccounts}
updateIndex={updateId}
pathCode={pathCode} // Pass pathCode here
/>
<List.Accordion
title={`Account ${currentIndex + 1}`}
@ -89,6 +91,16 @@ const Accounts: React.FC<AccountsProps> = ({
mode="contained"
onPress={() => {
setHdDialog(true);
switch (network) {
case 'eth':
setPathCode("m/44'/60'/");
break;
case 'cosmos':
setPathCode("m/44'/118'/");
break;
default:
setPathCode('');
}
}}>
Add Account from HD path
</Button>

View File

@ -1,15 +1,16 @@
import React, { useState } from 'react';
import { ScrollView, View } from 'react-native';
import { ScrollView, View, Text } from 'react-native';
import { Button, TextInput } from 'react-native-paper';
import { addAccountFromHDPath } from '../utils';
import { addAccountFromHDPath } from '../utils/Accounts';
import { Account } from '../types';
const HDPath = ({
pathCode,
updateAccounts,
updateIndex,
hideDialog,
}: {
pathCode: string;
updateIndex: (index: number) => void;
updateAccounts: (account: Account) => void;
hideDialog: () => void;
@ -19,7 +20,8 @@ const HDPath = ({
const createFromHDPathHandler = async () => {
setIsAccountCreating(true);
const newAccount = await addAccountFromHDPath(path);
const hdPath = pathCode + path;
const newAccount = await addAccountFromHDPath(hdPath);
setIsAccountCreating(false);
if (newAccount) {
@ -31,11 +33,17 @@ const HDPath = ({
return (
<ScrollView style={{ marginTop: 24, paddingHorizontal: 24 }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={{ color: 'black', fontSize: 18, padding: 10 }}>
{pathCode}
</Text>
<TextInput
mode="outlined"
onChangeText={text => setPath(text)}
value={path}
style={{ flex: 1 }}
/>
</View>
<View style={{ marginTop: 20, width: 200, alignSelf: 'center' }}>
<Button
mode="contained"

View File

@ -8,6 +8,7 @@ const HDPathDialog = ({
hideDialog,
updateIndex,
updateAccounts,
pathCode,
}: HDPathDialogProps) => {
return (
<Portal>
@ -15,6 +16,7 @@ const HDPathDialog = ({
<Dialog.Title>Add account from HD path</Dialog.Title>
<Dialog.Content>
<HDPath
pathCode={pathCode}
updateIndex={updateIndex}
updateAccounts={updateAccounts}
hideDialog={hideDialog}

View File

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Alert, View } from 'react-native';
import { Button } from 'react-native-paper';
import { createWallet, resetWallet } from '../utils';
import { createWallet, resetWallet } from '../utils/Accounts';
import { DialogComponent } from './Dialog';
import { NetworkDropdown } from './NetworkDropdown';
import { Account, AccountsState } from '../types';

View File

@ -5,8 +5,8 @@ import { Button, Text, TextInput } from 'react-native-paper';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { StackParamsList } from '../types';
import { signMessage } from '../utils';
import styles from '../styles/stylesheet';
import { signMessage } from '../utils/SignMessage';
type SignProps = NativeStackScreenProps<StackParamsList, 'SignMessage'>;

View File

@ -61,6 +61,7 @@ export type ResetDialogProps = {
};
export type HDPathDialogProps = {
pathCode: string;
visible: boolean;
hideDialog: () => void;
updateIndex: (index: number) => void;

406
utils.ts
View File

@ -1,406 +0,0 @@
/* Importing this library provides react native with a secure random source.
For more information, "visit https://docs.ethers.org/v5/cookbook/react-native/#cookbook-reactnative-security" */
import 'react-native-get-random-values';
import '@ethersproject/shims';
import { Wallet, utils } from 'ethers';
import { HDNode } from 'ethers/lib/utils';
import {
setInternetCredentials,
getInternetCredentials,
resetInternetCredentials,
} from 'react-native-keychain';
import { AccountData, Secp256k1HdWallet } from '@cosmjs/amino';
import { stringToPath } from '@cosmjs/crypto';
import { Account, SignMessageParams, WalletDetails } from './types';
const createWallet = async (): Promise<WalletDetails> => {
try {
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(16));
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
const hdNode = HDNode.fromMnemonic(mnemonic);
const ethNode = hdNode.derivePath("m/44'/60'/0'/0/0");
const cosmosNode = hdNode.derivePath("m/44'/118'/0'/0/0");
const ethAddress = ethNode.address;
const cosmosAddress = (await getCosmosAccounts(mnemonic, `0'/0/0`)).data
.address;
const ethAccountInfo = `${0},${ethNode.privateKey}`;
const cosmosAccountInfo = `${0},${cosmosNode.privateKey}`;
await setInternetCredentials(
'eth:keyServer:0',
'eth:pathKey:0',
ethAccountInfo,
);
await setInternetCredentials(
'cosmos:keyServer:0',
'cosmos:pathKey:0',
cosmosAccountInfo,
);
await setInternetCredentials('eth:accountIndices', 'ethCounter', '0');
await setInternetCredentials('cosmos:accountIndices', 'cosmosCounter', '0');
await setInternetCredentials('eth:globalCounter', 'ethGlobal', '0');
await setInternetCredentials('cosmos:globalCounter', 'cosmosGlobal', '0');
const ethAccounts = {
counterId: 0,
pubKey: ethNode.publicKey,
address: ethAddress,
hdPath: "m/44'/60'/0'/0/0",
};
const cosmosAccounts = {
counterId: 0,
pubKey: cosmosNode.publicKey,
address: cosmosAddress,
hdPath: "m/44'/118'/0'/0/0",
};
return { mnemonic, ethAccounts, cosmosAccounts };
} catch (error) {
console.error('Error creating HD wallet:', error);
return { mnemonic: '', ethAccounts: undefined, cosmosAccounts: undefined };
}
};
const addAccount = async (network: string): Promise<Account | undefined> => {
try {
const mnemonicStore = await getInternetCredentials('mnemonicServer');
if (!mnemonicStore) {
throw new Error('Mnemonic not found!');
}
const mnemonic = mnemonicStore.password;
const hdNode = HDNode.fromMnemonic(mnemonic);
const idStore = await getInternetCredentials(`${network}:accountIndices`);
if (!idStore) {
throw new Error('Account id not found');
}
const accountIds = idStore.password;
const ids = accountIds.split(',').map(Number);
const id = ids[ids.length - 1] + 1;
const hdPath =
network === 'eth' ? `m/44'/60'/0'/0/${id}` : `m/44'/118'/0'/0/${id}`;
const node = hdNode.derivePath(hdPath);
const privKey = node.privateKey;
const pubKey = node.publicKey;
let address: string;
switch (network) {
case 'eth':
address = node.address;
break;
case 'cosmos':
address = (await getCosmosAccounts(mnemonic, `0'/0/${id}`)).data
.address;
break;
default:
throw new Error('Invalid wallet type');
}
let indices = idStore.password;
indices += `,${id.toString()}`;
await resetInternetCredentials(`${network}:accountIndices`);
await setInternetCredentials(
`${network}:accountIndices`,
`${network}Counter`,
indices,
);
const counterStore = await getInternetCredentials(
`${network}:globalCounter`,
);
if (!counterStore) {
throw new Error('Error while fetching counter');
}
let accountCounter = counterStore.password;
const counterIds = accountCounter.split(',').map(Number);
const counterId = counterIds[counterIds.length - 1] + 1;
accountCounter += `,${counterId.toString()}`;
await resetInternetCredentials(`${network}:globalCounter`);
await setInternetCredentials(
`${network}:globalCounter`,
`${network}Global`,
accountCounter,
);
await setInternetCredentials(
`${network}:keyServer:${counterId}`,
`${network}:pathKey:${counterId}`,
`0'/0/${id},${privKey}`,
);
return { counterId, pubKey, address, hdPath };
} catch (error) {
console.error('Error creating account:', error);
}
};
const addAccountFromHDPath = async (
hdPath: string,
): Promise<
| { counterId: number; pubKey: string; address: string; hdPath: string }
| undefined
> => {
try {
const account = await accountInfoFromHDPath(hdPath);
if (!account) {
throw new Error('Error while creating account');
}
const { privKey, pubKey, address, network } = account;
const parts = hdPath.split('/');
const coinType = parts[2];
const path = parts.slice(-3).join('/');
const counterStore = await getInternetCredentials(
`${network}:globalCounter`,
);
if (!counterStore) {
throw new Error('Error while fetching counter');
}
let accountCounter = counterStore.password;
const counterIds = accountCounter.split(',').map(Number);
const counterId = counterIds[counterIds.length - 1] + 1;
accountCounter += `,${counterId.toString()}`;
await resetInternetCredentials(`${network}:globalCounter`);
await setInternetCredentials(
`${network}:globalCounter`,
`${network}Global`,
accountCounter,
);
const accountInfo = `${path},${privKey}`;
switch (coinType) {
case "60'":
await setInternetCredentials(
`eth:keyServer:${counterId}`,
`eth:pathKey:${counterId}`,
accountInfo,
);
break;
case "118'":
await setInternetCredentials(
`cosmos:keyServer${counterId}`,
`cosmos:pathKey:${counterId}`,
accountInfo,
);
break;
}
return { counterId, pubKey, address, hdPath };
} catch (error) {
console.error(error);
}
};
const accountInfoFromHDPath = async (
hdPath: string,
): Promise<
| { privKey: string; pubKey: string; address: string; network: string }
| undefined
> => {
const mnemonicStore = await getInternetCredentials('mnemonicServer');
if (!mnemonicStore) {
throw new Error('Mnemonic not found!');
}
const mnemonic = mnemonicStore.password;
const hdNode = HDNode.fromMnemonic(mnemonic);
const node = hdNode.derivePath(hdPath);
const privKey = node.privateKey;
const pubKey = node.publicKey;
const parts = hdPath.split('/');
const path = parts.slice(-3).join('/');
const coinType = parts[2];
let network: string;
let address: string;
switch (coinType) {
case "60'":
network = 'eth';
address = node.address;
break;
case "118'":
network = 'cosmos';
address = (await getCosmosAccounts(mnemonic, path)).data.address;
break;
default:
throw new Error('Invalid wallet type');
}
return { privKey, pubKey, address, network };
};
const signMessage = async ({
message,
network,
accountId,
}: SignMessageParams): Promise<string | undefined> => {
const pathKeyStore = await getInternetCredentials(
`${network}:keyServer:${accountId}`,
);
if (!pathKeyStore) {
throw new Error('Error while fetching counter');
}
const pathKeyVal = pathKeyStore.password;
const pathkey = pathKeyVal.split(',');
const hdPath = pathkey[0];
switch (network) {
case 'eth':
return await signEthMessage(message, accountId);
case 'cosmos':
return await signCosmosMessage(message, hdPath);
default:
throw new Error('Invalid wallet type');
}
};
const signEthMessage = async (
message: string,
accountId: number,
): Promise<string | undefined> => {
try {
const keyCred = await getInternetCredentials(`eth:keyServer:${accountId}`);
if (!keyCred) {
throw new Error('Failed to retrieve internet credentials');
}
const pathKey = keyCred.password;
const privKeyVal = pathKey.split(',');
const privKey = privKeyVal[privKeyVal.length - 1];
const wallet = new Wallet(privKey);
const signature = await wallet.signMessage(message);
return signature;
} catch (error) {
console.error('Error signing Ethereum message:', error);
return undefined;
}
};
const signCosmosMessage = async (
message: string,
hdPath: string,
): Promise<string | undefined> => {
try {
const mnemonicStore = await getInternetCredentials('mnemonicServer');
if (!mnemonicStore) {
throw new Error('Mnemonic not found');
}
const mnemonic = mnemonicStore.password;
const cosmosAccount = await getCosmosAccounts(mnemonic, hdPath);
const cosmosSignature = await cosmosAccount.cosmosWallet.signAmino(
cosmosAccount.data.address,
{
chain_id: '',
account_number: '0',
sequence: '0',
fee: {
gas: '0',
amount: [],
},
msgs: [
{
type: 'sign/MsgSignData',
value: {
signer: cosmosAccount.data.address,
data: btoa(message),
},
},
],
memo: '',
},
);
return cosmosSignature.signature.signature;
} catch (error) {
console.error('Error signing Cosmos message:', error);
return undefined;
}
};
const getCosmosAccounts = async (
mnemonic: string,
hdPath: string,
): Promise<{ cosmosWallet: Secp256k1HdWallet; data: AccountData }> => {
const cosmosWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
hdPaths: [stringToPath(`m/44'/118'/${hdPath}`)],
});
const accountsData = await cosmosWallet.getAccounts();
const data = accountsData[0];
return { cosmosWallet, data };
};
const resetKeyServers = async (prefix: string) => {
const idStore = await getInternetCredentials(`${prefix}:accountIndices`);
if (!idStore) {
throw new Error('Account id not found.');
}
const accountIds = idStore.password;
const ids = accountIds.split(',').map(Number);
const id = ids[ids.length - 1];
for (let i = 0; i <= id; i++) {
await resetInternetCredentials(`${prefix}:keyServer:${i}`);
}
};
const resetWallet = async () => {
try {
await resetInternetCredentials('mnemonicServer');
await resetKeyServers('eth');
await resetKeyServers('cosmos');
await resetInternetCredentials('eth:accountIndices');
await resetInternetCredentials('cosmos:accountIndices');
await resetInternetCredentials('eth:globalCounter');
await resetInternetCredentials('cosmos:globalCounter');
} catch (error) {
console.error('Error resetting wallet:', error);
throw error;
}
};
export {
createWallet,
addAccount,
signMessage,
resetWallet,
addAccountFromHDPath,
};

168
utils/Accounts.ts Normal file
View File

@ -0,0 +1,168 @@
/* Importing this library provides react native with a secure random source.
For more information, "visit https://docs.ethers.org/v5/cookbook/react-native/#cookbook-reactnative-security" */
import 'react-native-get-random-values';
import '@ethersproject/shims';
import { utils } from 'ethers';
import { HDNode } from 'ethers/lib/utils';
import {
setInternetCredentials,
resetInternetCredentials,
} from 'react-native-keychain';
import { Account, WalletDetails } from '../types';
import {
accountInfoFromHDPath,
getAddress,
getCosmosAccounts,
getHDPath,
getMnemonic,
getNextAccountId,
resetKeyServers,
updateAccountIndices,
updateGlobalCounter,
} from './utils';
const createWallet = async (): Promise<WalletDetails> => {
try {
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(16));
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
const hdNode = HDNode.fromMnemonic(mnemonic);
const ethNode = hdNode.derivePath("m/44'/60'/0'/0/0");
const cosmosNode = hdNode.derivePath("m/44'/118'/0'/0/0");
const ethAddress = ethNode.address;
const cosmosAddress = (await getCosmosAccounts(mnemonic, `0'/0/0`)).data
.address;
const ethAccountInfo = `${`0'/0/0`},${ethNode.privateKey}`;
const cosmosAccountInfo = `${`0'/0/0`},${cosmosNode.privateKey}`;
await Promise.all([
setInternetCredentials(
'eth:keyServer:0',
'eth:pathKey:0',
ethAccountInfo,
),
setInternetCredentials(
'cosmos:keyServer:0',
'cosmos:pathKey:0',
cosmosAccountInfo,
),
setInternetCredentials('eth:accountIndices', 'ethCounter', '0'),
setInternetCredentials('cosmos:accountIndices', 'cosmosCounter', '0'),
setInternetCredentials('eth:globalCounter', 'ethGlobal', '0'),
setInternetCredentials('cosmos:globalCounter', 'cosmosGlobal', '0'),
]);
const ethAccounts = {
counterId: 0,
pubKey: ethNode.publicKey,
address: ethAddress,
hdPath: "m/44'/60'/0'/0/0",
};
const cosmosAccounts = {
counterId: 0,
pubKey: cosmosNode.publicKey,
address: cosmosAddress,
hdPath: "m/44'/118'/0'/0/0",
};
return { mnemonic, ethAccounts, cosmosAccounts };
} catch (error) {
console.error('Error creating HD wallet:', error);
return { mnemonic: '', ethAccounts: undefined, cosmosAccounts: undefined };
}
};
const addAccount = async (network: string): Promise<Account | undefined> => {
try {
const mnemonic = await getMnemonic();
const hdNode = HDNode.fromMnemonic(mnemonic);
const id = await getNextAccountId(network);
const hdPath = getHDPath(network, id);
const node = hdNode.derivePath(hdPath);
const pubKey = node.publicKey;
const address = await getAddress(network, mnemonic, id);
await updateAccountIndices(network, id);
const { accountCounter, 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}`,
),
]);
return { counterId, pubKey, address, hdPath };
} catch (error) {
console.error('Error creating account:', error);
}
};
const addAccountFromHDPath = async (
hdPath: string,
): Promise<Account | undefined> => {
try {
const account = await accountInfoFromHDPath(hdPath);
if (!account) {
throw new Error('Error while creating account');
}
const parts = hdPath.split('/');
const path = parts.slice(-3).join('/');
const { privKey, pubKey, address, network } = account;
const { accountCounter, counterId } = await updateGlobalCounter(network);
const updatedAccountCounter = `${accountCounter},${counterId.toString()}`;
await Promise.all([
resetInternetCredentials(`${network}:globalCounter`),
setInternetCredentials(
`${network}:globalCounter`,
`${network}Global`,
updatedAccountCounter,
),
setInternetCredentials(
`${network}:keyServer:${counterId}`,
`${network}:pathKey:${counterId}`,
`${path},${privKey}`,
),
]);
return { counterId, pubKey, address, hdPath };
} catch (error) {
console.error(error);
}
};
const resetWallet = async () => {
try {
await Promise.all([
resetInternetCredentials('mnemonicServer'),
resetKeyServers('eth'),
resetKeyServers('cosmos'),
resetInternetCredentials('eth:accountIndices'),
resetInternetCredentials('cosmos:accountIndices'),
resetInternetCredentials('eth:globalCounter'),
resetInternetCredentials('cosmos:globalCounter'),
]);
} catch (error) {
console.error('Error resetting wallet:', error);
throw error;
}
};
export { createWallet, addAccount, addAccountFromHDPath, resetWallet };

80
utils/SignMessage.ts Normal file
View File

@ -0,0 +1,80 @@
import 'react-native-get-random-values';
import '@ethersproject/shims';
import { Wallet } from 'ethers';
import { SignMessageParams } from '../types';
import { getCosmosAccounts, getMnemonic, getPathKey } from './utils';
const signMessage = async ({
message,
network,
accountId,
}: SignMessageParams): Promise<string | undefined> => {
const hdPath = (await getPathKey(network, accountId)).hdPath;
switch (network) {
case 'eth':
return await signEthMessage(message, accountId);
case 'cosmos':
return await signCosmosMessage(message, hdPath);
default:
throw new Error('Invalid wallet type');
}
};
const signEthMessage = async (
message: string,
accountId: number,
): Promise<string | undefined> => {
try {
const privKey = (await getPathKey('eth', accountId)).privKey;
const wallet = new Wallet(privKey);
const signature = await wallet.signMessage(message);
return signature;
} catch (error) {
console.error('Error signing Ethereum message:', error);
return undefined;
}
};
const signCosmosMessage = async (
message: string,
hdPath: string,
): Promise<string | undefined> => {
try {
const mnemonic = await getMnemonic();
const cosmosAccount = await getCosmosAccounts(mnemonic, hdPath);
const address = cosmosAccount.data.address;
const cosmosSignature = await cosmosAccount.cosmosWallet.signAmino(
address,
{
chain_id: '',
account_number: '0',
sequence: '0',
fee: {
gas: '0',
amount: [],
},
msgs: [
{
type: 'sign/MsgSignData',
value: {
signer: address,
data: btoa(message),
},
},
],
memo: '',
},
);
return cosmosSignature.signature.signature;
} catch (error) {
console.error('Error signing Cosmos message:', error);
return undefined;
}
};
export { signMessage, signEthMessage, signCosmosMessage };

211
utils/utils.ts Normal file
View File

@ -0,0 +1,211 @@
import 'react-native-get-random-values';
import '@ethersproject/shims';
import { HDNode } from 'ethers/lib/utils';
import {
getInternetCredentials,
resetInternetCredentials,
setInternetCredentials,
} from 'react-native-keychain';
import { AccountData, Secp256k1HdWallet } from '@cosmjs/amino';
import { stringToPath } from '@cosmjs/crypto';
const getMnemonic = async (): Promise<string> => {
const mnemonicStore = await getInternetCredentials('mnemonicServer');
if (!mnemonicStore) {
throw new Error('Mnemonic not found!');
}
const mnemonic = mnemonicStore.password;
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 getAddress = async (
network: string,
mnemonic: string,
id: number,
): Promise<string> => {
switch (network) {
case 'eth':
return HDNode.fromMnemonic(mnemonic).derivePath(`m/44'/60'/0'/0/${id}`)
.address;
case 'cosmos':
return (await getCosmosAccounts(mnemonic, `0'/0/${id}`)).data.address;
default:
throw new Error('Invalid wallet type');
}
};
const getCosmosAccounts = async (
mnemonic: string,
hdPath: string,
): Promise<{ cosmosWallet: Secp256k1HdWallet; data: AccountData }> => {
const cosmosWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, {
hdPaths: [stringToPath(`m/44'/118'/${hdPath}`)],
});
const accountsData = await cosmosWallet.getAccounts();
const data = accountsData[0];
return { cosmosWallet, data };
};
const accountInfoFromHDPath = async (
hdPath: string,
): Promise<
| { privKey: string; pubKey: string; address: string; network: string }
| undefined
> => {
const mnemonicStore = await getInternetCredentials('mnemonicServer');
if (!mnemonicStore) {
throw new Error('Mnemonic not found!');
}
const mnemonic = mnemonicStore.password;
const hdNode = HDNode.fromMnemonic(mnemonic);
const node = hdNode.derivePath(hdPath);
const privKey = node.privateKey;
const pubKey = node.publicKey;
const parts = hdPath.split('/');
const path = parts.slice(-3).join('/');
const coinType = parts[2];
let network: string;
let address: string;
switch (coinType) {
case "60'":
network = 'eth';
address = node.address;
break;
case "118'":
network = 'cosmos';
address = (await getCosmosAccounts(mnemonic, path)).data.address;
break;
default:
throw new Error('Invalid wallet type');
}
return { privKey, pubKey, address, network };
};
const getPathKey = async (
network: string,
accountId: number,
): Promise<{ hdPath: string; privKey: string }> => {
const pathKeyStore = await getInternetCredentials(
`${network}:keyServer:${accountId}`,
);
if (!pathKeyStore) {
throw new Error('Error while fetching counter');
}
const pathKeyVal = pathKeyStore.password;
const pathkey = pathKeyVal.split(',');
const hdPath = pathkey[0];
const privKey = pathkey[1];
return { hdPath, privKey };
};
const getGlobalCounter = async (
network: string,
): Promise<{
accountCounter: string;
counterIds: number[];
counterId: number;
}> => {
const counterStore = await getInternetCredentials(`${network}:globalCounter`);
if (!counterStore) {
throw new Error('Error while fetching counter');
}
let accountCounter = counterStore.password;
const counterIds = accountCounter.split(',').map(Number);
const counterId = counterIds[counterIds.length - 1] + 1;
return { accountCounter, counterIds, counterId };
};
const updateGlobalCounter = async (
network: string,
): Promise<{ accountCounter: string; counterId: number }> => {
const globalCounterData = await getGlobalCounter(network);
const accountCounter = globalCounterData.accountCounter;
const counterId = globalCounterData.counterId;
const updatedAccountCounter = `${accountCounter},${counterId.toString()}`;
await resetInternetCredentials(`${network}:globalCounter`);
await setInternetCredentials(
`${network}:globalCounter`,
`${network}Global`,
updatedAccountCounter,
);
return { accountCounter: updatedAccountCounter, counterId };
};
const getNextAccountId = async (network: string): Promise<number> => {
const idStore = await getInternetCredentials(`${network}:accountIndices`);
if (!idStore) {
throw new Error('Account id not found');
}
const accountIds = idStore.password;
const ids = accountIds.split(',').map(Number);
return ids[ids.length - 1] + 1;
};
const updateAccountIndices = async (
network: string,
id: number,
): Promise<void> => {
const idStore = await getInternetCredentials(`${network}:accountIndices`);
if (!idStore) {
throw new Error('Account id not found');
}
const updatedIndices = `${idStore.password},${id.toString()}`;
await resetInternetCredentials(`${network}:accountIndices`);
await setInternetCredentials(
`${network}:accountIndices`,
`${network}Counter`,
updatedIndices,
);
};
const resetKeyServers = async (prefix: string) => {
const idStore = await getInternetCredentials(`${prefix}:accountIndices`);
if (!idStore) {
throw new Error('Account id not found.');
}
const accountIds = idStore.password;
const ids = accountIds.split(',').map(Number);
const id = ids[ids.length - 1];
for (let i = 0; i <= id; i++) {
await resetInternetCredentials(`${prefix}:keyServer:${i}`);
}
};
export {
accountInfoFromHDPath,
getCosmosAccounts,
getMnemonic,
getPathKey,
getNextAccountId,
updateGlobalCounter,
updateAccountIndices,
getHDPath,
getAddress,
resetKeyServers,
};