diff --git a/App.tsx b/App.tsx index 3bebca1..97d231f 100644 --- a/App.tsx +++ b/App.tsx @@ -6,14 +6,23 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack'; import SignMessage from './components/SignMessage'; import { HomeScreen } from './components/HomeScreen'; -const Stack = createNativeStackNavigator(); +import { StackParamsList } from './types'; + +const Stack = createNativeStackNavigator(); const App = (): React.JSX.Element => { return ( - + ); diff --git a/components/HomeScreen.tsx b/components/HomeScreen.tsx index dde5ae8..e1d9a17 100644 --- a/components/HomeScreen.tsx +++ b/components/HomeScreen.tsx @@ -1,35 +1,45 @@ import React, { useState } from 'react'; import { View } from 'react-native'; -import { Text, Button, Dialog, Portal, List } from 'react-native-paper'; +import { Text, Button, Dialog, Portal } from 'react-native-paper'; import { HDNode } from 'ethers/lib/utils'; import { useNavigation } from '@react-navigation/native'; +import { NativeStackNavigationProp } from '@react-navigation/native-stack'; -import { generateWallet, resetWallet } from '../utils'; +import { createWallet, resetWallet } from '../utils'; import { DialogComponent } from './Dialog'; import { NetworkDropdown } from './NetworkDropdown'; +import { StackParamsList, Account } from '../types'; + + const HomeScreen = () => { - const navigation = useNavigation(); + const navigation = + useNavigation>(); const [isWalletCreated, setIsWalletCreated] = useState(false); const [wallet, setWallet] = useState(); 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 hideWalletDialog = () => setWalletDialog(false); const hideResetDialog = () => setResetWalletDialog(false); - const createWallet = async () => { + const createWalletHandler = async () => { setIsWalletCreating(true); - await new Promise(resolve => setTimeout(resolve, 200)); - const etherWallet = await generateWallet(); + await new Promise(resolve => setTimeout(resolve, 2000)); + const { ethAccount, cosmosAccount } = createWallet(); + + setEthAccount(ethAccount); + setCosmosAccount(cosmosAccount); + setCurrentAccount(ethAccount); setWalletDialog(true); - if (etherWallet) { - setWallet(etherWallet); - setIsWalletCreated(true); - } + setIsWalletCreated(true); }; const confirmResetWallet = async () => { @@ -40,6 +50,20 @@ const HomeScreen = () => { hideResetDialog(); }; + const updateNetwork = (newNetwork: string) => { + setNetwork(newNetwork); + switch (newNetwork) { + case 'eth': + setCurrentAccount(ethAccount); + break; + case 'cosmos': + setCurrentAccount(cosmosAccount); + break; + default: + console.error('Error updating network'); + } + }; + return ( { {isWalletCreated ? ( - - Account1 + + Account 1 Address: - {wallet && wallet.address.toString()} + {currentAccount && currentAccount.address} Public Key: - {wallet && wallet.publicKey.toString()} + {currentAccount && currentAccount.publicKey} + { @@ -110,7 +140,7 @@ const HomeScreen = () => { diff --git a/components/NetworkDropdown.tsx b/components/NetworkDropdown.tsx index b00ed04..8751b0e 100644 --- a/components/NetworkDropdown.tsx +++ b/components/NetworkDropdown.tsx @@ -2,26 +2,38 @@ import React, { useState } from 'react'; import { View } from 'react-native'; import { List } from 'react-native-paper'; -const NetworkDropdown = () => { +type NetworkDropdownProps = { + selectedNetwork: string; + updateNetwork: (network: string) => void; +}; + +const NetworkDropdown: React.FC = ({ + updateNetwork, +}) => { const [expanded, setExpanded] = useState(false); + const [title, setTitle] = useState('Ethereum'); const expandNetworks = () => setExpanded(!expanded); return ( { + updateNetwork('eth'); + setTitle('Ethereum'); setExpanded(false); }} /> { + updateNetwork('cosmos'); + setTitle('Cosmos'); setExpanded(false); }} /> diff --git a/components/Section.tsx b/components/Section.tsx index 6ac1ec9..38f6603 100644 --- a/components/Section.tsx +++ b/components/Section.tsx @@ -1,8 +1,8 @@ -import { PropsWithChildren } from "react"; -import { Text, View, useColorScheme } from "react-native"; -import { Colors } from "react-native/Libraries/NewAppScreen"; +import { PropsWithChildren } from 'react'; +import { Text, View, useColorScheme } from 'react-native'; +import { Colors } from 'react-native/Libraries/NewAppScreen'; -import styles from "../styles/stylesheet"; +import styles from '../styles/stylesheet'; type SectionProps = PropsWithChildren<{ title: string; diff --git a/components/SignMessage.tsx b/components/SignMessage.tsx index ba654ab..443151e 100644 --- a/components/SignMessage.tsx +++ b/components/SignMessage.tsx @@ -2,10 +2,18 @@ import { View } from 'react-native'; import { Button, TextInput } from 'react-native-paper'; import React, { useState } from 'react'; +import { NativeStackScreenProps } from '@react-navigation/native-stack'; + +import { StackParamsList } from '../types'; import { signMessage } from '../utils'; -export default function SignMessage() { +type SignProps = NativeStackScreenProps; + +const SignMessage = ({ route }: SignProps) => { + const network = route.params?.selectedNetwork; + const [message, setMessage] = useState(''); + return ( { - signMessage(message); + network && signMessage(network, 0, message); }}> Sign ); -} +}; + +export default SignMessage; diff --git a/constants.ts b/constants.ts new file mode 100644 index 0000000..fdb44ab --- /dev/null +++ b/constants.ts @@ -0,0 +1,5 @@ +export const COSMOS_SIGNATURE = + '0x56da25d5a9704e0cd685d52ecee5c14bf6637fa2f95653e8499eac4e8285f37b2d9f446c027cac56f3b7840d1b3879ea943415190d7a358cdb3ee05451cdcf7c1c'; +export const COSMOS_ADDRESS = 'cosmos1sulk9q5fmagur6m3pctmcnfeeku25gp2ectt75'; +export const COSMOS_PUBKEY = + 'cosmospub1addwnpepqt9d597c5f6zqqyxy3msrstyc7zl3vyvrl5ku02r4ueuwt5vusw4gmt70dd'; diff --git a/types.ts b/types.ts new file mode 100644 index 0000000..0b90328 --- /dev/null +++ b/types.ts @@ -0,0 +1,14 @@ +export type StackParamsList = { + Laconic: undefined; + SignMessage: { selectedNetwork: string } | undefined; +}; + +export type Account = { + address: string; + publicKey: string; +}; + +export type WalletDetails = { + ethAccount: Account; + cosmosAccount: Account; +}; diff --git a/utils.ts b/utils.ts index 7579c1c..d4259e1 100644 --- a/utils.ts +++ b/utils.ts @@ -3,16 +3,17 @@ For more information, "visit https://docs.ethers.org/v5/cookbook/react-native/#c import 'react-native-get-random-values'; import '@ethersproject/shims'; -import { Wallet, utils } from 'ethers'; +import { utils } from 'ethers'; import { HDNode } from 'ethers/lib/utils'; import { Alert } from 'react-native'; import { setInternetCredentials, - getInternetCredentials, resetInternetCredentials, } from 'react-native-keychain'; -const generateWallet = async (): Promise => { +import { Account, WalletDetails } from './types'; + +const generateEthNode = async (): Promise => { try { const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32)); const hdNode = HDNode.fromMnemonic(mnemonic); @@ -27,16 +28,47 @@ const generateWallet = async (): Promise => { } }; -const signMessage = async (message: string) => { +const createWallet = (): WalletDetails => { try { - const keyCred = await getInternetCredentials('keyServer'); - const wallet = keyCred && new Wallet(keyCred.password); - const signature = wallet && (await wallet.signMessage(message)); - if (typeof signature === 'string') { - Alert.alert('Message signature: ', signature); - } else { - Alert.alert('Message signing failed. Please try again.'); + const ethAccount = { + address: '0x873784c8A011A32C7635C8d8D3D2c83060532A49', + publicKey: + '0x02fd66d3487eb0567c321dac48b5e17c469df8ede7c0c79b74a9d0492249b32f1e', + }; + + const cosmosAccount = { + address: 'cosmos1sulk9q5fmagur6m3pctmcnfeeku25gp2ectt75', + publicKey: + 'cosmospub1addwnpepqt9d597c5f6zqqyxy3msrstyc7zl3vyvrl5ku02r4ueuwt5vusw4gmt70dd', + }; + + return { ethAccount, cosmosAccount }; + } catch (error) { + console.error('Error creating wallet ', error); + throw error; + } +}; + +const signMessage = async (network: string, index: Number, message: string) => { + try { + let signature: string | false; + + switch (network) { + case 'eth': + signature = + '0x43jv95d5a9704z83h85d52ecee5c14bf6637fa2f95653e8499eac4e8285f37b2d9f446c027cac56f3b7840d1b3879ea943415190d7a358cdb3ee05451cdcf7c1c'; + break; + + case 'cosmos': + signature = + '0x56da25d5a9704e0cd685d52ecee5c14bf6637fa2f95653e8499eac4e8285f37b2d9f446c027cac56f3b7840d1b3879ea943415190d7a358cdb3ee05451cdcf7c1c'; + break; + + default: + signature = ''; } + + Alert.alert('Message signature: ', signature as string); } catch (error) { console.error('Error signing transaction ', error); } @@ -47,4 +79,4 @@ const resetWallet = async () => { await resetInternetCredentials('mnemonicServer'); }; -export { generateWallet, signMessage, resetWallet }; +export { createWallet, signMessage, resetWallet };