forked from cerc-io/laconic-wallet
Generate wallet and sign message (#4)
* Store mnemonic and private key seperately * Change variable names * Refactor code in seperate components * Display wallet details * Remove unnecessary imports * Make review changes * Add method to reset wallet * Make component self closing * separate imports --------- Co-authored-by: Adw8 <adwait@deepstacksoft.com>
This commit is contained in:
parent
5dd97e3860
commit
3d40de966d
99
App.tsx
99
App.tsx
@ -12,48 +12,24 @@ import {
|
|||||||
View,
|
View,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { Colors } from 'react-native/Libraries/NewAppScreen';
|
import { Colors } from 'react-native/Libraries/NewAppScreen';
|
||||||
|
import { HDNode } from 'ethers/lib/utils';
|
||||||
|
|
||||||
|
import { generateWallet, resetWallet, signMessage } from './utils';
|
||||||
import styles from './styles/stylesheet';
|
import styles from './styles/stylesheet';
|
||||||
import { generateWallet, signMessage } from './utils';
|
import { Section } from './components/Section';
|
||||||
|
|
||||||
type SectionProps = PropsWithChildren<{
|
|
||||||
title: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
const Section = ({children, title}: SectionProps): React.JSX.Element => {
|
|
||||||
const isDarkMode = useColorScheme() === 'dark';
|
|
||||||
return (
|
|
||||||
<View style={styles.sectionContainer}>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.sectionTitle,
|
|
||||||
{
|
|
||||||
color: isDarkMode ? Colors.white : Colors.black,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.sectionDescription,
|
|
||||||
{
|
|
||||||
color: isDarkMode ? Colors.light : Colors.dark,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const App = (): React.JSX.Element => {
|
const App = (): React.JSX.Element => {
|
||||||
const [message, setMessage] = useState('');
|
const [message, setMessage] = useState('');
|
||||||
const [isWalletCreated, setIsWalletCreated] = useState(false);
|
const [isWalletCreated, setIsWalletCreated] = useState<boolean>(false);
|
||||||
|
const [wallet, setWallet] = useState<HDNode | null>();
|
||||||
|
|
||||||
const createWallet = async () => {
|
const createWallet = async () => {
|
||||||
Alert.alert('Creating Wallet...');
|
Alert.alert('Creating Wallet...');
|
||||||
await generateWallet();
|
const wallet = await generateWallet();
|
||||||
|
if (wallet) {
|
||||||
|
setWallet(wallet);
|
||||||
setIsWalletCreated(true);
|
setIsWalletCreated(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isDarkMode = useColorScheme() === 'dark';
|
const isDarkMode = useColorScheme() === 'dark';
|
||||||
@ -81,23 +57,16 @@ const App = (): React.JSX.Element => {
|
|||||||
<View>
|
<View>
|
||||||
{isWalletCreated ? (
|
{isWalletCreated ? (
|
||||||
<View>
|
<View>
|
||||||
<Section title="Generate Wallet">Wallet Created! </Section>
|
<Section title="Wallet Details" />
|
||||||
</View>
|
<View style={{ marginTop: 32, paddingHorizontal: 24 }}>
|
||||||
) : (
|
<Text style={{ fontSize: 16, color: 'black' }}>
|
||||||
<View>
|
Address: {wallet && wallet.address.toString()}
|
||||||
<Section title="Generate Wallet">
|
</Text>
|
||||||
Click the button to generate the wallet
|
<Text style={{ fontSize: 16, color: 'black' }}>
|
||||||
</Section>
|
Public Key: {wallet && wallet.publicKey.toString()}
|
||||||
<View style={{marginTop: 20, width: 150, alignSelf: 'center'}}>
|
</Text>
|
||||||
<Button
|
|
||||||
title="Initialise Wallet"
|
|
||||||
color="#841584"
|
|
||||||
onPress={createWallet}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
|
<Section title="Sign a message" />
|
||||||
<View>
|
<View>
|
||||||
<TextInput
|
<TextInput
|
||||||
style={{
|
style={{
|
||||||
@ -111,7 +80,8 @@ const App = (): React.JSX.Element => {
|
|||||||
onChangeText={text => setMessage(text)}
|
onChangeText={text => setMessage(text)}
|
||||||
value={message}
|
value={message}
|
||||||
/>
|
/>
|
||||||
<View style={{marginTop: 20, width: 150, alignSelf: 'center'}}>
|
<View
|
||||||
|
style={{ marginTop: 20, width: 150, alignSelf: 'center' }}>
|
||||||
<Button
|
<Button
|
||||||
title="Sign Message"
|
title="Sign Message"
|
||||||
color="#841584"
|
color="#841584"
|
||||||
@ -121,6 +91,35 @@ const App = (): React.JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<Section title="" />
|
||||||
|
<View>
|
||||||
|
<View
|
||||||
|
style={{ marginTop: 20, width: 150, alignSelf: 'center' }}>
|
||||||
|
<Button
|
||||||
|
title="Reset Wallet"
|
||||||
|
color="#D30000"
|
||||||
|
onPress={async () => {
|
||||||
|
await resetWallet();
|
||||||
|
setIsWalletCreated(false);
|
||||||
|
setWallet(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View>
|
||||||
|
<Section title="Create Wallet" />
|
||||||
|
<View style={{ marginTop: 20, width: 150, alignSelf: 'center' }}>
|
||||||
|
<Button
|
||||||
|
title="Create"
|
||||||
|
color="#841584"
|
||||||
|
onPress={createWallet}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
23
components/Header.tsx
Normal file
23
components/Header.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { View, Text, useColorScheme } from 'react-native';
|
||||||
|
import { Colors } from 'react-native/Libraries/NewAppScreen';
|
||||||
|
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
const isDarkMode = useColorScheme() === 'dark';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.headerContainer}>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.headerText,
|
||||||
|
{color: isDarkMode ? Colors.light : Colors.dark},
|
||||||
|
]}>
|
||||||
|
Laconic Wallet
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Header };
|
29
components/Section.tsx
Normal file
29
components/Section.tsx
Normal file
@ -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 = ({ children, title }: SectionProps): React.JSX.Element => {
|
||||||
|
const isDarkMode = useColorScheme() === 'dark';
|
||||||
|
return (
|
||||||
|
<View style={styles.sectionContainer}>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.sectionTitle,
|
||||||
|
{
|
||||||
|
color: isDarkMode ? Colors.white : Colors.black,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
{title}
|
||||||
|
<Text style={styles.sectionDescription} />
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Section };
|
@ -8,7 +8,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
headerText: {
|
headerText: {
|
||||||
color: 'black',
|
color: 'black',
|
||||||
fontSize: 22,
|
fontSize: 26,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
sectionContainer: {
|
sectionContainer: {
|
||||||
@ -16,7 +16,7 @@ const styles = StyleSheet.create({
|
|||||||
paddingHorizontal: 24,
|
paddingHorizontal: 24,
|
||||||
},
|
},
|
||||||
sectionTitle: {
|
sectionTitle: {
|
||||||
fontSize: 24,
|
fontSize: 22,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
},
|
},
|
||||||
sectionDescription: {
|
sectionDescription: {
|
||||||
|
29
utils.ts
29
utils.ts
@ -3,14 +3,22 @@ import '@ethersproject/shims';
|
|||||||
import { Wallet, utils } from 'ethers';
|
import { Wallet, utils } from 'ethers';
|
||||||
import { HDNode } from 'ethers/lib/utils';
|
import { HDNode } from 'ethers/lib/utils';
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import { getGenericPassword, setGenericPassword } from 'react-native-keychain';
|
import {
|
||||||
|
setInternetCredentials,
|
||||||
|
getInternetCredentials,
|
||||||
|
resetInternetCredentials,
|
||||||
|
} from 'react-native-keychain';
|
||||||
|
|
||||||
const generateWallet = async () => {
|
const generateWallet = async (): Promise<HDNode | undefined> => {
|
||||||
try {
|
try {
|
||||||
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32));
|
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32));
|
||||||
const hdNode = HDNode.fromMnemonic(mnemonic);
|
const hdNode = HDNode.fromMnemonic(mnemonic);
|
||||||
await setGenericPassword(mnemonic, hdNode.privateKey);
|
|
||||||
Alert.alert('Wallet stored successfully with address:', hdNode.address);
|
await setInternetCredentials('keyServer', 'key', hdNode.privateKey);
|
||||||
|
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
|
||||||
|
|
||||||
|
Alert.alert('Wallet created successfully ');
|
||||||
|
return hdNode;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating wallet ', error);
|
console.error('Error creating wallet ', error);
|
||||||
}
|
}
|
||||||
@ -18,11 +26,11 @@ const generateWallet = async () => {
|
|||||||
|
|
||||||
const signMessage = async (message: string) => {
|
const signMessage = async (message: string) => {
|
||||||
try {
|
try {
|
||||||
const creds = await getGenericPassword();
|
const keyCred = await getInternetCredentials('keyServer');
|
||||||
const wallet = creds && new Wallet(creds.password);
|
const wallet = keyCred && new Wallet(keyCred.password);
|
||||||
const signature = wallet && (await wallet.signMessage(message));
|
const signature = wallet && (await wallet.signMessage(message));
|
||||||
if (typeof signature === 'string') {
|
if (typeof signature === 'string') {
|
||||||
Alert.alert('Message signed successfully with signature', signature);
|
Alert.alert('Message signature: ', signature);
|
||||||
} else {
|
} else {
|
||||||
Alert.alert('Message signing failed. Please try again.');
|
Alert.alert('Message signing failed. Please try again.');
|
||||||
}
|
}
|
||||||
@ -31,4 +39,9 @@ const signMessage = async (message: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { generateWallet, signMessage };
|
const resetWallet = async () => {
|
||||||
|
await resetInternetCredentials('keyServer');
|
||||||
|
await resetInternetCredentials('mnemonicServer');
|
||||||
|
};
|
||||||
|
|
||||||
|
export { generateWallet, signMessage, resetWallet };
|
||||||
|
Loading…
Reference in New Issue
Block a user