diff --git a/components/Accounts.tsx b/components/Accounts.tsx new file mode 100644 index 0000000..e43b48a --- /dev/null +++ b/components/Accounts.tsx @@ -0,0 +1,93 @@ +import { View } from 'react-native'; +import React, { useState } from 'react'; +import { Button, List, Text } from 'react-native-paper'; + +import { useNavigation } from '@react-navigation/native'; +import { NativeStackNavigationProp } from '@react-navigation/native-stack'; + +import { AccountsProps, StackParamsList, Account } from '../types'; +import { addAccount } from '../utils'; + +const Accounts: React.FC = ({ + network, + accounts, + updateAccounts, + currentIndex, + updateIndex, +}) => { + const navigation = + useNavigation>(); + + const [expanded, setExpanded] = useState(false); + + const handlePress = () => setExpanded(!expanded); + + const addAccountHandler = async () => { + const newAccount = await addAccount(network); + newAccount && updateAccounts(newAccount); + updateIndex(selectedAccounts[selectedAccounts.length -1].id); + }; + + let selectedAccounts: Account[] = []; + + if (network === 'eth') { + selectedAccounts = accounts.ethAccounts; + } + if (network === 'cosmos') { + selectedAccounts = accounts.cosmosAccounts; + } + + return ( + + + {selectedAccounts && + selectedAccounts.map((account) => ( + { + updateIndex(account.id); + setExpanded(false); + }} + /> + ))} + + + + + + + Address: + {selectedAccounts && + selectedAccounts[currentIndex] && + selectedAccounts[currentIndex].address} + + + Public Key: + {selectedAccounts && + selectedAccounts[currentIndex] && + selectedAccounts[currentIndex].pubKey} + + + + + + + ); +}; + +export default Accounts; diff --git a/components/Dialog.tsx b/components/Dialog.tsx index c4ca5f5..22ccba8 100644 --- a/components/Dialog.tsx +++ b/components/Dialog.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import { Button, Dialog, Portal, Text } from "react-native-paper"; +import React from 'react'; +import { Button, Dialog, Portal, Text } from 'react-native-paper'; type CustomDialogProps = { visible: boolean; @@ -8,7 +8,11 @@ type CustomDialogProps = { titleText?: string; }; -const DialogComponent: React.FC = ({ visible, hideDialog, titleText, contentText }) => { +const DialogComponent: React.FC = ({ + visible, + hideDialog, + contentText, +}) => { return ( diff --git a/components/HomeScreen.tsx b/components/HomeScreen.tsx index 4fd25d6..2255709 100644 --- a/components/HomeScreen.tsx +++ b/components/HomeScreen.tsx @@ -1,27 +1,25 @@ import React, { useState } from 'react'; -import { View } from 'react-native'; +import { Alert, ScrollView, View } from 'react-native'; import { Text, Button, Dialog, Portal } from 'react-native-paper'; -import { useNavigation } from '@react-navigation/native'; -import { NativeStackNavigationProp } from '@react-navigation/native-stack'; - import { createWallet, resetWallet } from '../utils'; import { DialogComponent } from './Dialog'; import { NetworkDropdown } from './NetworkDropdown'; -import { StackParamsList, Account } from '../types'; +import { Account, AccountsState } from '../types'; +import Accounts from './Accounts'; const HomeScreen = () => { - const navigation = - useNavigation>(); - const [isWalletCreated, setIsWalletCreated] = useState(false); const [isWalletCreating, setIsWalletCreating] = useState(false); const [walletDialog, setWalletDialog] = useState(false); const [resetWalletDialog, setResetWalletDialog] = useState(false); const [network, setNetwork] = useState('eth'); - const [currentAccount, setCurrentAccount] = useState(); - const [ethAccount, setEthAccount] = useState(); - const [cosmosAccount, setCosmosAccount] = useState(); + const [currentIndex, setCurrentIndex] = useState(0); + + const [accounts, setAccounts] = useState({ + ethAccounts: [], + cosmosAccounts: [], + }); const hideWalletDialog = () => setWalletDialog(false); const hideResetDialog = () => setResetWalletDialog(false); @@ -30,10 +28,12 @@ const HomeScreen = () => { setIsWalletCreating(true); await new Promise(resolve => setTimeout(resolve, 2000)); const { ethWalletInfo, cosmosWalletInfo } = await createWallet(); - - setEthAccount(ethWalletInfo); - setCosmosAccount(cosmosWalletInfo); - setCurrentAccount(ethWalletInfo); + ethWalletInfo && + cosmosWalletInfo && + setAccounts({ + ethAccounts: [...accounts.ethAccounts, ethWalletInfo], + cosmosAccounts: [...accounts.cosmosAccounts, cosmosWalletInfo], + }); setWalletDialog(true); setIsWalletCreated(true); }; @@ -42,25 +42,44 @@ const HomeScreen = () => { await resetWallet(); setIsWalletCreated(false); setIsWalletCreating(false); + setAccounts({ + ethAccounts: [], + cosmosAccounts: [], + }); + setCurrentIndex(0); hideResetDialog(); + setNetwork('eth'); }; const updateNetwork = (newNetwork: string) => { setNetwork(newNetwork); - switch (newNetwork) { - case 'eth': - setCurrentAccount(ethAccount); - break; - case 'cosmos': - setCurrentAccount(cosmosAccount); - break; - default: - console.error('Error updating network'); - } + setCurrentIndex(0); }; + const updateIndex = (index: number) => { + setCurrentIndex(index); + }; + + const updateAccounts = (account: Account) => { + switch (network) { + case 'eth': + setAccounts({ + ...accounts, + ethAccounts: [...accounts.ethAccounts, account], + }); + break; + case 'cosmos': + setAccounts({ + ...accounts, + cosmosAccounts: [...accounts.cosmosAccounts, account], + }); + break; + default: + Alert.alert('Select a valid network!'); + } + }; return ( - + { selectedNetwork={network} updateNetwork={updateNetwork} /> - Account 1 - - - Address: - {currentAccount && currentAccount.address} - - - Public Key: - {currentAccount && currentAccount.pubKey} - - - - - - - + + )} - + ); }; diff --git a/components/NetworkDropdown.tsx b/components/NetworkDropdown.tsx index 8751b0e..99e1aac 100644 --- a/components/NetworkDropdown.tsx +++ b/components/NetworkDropdown.tsx @@ -2,10 +2,7 @@ import React, { useState } from 'react'; import { View } from 'react-native'; import { List } from 'react-native-paper'; -type NetworkDropdownProps = { - selectedNetwork: string; - updateNetwork: (network: string) => void; -}; +import { NetworkDropdownProps } from '../types'; const NetworkDropdown: React.FC = ({ updateNetwork, diff --git a/components/SignMessage.tsx b/components/SignMessage.tsx index 7904b4d..8a8afee 100644 --- a/components/SignMessage.tsx +++ b/components/SignMessage.tsx @@ -1,7 +1,6 @@ -import { View } from 'react-native'; -import { Button, TextInput } from 'react-native-paper'; import React, { useState } from 'react'; -import { Alert } from 'react-native'; +import { ScrollView, View, Alert } from 'react-native'; +import { Button, Text, TextInput } from 'react-native-paper'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; @@ -12,18 +11,32 @@ type SignProps = NativeStackScreenProps; const SignMessage = ({ route }: SignProps) => { const network = route.params?.selectedNetwork; + const account = route.params?.accountInfo; const [message, setMessage] = useState(''); const signMessageHandler = async () => { if (network) { - const signedMessage = await signMessage(message, network, 0); + if (!account){ + throw new Error("Account is not valid"); + } + const signedMessage = await signMessage(message, network, account.id); Alert.alert('Signature', signedMessage); } }; return ( - + + + + Address: + {account && account.address} + + + Public Key: + {account && account.pubKey} + + { Sign - + ); }; diff --git a/types.ts b/types.ts index 985af43..b3ccacc 100644 --- a/types.ts +++ b/types.ts @@ -1,9 +1,10 @@ export type StackParamsList = { Laconic: undefined; - SignMessage: { selectedNetwork: string } | undefined; + SignMessage: { selectedNetwork: string; accountInfo: Account } | undefined; }; export type Account = { + id: number, pubKey: string; address: string; }; @@ -12,3 +13,24 @@ export type WalletDetails = { ethAccount: Account; cosmosAccount: Account; }; + +export type AccountsProps = { + network: string; + accounts: { + ethAccounts: Account[]; + cosmosAccounts: Account[]; + }; + currentIndex: number; + updateIndex: (index: number) => void; + updateAccounts: (account: Account) => void; +}; + +export type NetworkDropdownProps = { + selectedNetwork: string; + updateNetwork: (network: string) => void; +}; + +export type AccountsState = { + ethAccounts: Account[]; + cosmosAccounts: Account[]; +}; diff --git a/utils.ts b/utils.ts index e622821..237deac 100644 --- a/utils.ts +++ b/utils.ts @@ -15,8 +15,8 @@ import { AccountData, Secp256k1HdWallet } from '@cosmjs/amino'; import { stringToPath } from '@cosmjs/crypto'; const createWallet = async (): Promise<{ - ethWalletInfo: { pubKey: string; address: string } | undefined; - cosmosWalletInfo: { pubKey: string; address: string } | undefined; + ethWalletInfo: { id: number; pubKey: string; address: string } | undefined; + cosmosWalletInfo: { id: number; pubKey: string; address: string } | undefined; }> => { try { const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32)); @@ -41,8 +41,13 @@ const createWallet = async (): Promise<{ cosmosNode.privateKey, ); - const ethWalletInfo = { pubKey: ethNode.publicKey, address: ethAddress }; + const ethWalletInfo = { + id: 0, + pubKey: ethNode.publicKey, + address: ethAddress, + }; const cosmosWalletInfo = { + id: 0, pubKey: cosmosNode.publicKey, address: cosmosAddress, }; @@ -75,7 +80,6 @@ const signMessage = async ( index: number, ): Promise => { try { - console.log(walletType); switch (walletType) { case 'eth': return await signEthMessage(message, index); @@ -153,6 +157,16 @@ const signCosmosMessage = async ( }; // const createAccount +const addAccount = async (network: string) => { + // // const index = 5; + // switch (network) { + // case 'eth': + // return dummyEthAccounts[3]; + // case 'cosmos': + // return dummyCosmosAccounts[3]; + // } + +}; const resetWallet = async () => { // TODO: Add method to reset all the accounts @@ -161,4 +175,4 @@ const resetWallet = async () => { await resetInternetCredentials('cosmos:keyServer:0'); }; -export { createWallet, signMessage, resetWallet }; +export { createWallet, signMessage, resetWallet, addAccount };