From 894829dd9d9650822f2feb91e698aea3c2e09828 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Thu, 15 Feb 2024 10:55:41 +0530 Subject: [PATCH 01/17] Create addAccount function --- components/Section.tsx | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 components/Section.tsx diff --git a/components/Section.tsx b/components/Section.tsx new file mode 100644 index 0000000..f1ab8fe --- /dev/null +++ b/components/Section.tsx @@ -0,0 +1,29 @@ +import { PropsWithChildren } from 'react'; +import { Text, View, useColorScheme } from 'react-native'; +import { Colors } from 'react-native/Libraries/NewAppScreen'; + +import styles from '../styles/stylesheet'; + +type SectionProps = PropsWithChildren<{ + title: string; +}>; + +const Section = ({ title }: SectionProps): React.JSX.Element => { + const isDarkMode = useColorScheme() === 'dark'; + return ( + + + {title} + + + + ); +}; + +export { Section }; From 5df584b75024ae95dbd8406cb0761890e14ce97b Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Thu, 15 Feb 2024 13:49:43 +0530 Subject: [PATCH 02/17] Create addAccount function --- utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils.ts b/utils.ts index e8563a6..82ef69a 100644 --- a/utils.ts +++ b/utils.ts @@ -122,7 +122,7 @@ const addAccount = async (network: string): Promise => { indices, ); - return { pubKey, address, id }; + return { id, pubKey, address }; } catch (error) { console.error('Error creating account:', error); } From ad42b74841ebebec13941c9799018f6305cae981 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Thu, 15 Feb 2024 17:50:22 +0530 Subject: [PATCH 03/17] Integrate functions --- components/Accounts.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/components/Accounts.tsx b/components/Accounts.tsx index d5cb2e8..31b7339 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -21,19 +21,14 @@ const Accounts: React.FC = ({ const [expanded, setExpanded] = useState(false); const [isAccountCreating, setIsAccountCreating] = useState(false); - const handlePress = () => setExpanded(!expanded); const addAccountHandler = async () => { setIsAccountCreating(true); const newAccount = await addAccount(network); setIsAccountCreating(false); - setExpanded(false); - - if (newAccount) { - updateAccounts(newAccount); - updateIndex(selectedAccounts[selectedAccounts.length - 1].id + 1); - } + newAccount && updateAccounts(newAccount); + updateIndex(selectedAccounts[selectedAccounts.length - 1].id + 1); }; const selectedAccounts: Account[] = (() => { From 1bde70b7d62809fb5d796d4d66d79a6ad9581c8f Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Fri, 16 Feb 2024 09:40:33 +0530 Subject: [PATCH 04/17] HDPath display --- utils.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utils.ts b/utils.ts index 82ef69a..b9a9f7c 100644 --- a/utils.ts +++ b/utils.ts @@ -22,8 +22,12 @@ const createWallet = async (): Promise => { 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 ethDerivationPath = "m/44'/60'/0'/0/0"; + const cosmosDerivationPath = "m/44'/118'/0'/0/0"; + + const ethNode = hdNode.derivePath(ethDerivationPath); + const cosmosNode = hdNode.derivePath(cosmosDerivationPath); const ethAddress = ethNode.address; const cosmosAddress = (await getCosmosAccounts(mnemonic, 0)).data.address; From dbaf43f98cb2e1f3e704c96e4c3539fbf0b87fe1 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Fri, 16 Feb 2024 11:06:42 +0530 Subject: [PATCH 05/17] Display hdpaths for newly created accounts --- components/Accounts.tsx | 12 ++++++++++-- components/HomeScreen.tsx | 1 - types.ts | 1 + utils.ts | 16 +++++++--------- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/components/Accounts.tsx b/components/Accounts.tsx index 31b7339..3d787dd 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -27,8 +27,10 @@ const Accounts: React.FC = ({ setIsAccountCreating(true); const newAccount = await addAccount(network); setIsAccountCreating(false); - newAccount && updateAccounts(newAccount); - updateIndex(selectedAccounts[selectedAccounts.length - 1].id + 1); + if (newAccount) { + updateAccounts(newAccount); + updateIndex(newAccount.id); + } }; const selectedAccounts: Account[] = (() => { @@ -82,6 +84,12 @@ const Accounts: React.FC = ({ Public Key: {selectedAccounts[currentIndex]?.pubKey} + + HD Path: + {selectedAccounts && + selectedAccounts[currentIndex] && + selectedAccounts[currentIndex].hdPath} + diff --git a/components/HomeScreen.tsx b/components/HomeScreen.tsx index 9acdc9f..bfa62e3 100644 --- a/components/HomeScreen.tsx +++ b/components/HomeScreen.tsx @@ -30,7 +30,6 @@ const HomeScreen = () => { const createWalletHandler = async () => { setIsWalletCreating(true); - await new Promise(resolve => setTimeout(resolve, 2000)); const { mnemonic, ethAccounts, cosmosAccounts } = await createWallet(); ethAccounts && cosmosAccounts && diff --git a/types.ts b/types.ts index ff85673..ac0e9b1 100644 --- a/types.ts +++ b/types.ts @@ -7,6 +7,7 @@ export type Account = { id: number; pubKey: string; address: string; + hdPath: string; }; export type WalletDetails = { diff --git a/utils.ts b/utils.ts index b9a9f7c..54b93de 100644 --- a/utils.ts +++ b/utils.ts @@ -22,12 +22,8 @@ const createWallet = async (): Promise => { await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic); const hdNode = HDNode.fromMnemonic(mnemonic); - - const ethDerivationPath = "m/44'/60'/0'/0/0"; - const cosmosDerivationPath = "m/44'/118'/0'/0/0"; - - const ethNode = hdNode.derivePath(ethDerivationPath); - const cosmosNode = hdNode.derivePath(cosmosDerivationPath); + 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)).data.address; @@ -50,12 +46,14 @@ const createWallet = async (): Promise => { id: 0, pubKey: ethNode.publicKey, address: ethAddress, + hdPath: "m/44'/60'/0'/0/0", }; const cosmosAccounts = { id: 0, pubKey: cosmosNode.publicKey, address: cosmosAddress, + hdPath: "m/44'/118'/0'/0/0", }; return { mnemonic, ethAccounts, cosmosAccounts }; @@ -84,10 +82,10 @@ const addAccount = async (network: string): Promise => { const ids = accountIds.split(',').map(Number); const id = ids[ids.length - 1] + 1; - const derivationPath = + const hdPath = network === 'eth' ? `m/44'/60'/0'/0/${id}` : `m/44'/118'/0'/0/${id}`; - const node = hdNode.derivePath(derivationPath); + const node = hdNode.derivePath(hdPath); const privKey = node.privateKey; const pubKey = node.publicKey; @@ -126,7 +124,7 @@ const addAccount = async (network: string): Promise => { indices, ); - return { id, pubKey, address }; + return { pubKey, address, id, hdPath: hdPath }; } catch (error) { console.error('Error creating account:', error); } From 49613ef52fdbc3323d5fa0696134e5a20e523113 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Fri, 16 Feb 2024 14:37:21 +0530 Subject: [PATCH 06/17] Add new account using hd path given by user --- components/Accounts.tsx | 6 ++-- components/HDPath.tsx | 63 +++++++++++++++++++++++++++++++++++++++++ types.ts | 1 + utils.ts | 38 ++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 components/HDPath.tsx diff --git a/components/Accounts.tsx b/components/Accounts.tsx index 3d787dd..e3b0aa7 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -14,7 +14,7 @@ const Accounts: React.FC = ({ accounts, updateAccounts, currentIndex, - updateIndex, + updateIndex: updateId, }) => { const navigation = useNavigation>(); @@ -29,7 +29,7 @@ const Accounts: React.FC = ({ setIsAccountCreating(false); if (newAccount) { updateAccounts(newAccount); - updateIndex(newAccount.id); + updateId(newAccount.id); } }; @@ -50,7 +50,7 @@ const Accounts: React.FC = ({ key={account.id} title={`Account ${account.id + 1}`} onPress={() => { - updateIndex(account.id); + updateId(account.id); setExpanded(false); }} /> diff --git a/components/HDPath.tsx b/components/HDPath.tsx new file mode 100644 index 0000000..64ed2d7 --- /dev/null +++ b/components/HDPath.tsx @@ -0,0 +1,63 @@ +import React, { useState } from 'react'; +import { ScrollView, View, Alert } from 'react-native'; +import { Button, Text, TextInput } from 'react-native-paper'; + +import { NativeStackScreenProps } from '@react-navigation/native-stack'; + +import { StackParamsList } from '../types'; +import { accountFromHDPath } from '../utils'; + +type HDPathProps = NativeStackScreenProps; + +const HDPath: React.FC = ({}) => { + const [path, setPath] = useState(''); + const [account, setAccount] = useState(null); + const [isAccountCreating, setIsAccountCreating] = useState(false); + + const createFromHDPathHandler = async () => { + setIsAccountCreating(true); + const newAccount = await accountFromHDPath(path); + setIsAccountCreating(false); + setAccount(newAccount); + Alert.alert('Account Created'); + }; + + return ( + + + + Enter the HD Path: + + + setPath(text)} + value={path} + /> + + + + + {account && ( + <> + + Address: + {account.address} + + + Public Key: + {account.pubKey} + + + )} + + + ); +}; + +export default HDPath; diff --git a/types.ts b/types.ts index ac0e9b1..2d66734 100644 --- a/types.ts +++ b/types.ts @@ -1,6 +1,7 @@ export type StackParamsList = { Laconic: undefined; SignMessage: { selectedNetwork: string; accountInfo: Account } | undefined; + HDPath: undefined; }; export type Account = { diff --git a/utils.ts b/utils.ts index 54b93de..83e7822 100644 --- a/utils.ts +++ b/utils.ts @@ -130,6 +130,36 @@ const addAccount = async (network: string): Promise => { } }; +const accountFromHDPath = async ( + hdPath: string, +): Promise< + | { + pubKey: string; + address: string; + } + | 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 node = hdNode.derivePath(hdPath); + + const pubKey = node.publicKey; + const address = node.address; + + return { pubKey, address }; + } catch (error) { + console.error('Error creating account:', error); + return undefined; + } +}; + const signMessage = async ({ message, network, @@ -253,4 +283,10 @@ const resetWallet = async () => { } }; -export { createWallet, addAccount, signMessage, resetWallet }; +export { + createWallet, + addAccount, + signMessage, + resetWallet, + accountFromHDPath, +}; From 25f9243d85076d698b420c2114e2595d627fdec8 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Mon, 19 Feb 2024 17:43:34 +0530 Subject: [PATCH 07/17] Create a function to add eth or cosmos account from hd path --- utils.ts | 61 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/utils.ts b/utils.ts index 83e7822..ad5f4fb 100644 --- a/utils.ts +++ b/utils.ts @@ -124,36 +124,70 @@ const addAccount = async (network: string): Promise => { indices, ); - return { pubKey, address, id, hdPath: hdPath }; + return { id, pubKey, address, hdPath }; } catch (error) { console.error('Error creating account:', error); } }; -const accountFromHDPath = async ( +const createAccountFromHDPath = async ( + hdPath: string, +): Promise<{ pubKey: string; address: string } | undefined> => { + try { + const account = await accountInfoFromHDPath(hdPath); + if (!account) throw new Error('Error while creating account'); + + const { privKey, pubKey, address } = account; + + const parts = hdPath.split('/'); + const id = parts[5]; + const coinType = parts[2]; + const path = parts.slice(-3).join('/'); + + const accountInfo = `${path},${privKey}`; + + switch (coinType) { + case '60': + await setInternetCredentials( + `Eth:keyServer:${id}`, + `Eth:key:${id}`, + accountInfo, + ); + break; + case '118': + await setInternetCredentials( + `Cosmos:keyServer${id}`, + `Cosmos:key:${id}`, + accountInfo, + ); + break; + } + + return { pubKey, address }; + } catch (error) { + console.error('Error creating account:', error); + return undefined; + } +}; + +const accountInfoFromHDPath = async ( hdPath: string, ): Promise< - | { - pubKey: string; - address: string; - } - | undefined + { privKey: string; pubKey: string; address: string } | undefined > => { try { const mnemonicStore = await getInternetCredentials('mnemonicServer'); - if (!mnemonicStore) { - throw new Error('Mnemonic not found!'); - } + 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 address = node.address; - return { pubKey, address }; + return { privKey, pubKey, address }; } catch (error) { console.error('Error creating account:', error); return undefined; @@ -288,5 +322,6 @@ export { addAccount, signMessage, resetWallet, - accountFromHDPath, + accountInfoFromHDPath, + createAccountFromHDPath, }; From a3c434178bfd42e4d9c486160519f501ce28cca7 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Mon, 19 Feb 2024 19:10:21 +0530 Subject: [PATCH 08/17] Add a global counter for eth and cosmos --- utils.ts | 96 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/utils.ts b/utils.ts index ad5f4fb..88897cb 100644 --- a/utils.ts +++ b/utils.ts @@ -41,6 +41,9 @@ const createWallet = async (): Promise => { await setInternetCredentials('eth:accountIndices', 'ethAccount', '0'); await setInternetCredentials('cosmos:accountIndices', 'cosmosAccount', '0'); + // Global counter + await setInternetCredentials('eth:globalCounter', 'ethCounter', '0'); + await setInternetCredentials('cosmos:globalCounter', 'cosmosCounter', '0'); const ethAccounts = { id: 0, @@ -108,23 +111,37 @@ const addAccount = async (network: string): Promise => { privKey, ); - const accountIndicesKey = `${network}:accountIndices`; - const accountIndices = await getInternetCredentials(accountIndicesKey); - - if (!accountIndices) { - throw new Error('Account not found!'); - } - let indices = accountIndices.password; + let indices = idStore.password; indices += `,${id.toString()}`; - await resetInternetCredentials(accountIndicesKey); + await resetInternetCredentials(`${network}:accountIndices`); await setInternetCredentials( - accountIndicesKey, + `${network}:accountIndices`, `${network}Account`, indices, ); - return { id, pubKey, address, hdPath }; + const counterStore = await getInternetCredentials( + `${network}:globalCounter`, + ); + if (!counterStore) { + throw new Error('Error while fetching counter'); + } + + let accountCounter = counterStore.password; + const cIds = accountCounter.split(',').map(Number); + const counterId = cIds[cIds.length - 1] + 1; + accountCounter += `,${counterId.toString()}`; + + await resetInternetCredentials(`${network}:globalCounter`); + + await setInternetCredentials( + `${network}:globalCounter`, + `${network}Counter`, + accountCounter, + ); + + return { pubKey, address, id, hdPath: hdPath }; } catch (error) { console.error('Error creating account:', error); } @@ -135,7 +152,9 @@ const createAccountFromHDPath = async ( ): Promise<{ pubKey: string; address: string } | undefined> => { try { const account = await accountInfoFromHDPath(hdPath); - if (!account) throw new Error('Error while creating account'); + if (!account) { + throw new Error('Error while creating account'); + } const { privKey, pubKey, address } = account; @@ -146,8 +165,11 @@ const createAccountFromHDPath = async ( const accountInfo = `${path},${privKey}`; + let network = null; + switch (coinType) { case '60': + network = 'eth'; await setInternetCredentials( `Eth:keyServer:${id}`, `Eth:key:${id}`, @@ -155,6 +177,7 @@ const createAccountFromHDPath = async ( ); break; case '118': + network = 'cosmos'; await setInternetCredentials( `Cosmos:keyServer${id}`, `Cosmos:key:${id}`, @@ -163,9 +186,29 @@ const createAccountFromHDPath = async ( break; } + const counterStore = await getInternetCredentials( + `${network}:globalCounter`, + ); + if (!counterStore) { + throw new Error('Error while fetching counter'); + } + + let accountCounter = counterStore.password; + const cIds = accountCounter.split(',').map(Number); + const counterId = cIds[cIds.length - 1] + 1; + accountCounter += `,${counterId.toString()}`; + + await resetInternetCredentials(`${network}:globalCounter`); + + await setInternetCredentials( + `${network}:globalCounter`, + `${network}Counter`, + accountCounter, + ); + return { pubKey, address }; } catch (error) { - console.error('Error creating account:', error); + console.error(error); return undefined; } }; @@ -175,23 +218,20 @@ const accountInfoFromHDPath = async ( ): Promise< { privKey: string; pubKey: string; address: string } | 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 node = hdNode.derivePath(hdPath); - - const privKey = node.privateKey; - const pubKey = node.publicKey; - const address = node.address; - - return { privKey, pubKey, address }; - } catch (error) { - console.error('Error creating account:', error); - return 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 address = node.address; + + return { privKey, pubKey, address }; }; const signMessage = async ({ From 4aa442b5b155267d8331dccfea0aac20c6fcf308 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Tue, 20 Feb 2024 09:14:34 +0530 Subject: [PATCH 09/17] Make review changes --- utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/utils.ts b/utils.ts index 88897cb..819bddb 100644 --- a/utils.ts +++ b/utils.ts @@ -209,7 +209,6 @@ const createAccountFromHDPath = async ( return { pubKey, address }; } catch (error) { console.error(error); - return undefined; } }; @@ -362,6 +361,5 @@ export { addAccount, signMessage, resetWallet, - accountInfoFromHDPath, createAccountFromHDPath, }; From 7a3ad2823d1efcd5065c5efbeeea069af6a45ce9 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Tue, 20 Feb 2024 10:33:49 +0530 Subject: [PATCH 10/17] Store the private keys and paths for all the accounts --- utils.ts | 74 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/utils.ts b/utils.ts index 819bddb..21d0ed9 100644 --- a/utils.ts +++ b/utils.ts @@ -28,19 +28,24 @@ const createWallet = async (): Promise => { const ethAddress = ethNode.address; const cosmosAddress = (await getCosmosAccounts(mnemonic, 0)).data.address; + const ethAccountInfo = `${0},${ethNode.privateKey}`; + const cosmosAccountInfo = `${0},${cosmosNode.privateKey}`; + + // Store HD Id and private key of accounts created using add account await setInternetCredentials( 'eth:keyServer:0', - 'eth:key:0', - ethNode.privateKey, + 'eth:keyPath:0', + ethAccountInfo, ); await setInternetCredentials( 'cosmos:keyServer:0', - 'cosmos:key:0', - cosmosNode.privateKey, + 'cosmos:keyPath:0', + cosmosAccountInfo, ); - + // Counter to keep track of add account index await setInternetCredentials('eth:accountIndices', 'ethAccount', '0'); await setInternetCredentials('cosmos:accountIndices', 'cosmosAccount', '0'); + // Global counter await setInternetCredentials('eth:globalCounter', 'ethCounter', '0'); await setInternetCredentials('cosmos:globalCounter', 'cosmosCounter', '0'); @@ -105,12 +110,6 @@ const addAccount = async (network: string): Promise => { throw new Error('Invalid wallet type'); } - await setInternetCredentials( - `${network}:keyServer:${id}`, - `${network}:key:${id}`, - privKey, - ); - let indices = idStore.password; indices += `,${id.toString()}`; @@ -141,7 +140,14 @@ const addAccount = async (network: string): Promise => { accountCounter, ); - return { pubKey, address, id, hdPath: hdPath }; + // Store the path and private key against the global counter - while fetching accounts in UI, this counter will be used + await setInternetCredentials( + `${network}:keyServer:${counterId}`, + `${network}:key:${counterId}`, + `${id}${privKey}`, + ); + + return { counterId, pubKey, address, hdPath }; } catch (error) { console.error('Error creating account:', error); } @@ -156,7 +162,7 @@ const createAccountFromHDPath = async ( throw new Error('Error while creating account'); } - const { privKey, pubKey, address } = account; + const { privKey, pubKey, address, network } = account; const parts = hdPath.split('/'); const id = parts[5]; @@ -165,22 +171,18 @@ const createAccountFromHDPath = async ( const accountInfo = `${path},${privKey}`; - let network = null; - switch (coinType) { - case '60': - network = 'eth'; + case "60'": await setInternetCredentials( - `Eth:keyServer:${id}`, - `Eth:key:${id}`, + `eth:keyServer:${id}`, + `eth:key:${id}`, accountInfo, ); break; - case '118': - network = 'cosmos'; + case "118'": await setInternetCredentials( - `Cosmos:keyServer${id}`, - `Cosmos:key:${id}`, + `cosmos:keyServer${id}`, + `cosmos:key:${id}`, accountInfo, ); break; @@ -189,6 +191,7 @@ const createAccountFromHDPath = async ( const counterStore = await getInternetCredentials( `${network}:globalCounter`, ); + if (!counterStore) { throw new Error('Error while fetching counter'); } @@ -215,7 +218,8 @@ const createAccountFromHDPath = async ( const accountInfoFromHDPath = async ( hdPath: string, ): Promise< - { privKey: string; pubKey: string; address: string } | undefined + | { privKey: string; pubKey: string; address: string; network: string } + | undefined > => { const mnemonicStore = await getInternetCredentials('mnemonicServer'); if (!mnemonicStore) { @@ -228,9 +232,27 @@ const accountInfoFromHDPath = async ( const privKey = node.privateKey; const pubKey = node.publicKey; - const address = node.address; - return { privKey, pubKey, address }; + const parts = hdPath.split('/'); + const id = parseInt(parts[5]); + 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, id)).data.address; + break; + default: + throw new Error('Invalid wallet type'); + } + return { privKey, pubKey, address, network }; }; const signMessage = async ({ From 68eec9cc1ac268e52f6e872f1b4433167219ed16 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Tue, 20 Feb 2024 11:17:05 +0530 Subject: [PATCH 11/17] Make review changes --- types.ts | 2 +- utils.ts | 78 +++++++++++++++++++++++++++++--------------------------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/types.ts b/types.ts index 2d66734..5a3135d 100644 --- a/types.ts +++ b/types.ts @@ -41,7 +41,7 @@ export type AccountsState = { export type SignMessageParams = { message: string; network: string; - accountId: number; + accountId: string; }; export type CreateWalletProps = { diff --git a/utils.ts b/utils.ts index 21d0ed9..5ea15e9 100644 --- a/utils.ts +++ b/utils.ts @@ -26,12 +26,12 @@ const createWallet = async (): Promise => { const cosmosNode = hdNode.derivePath("m/44'/118'/0'/0/0"); const ethAddress = ethNode.address; - const cosmosAddress = (await getCosmosAccounts(mnemonic, 0)).data.address; + const cosmosAddress = (await getCosmosAccounts(mnemonic, `/0'/0/0`)).data + .address; const ethAccountInfo = `${0},${ethNode.privateKey}`; const cosmosAccountInfo = `${0},${cosmosNode.privateKey}`; - // Store HD Id and private key of accounts created using add account await setInternetCredentials( 'eth:keyServer:0', 'eth:keyPath:0', @@ -42,11 +42,10 @@ const createWallet = async (): Promise => { 'cosmos:keyPath:0', cosmosAccountInfo, ); - // Counter to keep track of add account index + await setInternetCredentials('eth:accountIndices', 'ethAccount', '0'); await setInternetCredentials('cosmos:accountIndices', 'cosmosAccount', '0'); - // Global counter await setInternetCredentials('eth:globalCounter', 'ethCounter', '0'); await setInternetCredentials('cosmos:globalCounter', 'cosmosCounter', '0'); @@ -104,7 +103,8 @@ const addAccount = async (network: string): Promise => { address = node.address; break; case 'cosmos': - address = (await getCosmosAccounts(mnemonic, id)).data.address; + address = (await getCosmosAccounts(mnemonic, `0'/0/${id}`)).data + .address; break; default: throw new Error('Invalid wallet type'); @@ -128,8 +128,8 @@ const addAccount = async (network: string): Promise => { } let accountCounter = counterStore.password; - const cIds = accountCounter.split(',').map(Number); - const counterId = cIds[cIds.length - 1] + 1; + const counterIds = accountCounter.split(',').map(Number); + const counterId = counterIds[counterIds.length - 1] + 1; accountCounter += `,${counterId.toString()}`; await resetInternetCredentials(`${network}:globalCounter`); @@ -140,7 +140,6 @@ const addAccount = async (network: string): Promise => { accountCounter, ); - // Store the path and private key against the global counter - while fetching accounts in UI, this counter will be used await setInternetCredentials( `${network}:keyServer:${counterId}`, `${network}:key:${counterId}`, @@ -153,7 +152,7 @@ const addAccount = async (network: string): Promise => { } }; -const createAccountFromHDPath = async ( +const addAccountFromHDPath = async ( hdPath: string, ): Promise<{ pubKey: string; address: string } | undefined> => { try { @@ -165,29 +164,9 @@ const createAccountFromHDPath = async ( const { privKey, pubKey, address, network } = account; const parts = hdPath.split('/'); - const id = parts[5]; const coinType = parts[2]; const path = parts.slice(-3).join('/'); - const accountInfo = `${path},${privKey}`; - - switch (coinType) { - case "60'": - await setInternetCredentials( - `eth:keyServer:${id}`, - `eth:key:${id}`, - accountInfo, - ); - break; - case "118'": - await setInternetCredentials( - `cosmos:keyServer${id}`, - `cosmos:key:${id}`, - accountInfo, - ); - break; - } - const counterStore = await getInternetCredentials( `${network}:globalCounter`, ); @@ -197,8 +176,8 @@ const createAccountFromHDPath = async ( } let accountCounter = counterStore.password; - const cIds = accountCounter.split(',').map(Number); - const counterId = cIds[cIds.length - 1] + 1; + const counterIds = accountCounter.split(',').map(Number); + const counterId = counterIds[counterIds.length - 1] + 1; accountCounter += `,${counterId.toString()}`; await resetInternetCredentials(`${network}:globalCounter`); @@ -209,6 +188,25 @@ const createAccountFromHDPath = async ( accountCounter, ); + const accountInfo = `${path},${privKey}`; + + switch (coinType) { + case "60'": + await setInternetCredentials( + `eth:keyServer:${counterId}`, + `eth:key:${counterId}`, + accountInfo, + ); + break; + case "118'": + await setInternetCredentials( + `cosmos:keyServer${counterId}`, + `cosmos:key:${counterId}`, + accountInfo, + ); + break; + } + return { pubKey, address }; } catch (error) { console.error(error); @@ -234,8 +232,9 @@ const accountInfoFromHDPath = async ( const pubKey = node.publicKey; const parts = hdPath.split('/'); - const id = parseInt(parts[5]); + const path = parts.slice(-3).join('/'); const coinType = parts[2]; + console.log(path); let network: string; let address: string; @@ -247,7 +246,7 @@ const accountInfoFromHDPath = async ( break; case "118'": network = 'cosmos'; - address = (await getCosmosAccounts(mnemonic, id)).data.address; + address = (await getCosmosAccounts(mnemonic, path)).data.address; break; default: throw new Error('Invalid wallet type'); @@ -272,7 +271,7 @@ const signMessage = async ({ const signEthMessage = async ( message: string, - id: number, + id: string, ): Promise => { try { const keyCred = await getInternetCredentials(`eth:keyServer:${id}`); @@ -293,7 +292,7 @@ const signEthMessage = async ( const signCosmosMessage = async ( message: string, - id: number, + id: string, ): Promise => { try { const mnemonicStore = await getInternetCredentials('mnemonicServer'); @@ -336,10 +335,10 @@ const signCosmosMessage = async ( const getCosmosAccounts = async ( mnemonic: string, - id: number, + id: string, ): Promise<{ cosmosWallet: Secp256k1HdWallet; data: AccountData }> => { const cosmosWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, { - hdPaths: [stringToPath(`m/44'/118'/0'/0/${id}`)], + hdPaths: [stringToPath(`m/44'/118'/${id}`)], }); const accountsData = await cosmosWallet.getAccounts(); @@ -372,6 +371,9 @@ const resetWallet = async () => { 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; @@ -383,5 +385,5 @@ export { addAccount, signMessage, resetWallet, - createAccountFromHDPath, + addAccountFromHDPath, }; From f2727315bde9a52d08bbcf5dd323b5019dee679d Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Tue, 20 Feb 2024 14:39:13 +0530 Subject: [PATCH 12/17] Resolve errors due to rebasing --- components/Accounts.tsx | 8 ++--- components/HDPath.tsx | 4 +-- components/SignMessage.tsx | 4 +-- types.ts | 4 +-- utils.ts | 62 +++++++++++++++++++++++--------------- 5 files changed, 48 insertions(+), 34 deletions(-) diff --git a/components/Accounts.tsx b/components/Accounts.tsx index e3b0aa7..3eca801 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -29,7 +29,7 @@ const Accounts: React.FC = ({ setIsAccountCreating(false); if (newAccount) { updateAccounts(newAccount); - updateId(newAccount.id); + updateId(newAccount.counterId); } }; @@ -47,10 +47,10 @@ const Accounts: React.FC = ({ const renderAccountItems = () => selectedAccounts.map(account => ( { - updateId(account.id); + updateId(account.counterId); setExpanded(false); }} /> diff --git a/components/HDPath.tsx b/components/HDPath.tsx index 64ed2d7..ae2e1ab 100644 --- a/components/HDPath.tsx +++ b/components/HDPath.tsx @@ -5,7 +5,7 @@ import { Button, Text, TextInput } from 'react-native-paper'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { StackParamsList } from '../types'; -import { accountFromHDPath } from '../utils'; +import { addAccountFromHDPath } from '../utils'; type HDPathProps = NativeStackScreenProps; @@ -16,7 +16,7 @@ const HDPath: React.FC = ({}) => { const createFromHDPathHandler = async () => { setIsAccountCreating(true); - const newAccount = await accountFromHDPath(path); + const newAccount = await addAccountFromHDPath(path); setIsAccountCreating(false); setAccount(newAccount); Alert.alert('Account Created'); diff --git a/components/SignMessage.tsx b/components/SignMessage.tsx index 64884f7..db62e64 100644 --- a/components/SignMessage.tsx +++ b/components/SignMessage.tsx @@ -24,7 +24,7 @@ const SignMessage = ({ route }: SignProps) => { const signedMessage = await signMessage({ message, network, - accountId: account.id, + accountId: account.counterId, }); Alert.alert('Signature', signedMessage); } @@ -35,7 +35,7 @@ const SignMessage = ({ route }: SignProps) => { - {account && `Account ${account.id + 1}`} + {account && `Account ${account.counterId + 1}`} diff --git a/types.ts b/types.ts index 5a3135d..980b680 100644 --- a/types.ts +++ b/types.ts @@ -5,7 +5,7 @@ export type StackParamsList = { }; export type Account = { - id: number; + counterId: number; pubKey: string; address: string; hdPath: string; @@ -41,7 +41,7 @@ export type AccountsState = { export type SignMessageParams = { message: string; network: string; - accountId: string; + accountId: number; }; export type CreateWalletProps = { diff --git a/utils.ts b/utils.ts index 5ea15e9..31d35f3 100644 --- a/utils.ts +++ b/utils.ts @@ -26,7 +26,7 @@ const createWallet = async (): Promise => { 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},${ethNode.privateKey}`; @@ -34,30 +34,30 @@ const createWallet = async (): Promise => { await setInternetCredentials( 'eth:keyServer:0', - 'eth:keyPath:0', + 'eth:pathKey:0', ethAccountInfo, ); await setInternetCredentials( 'cosmos:keyServer:0', - 'cosmos:keyPath:0', + 'cosmos:pathKey:0', cosmosAccountInfo, ); - await setInternetCredentials('eth:accountIndices', 'ethAccount', '0'); - await setInternetCredentials('cosmos:accountIndices', 'cosmosAccount', '0'); + await setInternetCredentials('eth:accountIndices', 'ethCounter', '0'); + await setInternetCredentials('cosmos:accountIndices', 'cosmosCounter', '0'); - await setInternetCredentials('eth:globalCounter', 'ethCounter', '0'); - await setInternetCredentials('cosmos:globalCounter', 'cosmosCounter', '0'); + await setInternetCredentials('eth:globalCounter', 'ethGlobal', '0'); + await setInternetCredentials('cosmos:globalCounter', 'cosmosGlobal', '0'); const ethAccounts = { - id: 0, + counterId: 0, pubKey: ethNode.publicKey, address: ethAddress, hdPath: "m/44'/60'/0'/0/0", }; const cosmosAccounts = { - id: 0, + counterId: 0, pubKey: cosmosNode.publicKey, address: cosmosAddress, hdPath: "m/44'/118'/0'/0/0", @@ -116,7 +116,7 @@ const addAccount = async (network: string): Promise => { await resetInternetCredentials(`${network}:accountIndices`); await setInternetCredentials( `${network}:accountIndices`, - `${network}Account`, + `${network}Counter`, indices, ); @@ -136,14 +136,14 @@ const addAccount = async (network: string): Promise => { await setInternetCredentials( `${network}:globalCounter`, - `${network}Counter`, + `${network}Global`, accountCounter, ); await setInternetCredentials( `${network}:keyServer:${counterId}`, - `${network}:key:${counterId}`, - `${id}${privKey}`, + `${network}:pathKey:${counterId}`, + `0'/0/${id}${privKey}`, ); return { counterId, pubKey, address, hdPath }; @@ -184,7 +184,7 @@ const addAccountFromHDPath = async ( await setInternetCredentials( `${network}:globalCounter`, - `${network}Counter`, + `${network}Global`, accountCounter, ); @@ -194,19 +194,21 @@ const addAccountFromHDPath = async ( case "60'": await setInternetCredentials( `eth:keyServer:${counterId}`, - `eth:key:${counterId}`, + `eth:pathKey:${counterId}`, accountInfo, ); break; case "118'": await setInternetCredentials( `cosmos:keyServer${counterId}`, - `cosmos:key:${counterId}`, + `cosmos:pathKey:${counterId}`, accountInfo, ); break; } + console.log(pubKey, address); + return { pubKey, address }; } catch (error) { console.error(error); @@ -259,11 +261,23 @@ const signMessage = async ({ network, accountId, }: SignMessageParams): Promise => { + 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[pathkey.length - 1]; + switch (network) { case 'eth': - return await signEthMessage(message, accountId); + return await signEthMessage(message, hdPath); case 'cosmos': - return await signCosmosMessage(message, accountId); + return await signCosmosMessage(message, hdPath); default: throw new Error('Invalid wallet type'); } @@ -271,10 +285,10 @@ const signMessage = async ({ const signEthMessage = async ( message: string, - id: string, + hdPath: string, ): Promise => { try { - const keyCred = await getInternetCredentials(`eth:keyServer:${id}`); + const keyCred = await getInternetCredentials(`eth:keyServer:${hdPath}`); if (!keyCred) { throw new Error('Failed to retrieve internet credentials'); @@ -292,7 +306,7 @@ const signEthMessage = async ( const signCosmosMessage = async ( message: string, - id: string, + hdPath: string, ): Promise => { try { const mnemonicStore = await getInternetCredentials('mnemonicServer'); @@ -302,7 +316,7 @@ const signCosmosMessage = async ( } const mnemonic = mnemonicStore.password; - const cosmosAccount = await getCosmosAccounts(mnemonic, id); + const cosmosAccount = await getCosmosAccounts(mnemonic, hdPath); const cosmosSignature = await cosmosAccount.cosmosWallet.signAmino( cosmosAccount.data.address, { @@ -335,10 +349,10 @@ const signCosmosMessage = async ( const getCosmosAccounts = async ( mnemonic: string, - id: string, + hdPath: string, ): Promise<{ cosmosWallet: Secp256k1HdWallet; data: AccountData }> => { const cosmosWallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, { - hdPaths: [stringToPath(`m/44'/118'/${id}`)], + hdPaths: [stringToPath(`m/44'/118'/${hdPath}`)], }); const accountsData = await cosmosWallet.getAccounts(); From 35d51f1c015773403033754315ff826fd68581f6 Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Tue, 20 Feb 2024 18:06:29 +0530 Subject: [PATCH 13/17] Use dialog box to add accounts using HD path --- components/Accounts.tsx | 18 ++++++++++++++ components/HDPath.tsx | 47 ++++++++++++++----------------------- components/HDPathDialog.tsx | 28 ++++++++++++++++++++++ types.ts | 14 ++++++++++- utils.ts | 10 ++++---- 5 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 components/HDPathDialog.tsx diff --git a/components/Accounts.tsx b/components/Accounts.tsx index 3eca801..6850299 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -8,6 +8,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { AccountsProps, StackParamsList, Account } from '../types'; import { addAccount } from '../utils'; import styles from '../styles/stylesheet'; +import HDPathDialog from './HDPathDialog'; const Accounts: React.FC = ({ network, @@ -21,6 +22,7 @@ const Accounts: React.FC = ({ const [expanded, setExpanded] = useState(false); const [isAccountCreating, setIsAccountCreating] = useState(false); + const [hdDialog, setHdDialog] = useState(false); const handlePress = () => setExpanded(!expanded); const addAccountHandler = async () => { @@ -59,6 +61,12 @@ const Accounts: React.FC = ({ return ( + setHdDialog(false)} + updateAccounts={updateAccounts} + updateIndex={updateId} + /> = ({ + + + + Address: diff --git a/components/HDPath.tsx b/components/HDPath.tsx index ae2e1ab..a5d86cc 100644 --- a/components/HDPath.tsx +++ b/components/HDPath.tsx @@ -1,34 +1,35 @@ import React, { useState } from 'react'; -import { ScrollView, View, Alert } from 'react-native'; -import { Button, Text, TextInput } from 'react-native-paper'; +import { ScrollView, View } from 'react-native'; +import { Button, TextInput } from 'react-native-paper'; -import { NativeStackScreenProps } from '@react-navigation/native-stack'; - -import { StackParamsList } from '../types'; import { addAccountFromHDPath } from '../utils'; +import { Account } from '../types'; -type HDPathProps = NativeStackScreenProps; - -const HDPath: React.FC = ({}) => { +const HDPath = ({ + updateAccounts, + updateIndex, + hideDialog, +}: { + updateIndex: (index: number) => void; + updateAccounts: (account: Account) => void; + hideDialog: () => void; +}) => { const [path, setPath] = useState(''); - const [account, setAccount] = useState(null); const [isAccountCreating, setIsAccountCreating] = useState(false); const createFromHDPathHandler = async () => { setIsAccountCreating(true); const newAccount = await addAccountFromHDPath(path); setIsAccountCreating(false); - setAccount(newAccount); - Alert.alert('Account Created'); + if (newAccount) { + updateAccounts(newAccount); + updateIndex(newAccount.counterId); + hideDialog(); + } }; return ( - - - Enter the HD Path: - - setPath(text)} @@ -42,20 +43,6 @@ const HDPath: React.FC = ({}) => { {isAccountCreating ? 'Adding' : 'Add Account'} - - {account && ( - <> - - Address: - {account.address} - - - Public Key: - {account.pubKey} - - - )} - ); }; diff --git a/components/HDPathDialog.tsx b/components/HDPathDialog.tsx new file mode 100644 index 0000000..08b1c93 --- /dev/null +++ b/components/HDPathDialog.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Portal, Dialog } from 'react-native-paper'; +import { HDPathDialogProps } from '../types'; +import HDPath from './HDPath'; + +const HDPathDialog = ({ + visible, + hideDialog, + updateIndex, + updateAccounts, +}: HDPathDialogProps) => { + return ( + + + Add account from HD path + + + + + + ); +}; + +export default HDPathDialog; diff --git a/types.ts b/types.ts index 980b680..a303531 100644 --- a/types.ts +++ b/types.ts @@ -1,7 +1,12 @@ export type StackParamsList = { Laconic: undefined; SignMessage: { selectedNetwork: string; accountInfo: Account } | undefined; - HDPath: undefined; + HDPath: + | { + updateIndex: (index: number) => void; + updateAccounts: (account: Account) => void; + } + | undefined; }; export type Account = { @@ -55,6 +60,13 @@ export type ResetDialogProps = { onConfirm: () => void; }; +export type HDPathDialogProps = { + visible: boolean; + hideDialog: () => void; + updateIndex: (index: number) => void; + updateAccounts: (account: Account) => void; +}; + export type GridViewProps = { words: string[]; }; diff --git a/utils.ts b/utils.ts index 31d35f3..4a28585 100644 --- a/utils.ts +++ b/utils.ts @@ -154,7 +154,10 @@ const addAccount = async (network: string): Promise => { const addAccountFromHDPath = async ( hdPath: string, -): Promise<{ pubKey: string; address: string } | undefined> => { +): Promise< + | { counterId: number; pubKey: string; address: string; hdPath: string } + | undefined +> => { try { const account = await accountInfoFromHDPath(hdPath); if (!account) { @@ -207,9 +210,7 @@ const addAccountFromHDPath = async ( break; } - console.log(pubKey, address); - - return { pubKey, address }; + return { counterId, pubKey, address, hdPath }; } catch (error) { console.error(error); } @@ -236,7 +237,6 @@ const accountInfoFromHDPath = async ( const parts = hdPath.split('/'); const path = parts.slice(-3).join('/'); const coinType = parts[2]; - console.log(path); let network: string; let address: string; From 63edfdd9900cc9990d6bc8f0d093e6ec632992fb Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Tue, 20 Feb 2024 18:55:00 +0530 Subject: [PATCH 14/17] Modify signMessage function --- components/Accounts.tsx | 1 + components/HDPath.tsx | 1 + utils.ts | 15 +++++++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/components/Accounts.tsx b/components/Accounts.tsx index 6850299..4d05944 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -23,6 +23,7 @@ const Accounts: React.FC = ({ const [expanded, setExpanded] = useState(false); const [isAccountCreating, setIsAccountCreating] = useState(false); const [hdDialog, setHdDialog] = useState(false); + const handlePress = () => setExpanded(!expanded); const addAccountHandler = async () => { diff --git a/components/HDPath.tsx b/components/HDPath.tsx index a5d86cc..f3cb123 100644 --- a/components/HDPath.tsx +++ b/components/HDPath.tsx @@ -21,6 +21,7 @@ const HDPath = ({ setIsAccountCreating(true); const newAccount = await addAccountFromHDPath(path); setIsAccountCreating(false); + if (newAccount) { updateAccounts(newAccount); updateIndex(newAccount.counterId); diff --git a/utils.ts b/utils.ts index 4a28585..516cb01 100644 --- a/utils.ts +++ b/utils.ts @@ -143,7 +143,7 @@ const addAccount = async (network: string): Promise => { await setInternetCredentials( `${network}:keyServer:${counterId}`, `${network}:pathKey:${counterId}`, - `0'/0/${id}${privKey}`, + `0'/0/${id},${privKey}`, ); return { counterId, pubKey, address, hdPath }; @@ -271,11 +271,11 @@ const signMessage = async ({ const pathKeyVal = pathKeyStore.password; const pathkey = pathKeyVal.split(','); - const hdPath = pathkey[pathkey.length - 1]; + const hdPath = pathkey[0]; switch (network) { case 'eth': - return await signEthMessage(message, hdPath); + return await signEthMessage(message, accountId); case 'cosmos': return await signCosmosMessage(message, hdPath); default: @@ -285,16 +285,19 @@ const signMessage = async ({ const signEthMessage = async ( message: string, - hdPath: string, + accountId: number, ): Promise => { try { - const keyCred = await getInternetCredentials(`eth:keyServer:${hdPath}`); + const keyCred = await getInternetCredentials(`eth:keyServer:${accountId}`); if (!keyCred) { throw new Error('Failed to retrieve internet credentials'); } - const wallet = new Wallet(keyCred.password); + 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; From 9a6e52de90563fa9ca34b6d96a15d61d5ae2772d Mon Sep 17 00:00:00 2001 From: IshaVenikar Date: Wed, 21 Feb 2024 10:08:27 +0530 Subject: [PATCH 15/17] Hard-code the prefix of the hd paths and refactor functions --- components/Accounts.tsx | 14 +- components/HDPath.tsx | 26 ++- components/HDPathDialog.tsx | 2 + components/HomeScreen.tsx | 2 +- components/SignMessage.tsx | 2 +- types.ts | 1 + utils.ts | 406 ------------------------------------ utils/Accounts.ts | 168 +++++++++++++++ utils/SignMessage.ts | 80 +++++++ utils/utils.ts | 211 +++++++++++++++++++ 10 files changed, 494 insertions(+), 418 deletions(-) delete mode 100644 utils.ts create mode 100644 utils/Accounts.ts create mode 100644 utils/SignMessage.ts create mode 100644 utils/utils.ts diff --git a/components/Accounts.tsx b/components/Accounts.tsx index 4d05944..eaa96ab 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -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 = ({ 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 = ({ hideDialog={() => setHdDialog(false)} updateAccounts={updateAccounts} updateIndex={updateId} + pathCode={pathCode} // Pass pathCode here /> = ({ 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 diff --git a/components/HDPath.tsx b/components/HDPath.tsx index f3cb123..1e66efe 100644 --- a/components/HDPath.tsx +++ b/components/HDPath.tsx @@ -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 ( - setPath(text)} - value={path} - /> + + + {pathCode} + + setPath(text)} + value={path} + style={{ flex: 1 }} + /> + @@ -117,9 +105,7 @@ const Accounts: React.FC = ({ HD Path: - {selectedAccounts && - selectedAccounts[currentIndex] && - selectedAccounts[currentIndex].hdPath} + {selectedAccounts[currentIndex]?.hdPath} diff --git a/components/HDPath.tsx b/components/HDPath.tsx index 1e66efe..6e9c6fa 100644 --- a/components/HDPath.tsx +++ b/components/HDPath.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { ScrollView, View, Text } from 'react-native'; import { Button, TextInput } from 'react-native-paper'; + import { addAccountFromHDPath } from '../utils/Accounts'; import { Account } from '../types'; @@ -21,13 +22,17 @@ const HDPath = ({ const createFromHDPathHandler = async () => { setIsAccountCreating(true); const hdPath = pathCode + path; - const newAccount = await addAccountFromHDPath(hdPath); - setIsAccountCreating(false); - - if (newAccount) { - updateAccounts(newAccount); - updateIndex(newAccount.counterId); - hideDialog(); + try { + const newAccount = await addAccountFromHDPath(hdPath); + if (newAccount) { + updateAccounts(newAccount); + updateIndex(newAccount.counterId); + hideDialog(); + } + } catch (error) { + console.error('Error creating account:', error); + } finally { + setIsAccountCreating(false); } }; @@ -39,7 +44,7 @@ const HDPath = ({ setPath(text)} + onChangeText={setPath} value={path} style={{ flex: 1 }} /> diff --git a/components/HomeScreen.tsx b/components/HomeScreen.tsx index b2d5267..e6dc587 100644 --- a/components/HomeScreen.tsx +++ b/components/HomeScreen.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Alert, View } from 'react-native'; +import { View } from 'react-native'; import { Button } from 'react-native-paper'; import { createWallet, resetWallet } from '../utils/Accounts'; @@ -19,7 +19,6 @@ const HomeScreen = () => { const [network, setNetwork] = useState('eth'); const [currentIndex, setCurrentIndex] = useState(0); const [phrase, setPhrase] = useState(''); - const [accounts, setAccounts] = useState({ ethAccounts: [], cosmosAccounts: [], @@ -31,15 +30,15 @@ const HomeScreen = () => { const createWalletHandler = async () => { setIsWalletCreating(true); const { mnemonic, ethAccounts, cosmosAccounts } = await createWallet(); - ethAccounts && - cosmosAccounts && + if (ethAccounts && cosmosAccounts) { setAccounts({ ethAccounts: [...accounts.ethAccounts, ethAccounts], cosmosAccounts: [...accounts.cosmosAccounts, cosmosAccounts], }); - setWalletDialog(true); - setIsWalletCreated(true); - setPhrase(mnemonic); + setWalletDialog(true); + setIsWalletCreated(true); + setPhrase(mnemonic); + } }; const confirmResetWallet = async () => { @@ -79,9 +78,10 @@ const HomeScreen = () => { }); break; default: - Alert.alert('Select a valid network!'); + console.error('Select a valid network!'); } }; + return ( Date: Wed, 21 Feb 2024 11:09:29 +0530 Subject: [PATCH 17/17] Make the component definitions consistent --- components/Accounts.tsx | 4 ++-- components/Dialog.tsx | 4 ++-- components/Grid.tsx | 2 +- components/NetworkDropdown.tsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/Accounts.tsx b/components/Accounts.tsx index b6b6b39..fa04c2a 100644 --- a/components/Accounts.tsx +++ b/components/Accounts.tsx @@ -8,13 +8,13 @@ import { addAccount } from '../utils/Accounts'; import styles from '../styles/stylesheet'; import HDPathDialog from './HDPathDialog'; -const Accounts: React.FC = ({ +const Accounts = ({ network, accounts, updateAccounts, currentIndex, updateIndex: updateId, -}) => { +}: AccountsProps) => { const navigation = useNavigation>(); const [expanded, setExpanded] = useState(false); diff --git a/components/Dialog.tsx b/components/Dialog.tsx index 9bef5e1..2867b74 100644 --- a/components/Dialog.tsx +++ b/components/Dialog.tsx @@ -12,11 +12,11 @@ type CustomDialogProps = { titleText?: string; }; -const DialogComponent: React.FC = ({ +const DialogComponent = ({ visible, hideDialog, contentText, -}) => { +}: CustomDialogProps) => { const words = contentText.split(' '); return ( diff --git a/components/Grid.tsx b/components/Grid.tsx index 752db7b..764e51c 100644 --- a/components/Grid.tsx +++ b/components/Grid.tsx @@ -5,7 +5,7 @@ import { Text } from 'react-native-paper'; import styles from '../styles/stylesheet'; import { GridViewProps } from '../types'; -const GridView: React.FC = ({ words }) => { +const GridView = ({ words }: GridViewProps) => { return ( {words.map((word, index) => ( diff --git a/components/NetworkDropdown.tsx b/components/NetworkDropdown.tsx index 37ad624..320eaae 100644 --- a/components/NetworkDropdown.tsx +++ b/components/NetworkDropdown.tsx @@ -5,7 +5,7 @@ import { List } from 'react-native-paper'; import { NetworkDropdownProps } from '../types'; import styles from '../styles/stylesheet'; -const NetworkDropdown: React.FC = ({ updateNetwork }) => { +const NetworkDropdown = ({ updateNetwork }: NetworkDropdownProps) => { const [expanded, setExpanded] = useState(false); const [selectedNetwork, setSelectedNetwork] = useState('Ethereum');