forked from cerc-io/laconic-wallet
Show account data specific to selected network (#11)
* Add state for selected network * Make review changes * Add cosmos signature * Explicit check for cosmos * Add dummy method for generating wallet * Remove logic from component * Add dummy sign method * Change network state values * Use separate file for types * Add default case to switch * Use consistent method names --------- Co-authored-by: Adw8 <adwait@deepstacksoft.com>
This commit is contained in:
parent
f026d9345f
commit
9ab3148aa9
13
App.tsx
13
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<StackParamsList>();
|
||||
|
||||
const App = (): React.JSX.Element => {
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen name="Laconic" component={HomeScreen} />
|
||||
<Stack.Screen name="Sign Message" component={SignMessage} />
|
||||
<Stack.Screen
|
||||
name="SignMessage"
|
||||
component={SignMessage}
|
||||
options={{
|
||||
title: 'Sign Message',
|
||||
}}
|
||||
initialParams={{ selectedNetwork: 'Ethereum' }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
@ -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<NativeStackNavigationProp<StackParamsList>>();
|
||||
|
||||
const [isWalletCreated, setIsWalletCreated] = useState<boolean>(false);
|
||||
const [wallet, setWallet] = useState<HDNode | null>();
|
||||
const [isWalletCreating, setIsWalletCreating] = useState<boolean>(false);
|
||||
const [walletDialog, setWalletDialog] = useState<boolean>(false);
|
||||
const [resetWalletDialog, setResetWalletDialog] = useState<boolean>(false);
|
||||
const [network, setNetwork] = useState<string>('eth');
|
||||
const [currentAccount, setCurrentAccount] = useState<Account>();
|
||||
const [ethAccount, setEthAccount] = useState<Account>();
|
||||
const [cosmosAccount, setCosmosAccount] = useState<Account>();
|
||||
|
||||
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 (
|
||||
<View style={{ marginTop: 24, paddingHorizontal: 24 }}>
|
||||
<DialogComponent
|
||||
@ -63,18 +87,22 @@ const HomeScreen = () => {
|
||||
</Portal>
|
||||
{isWalletCreated ? (
|
||||
<View>
|
||||
<NetworkDropdown />
|
||||
<Text variant="headlineSmall">Account1</Text>
|
||||
<NetworkDropdown
|
||||
selectedNetwork={network}
|
||||
updateNetwork={updateNetwork}
|
||||
/>
|
||||
<Text variant="headlineSmall">Account 1</Text>
|
||||
<View style={{ marginTop: 15, marginBottom: 15 }}>
|
||||
<Text variant="bodyLarge">
|
||||
<Text style={{ fontWeight: '700' }}>Address: </Text>
|
||||
{wallet && wallet.address.toString()}
|
||||
{currentAccount && currentAccount.address}
|
||||
</Text>
|
||||
<Text variant="bodyLarge">
|
||||
<Text style={{ fontWeight: '700' }}>Public Key: </Text>
|
||||
{wallet && wallet.publicKey.toString()}
|
||||
{currentAccount && currentAccount.publicKey}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
@ -86,7 +114,9 @@ const HomeScreen = () => {
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => {
|
||||
navigation.navigate('Sign Message' as never);
|
||||
navigation.navigate('SignMessage', {
|
||||
selectedNetwork: network,
|
||||
});
|
||||
}}>
|
||||
Sign Message
|
||||
</Button>
|
||||
@ -110,7 +140,7 @@ const HomeScreen = () => {
|
||||
<Button
|
||||
mode="contained"
|
||||
loading={isWalletCreating}
|
||||
onPress={createWallet}>
|
||||
onPress={createWalletHandler}>
|
||||
{isWalletCreating ? 'Creating' : 'Create'}{' '}
|
||||
</Button>
|
||||
</View>
|
||||
|
@ -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<NetworkDropdownProps> = ({
|
||||
updateNetwork,
|
||||
}) => {
|
||||
const [expanded, setExpanded] = useState<boolean>(false);
|
||||
const [title, setTitle] = useState<string>('Ethereum');
|
||||
|
||||
const expandNetworks = () => setExpanded(!expanded);
|
||||
|
||||
return (
|
||||
<View style={{ marginBottom: 20 }}>
|
||||
<List.Accordion
|
||||
title="Select Network"
|
||||
title={title}
|
||||
expanded={expanded}
|
||||
onPress={expandNetworks}>
|
||||
<List.Item
|
||||
title="Ethereum"
|
||||
onPress={() => {
|
||||
updateNetwork('eth');
|
||||
setTitle('Ethereum');
|
||||
setExpanded(false);
|
||||
}}
|
||||
/>
|
||||
<List.Item
|
||||
title="Cosmos"
|
||||
onPress={() => {
|
||||
updateNetwork('cosmos');
|
||||
setTitle('Cosmos');
|
||||
setExpanded(false);
|
||||
}}
|
||||
/>
|
||||
|
@ -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;
|
||||
|
@ -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<StackParamsList, 'SignMessage'>;
|
||||
|
||||
const SignMessage = ({ route }: SignProps) => {
|
||||
const network = route.params?.selectedNetwork;
|
||||
|
||||
const [message, setMessage] = useState<string>('');
|
||||
|
||||
return (
|
||||
<View style={{ marginTop: 30, paddingHorizontal: 48 }}>
|
||||
<TextInput
|
||||
@ -18,11 +26,13 @@ export default function SignMessage() {
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => {
|
||||
signMessage(message);
|
||||
network && signMessage(network, 0, message);
|
||||
}}>
|
||||
Sign
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SignMessage;
|
||||
|
5
constants.ts
Normal file
5
constants.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const COSMOS_SIGNATURE =
|
||||
'0x56da25d5a9704e0cd685d52ecee5c14bf6637fa2f95653e8499eac4e8285f37b2d9f446c027cac56f3b7840d1b3879ea943415190d7a358cdb3ee05451cdcf7c1c';
|
||||
export const COSMOS_ADDRESS = 'cosmos1sulk9q5fmagur6m3pctmcnfeeku25gp2ectt75';
|
||||
export const COSMOS_PUBKEY =
|
||||
'cosmospub1addwnpepqt9d597c5f6zqqyxy3msrstyc7zl3vyvrl5ku02r4ueuwt5vusw4gmt70dd';
|
14
types.ts
Normal file
14
types.ts
Normal file
@ -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;
|
||||
};
|
56
utils.ts
56
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<HDNode | undefined> => {
|
||||
import { Account, WalletDetails } from './types';
|
||||
|
||||
const generateEthNode = async (): Promise<HDNode | undefined> => {
|
||||
try {
|
||||
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32));
|
||||
const hdNode = HDNode.fromMnemonic(mnemonic);
|
||||
@ -27,16 +28,47 @@ const generateWallet = async (): Promise<HDNode | undefined> => {
|
||||
}
|
||||
};
|
||||
|
||||
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 };
|
||||
|
Loading…
Reference in New Issue
Block a user