forked from cerc-io/laconic-wallet
Refactor code (#18)
* Refactored accounts and sign message component * Change sign message to hyperlink * Refactor network dropdown * Add types to utils * Import react in index.js * Use components for create wallet and reset dialog * Remove inline styles from accounts component * Remove inline styles from components * Remove incorrectly placed async * Make app responsive using flex * Make review changes --------- Co-authored-by: Adw8 <adwait@deepstacksoft.com>
This commit is contained in:
parent
8685c94151
commit
cad0b6fae5
2
App.tsx
2
App.tsx
@ -4,7 +4,7 @@ import { NavigationContainer } from '@react-navigation/native';
|
|||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
|
|
||||||
import SignMessage from './components/SignMessage';
|
import SignMessage from './components/SignMessage';
|
||||||
import { HomeScreen } from './components/HomeScreen';
|
import HomeScreen from './components/HomeScreen';
|
||||||
|
|
||||||
import { StackParamsList } from './types';
|
import { StackParamsList } from './types';
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { View } from 'react-native';
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Button, List, Text } from 'react-native-paper';
|
import { TouchableOpacity, View } from 'react-native';
|
||||||
|
import { Button, List, Text, useTheme } from 'react-native-paper';
|
||||||
|
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
|
|
||||||
import { AccountsProps, StackParamsList, Account } from '../types';
|
import { AccountsProps, StackParamsList, Account } from '../types';
|
||||||
import { addAccount } from '../utils';
|
import { addAccount } from '../utils';
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
const Accounts: React.FC<AccountsProps> = ({
|
const Accounts: React.FC<AccountsProps> = ({
|
||||||
network,
|
network,
|
||||||
@ -20,24 +21,44 @@ const Accounts: React.FC<AccountsProps> = ({
|
|||||||
|
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
const [isAccountCreating, setIsAccountCreating] = useState(false);
|
const [isAccountCreating, setIsAccountCreating] = useState(false);
|
||||||
|
|
||||||
const handlePress = () => setExpanded(!expanded);
|
const handlePress = () => setExpanded(!expanded);
|
||||||
|
|
||||||
const addAccountHandler = async () => {
|
const addAccountHandler = async () => {
|
||||||
setIsAccountCreating(true);
|
setIsAccountCreating(true);
|
||||||
const newAccount = await addAccount(network);
|
const newAccount = await addAccount(network);
|
||||||
setIsAccountCreating(false);
|
setIsAccountCreating(false);
|
||||||
newAccount && updateAccounts(newAccount);
|
setExpanded(false);
|
||||||
updateIndex(selectedAccounts[selectedAccounts.length - 1].id + 1);
|
|
||||||
|
if (newAccount) {
|
||||||
|
updateAccounts(newAccount);
|
||||||
|
updateIndex(selectedAccounts[selectedAccounts.length - 1].id + 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let selectedAccounts: Account[] = [];
|
const selectedAccounts: Account[] = (() => {
|
||||||
|
switch (network) {
|
||||||
|
case 'eth':
|
||||||
|
return accounts.ethAccounts;
|
||||||
|
case 'cosmos':
|
||||||
|
return accounts.cosmosAccounts;
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
if (network === 'eth') {
|
const renderAccountItems = () =>
|
||||||
selectedAccounts = accounts.ethAccounts;
|
selectedAccounts.map(account => (
|
||||||
}
|
<List.Item
|
||||||
if (network === 'cosmos') {
|
key={account.id}
|
||||||
selectedAccounts = accounts.cosmosAccounts;
|
title={`Account ${account.id + 1}`}
|
||||||
}
|
onPress={() => {
|
||||||
|
updateIndex(account.id);
|
||||||
|
setExpanded(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
@ -45,51 +66,43 @@ const Accounts: React.FC<AccountsProps> = ({
|
|||||||
title={`Account ${currentIndex + 1}`}
|
title={`Account ${currentIndex + 1}`}
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
onPress={handlePress}>
|
onPress={handlePress}>
|
||||||
{selectedAccounts &&
|
{renderAccountItems()}
|
||||||
selectedAccounts.map(account => (
|
|
||||||
<List.Item
|
|
||||||
key={account.id}
|
|
||||||
title={`Account ${account.id + 1}`}
|
|
||||||
onPress={() => {
|
|
||||||
updateIndex(account.id);
|
|
||||||
setExpanded(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</List.Accordion>
|
</List.Accordion>
|
||||||
<View style={{ alignItems: 'center', marginTop: 24 }}>
|
|
||||||
|
<View style={styles.addAccountButton}>
|
||||||
<Button
|
<Button
|
||||||
mode="contained"
|
mode="contained"
|
||||||
onPress={addAccountHandler}
|
onPress={addAccountHandler}
|
||||||
loading={isAccountCreating}>
|
loading={isAccountCreating}>
|
||||||
{isAccountCreating ? 'Adding' : 'Add Account'}{' '}
|
{isAccountCreating ? 'Adding' : 'Add Account'}
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
<View style={{ marginTop: 24 }}>
|
|
||||||
|
<View style={styles.accountContainer}>
|
||||||
<Text variant="bodyLarge">
|
<Text variant="bodyLarge">
|
||||||
<Text style={{ fontWeight: '700' }}>Address: </Text>
|
<Text style={styles.highlight}>Address: </Text>
|
||||||
{selectedAccounts &&
|
{selectedAccounts[currentIndex]?.address}
|
||||||
selectedAccounts[currentIndex] &&
|
|
||||||
selectedAccounts[currentIndex].address}
|
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="bodyLarge">
|
<Text variant="bodyLarge">
|
||||||
<Text style={{ fontWeight: '700' }}>Public Key: </Text>
|
<Text style={styles.highlight}>Public Key: </Text>
|
||||||
{selectedAccounts &&
|
{selectedAccounts[currentIndex]?.pubKey}
|
||||||
selectedAccounts[currentIndex] &&
|
|
||||||
selectedAccounts[currentIndex].pubKey}
|
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={{ alignItems: 'center', marginTop: 24 }}>
|
|
||||||
<Button
|
<View style={styles.signLink}>
|
||||||
mode="contained"
|
<TouchableOpacity
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigation.navigate('SignMessage', {
|
navigation.navigate('SignMessage', {
|
||||||
selectedNetwork: network,
|
selectedNetwork: network,
|
||||||
accountInfo: selectedAccounts[currentIndex],
|
accountInfo: selectedAccounts[currentIndex],
|
||||||
});
|
});
|
||||||
}}>
|
}}>
|
||||||
Sign Message
|
<Text
|
||||||
</Button>
|
variant="titleSmall"
|
||||||
|
style={[styles.hyperlink, { color: theme.colors.primary }]}>
|
||||||
|
Sign Message
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
26
components/CreateWallet.tsx
Normal file
26
components/CreateWallet.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { View } from 'react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import { Button } from 'react-native-paper';
|
||||||
|
|
||||||
|
import { CreateWalletProps } from '../types';
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
|
const CreateWallet = ({
|
||||||
|
isWalletCreating,
|
||||||
|
createWalletHandler,
|
||||||
|
}: CreateWalletProps) => {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View style={styles.createWalletContainer}>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
loading={isWalletCreating}
|
||||||
|
onPress={createWalletHandler}>
|
||||||
|
{isWalletCreating ? 'Creating' : 'Create Wallet'}
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CreateWallet;
|
@ -1,12 +1,15 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Alert, ScrollView, View } from 'react-native';
|
import { Alert, View } from 'react-native';
|
||||||
import { Text, Button, Dialog, Portal } from 'react-native-paper';
|
import { Button } from 'react-native-paper';
|
||||||
|
|
||||||
import { createWallet, resetWallet } from '../utils';
|
import { createWallet, resetWallet } from '../utils';
|
||||||
import { DialogComponent } from './Dialog';
|
import { DialogComponent } from './Dialog';
|
||||||
import { NetworkDropdown } from './NetworkDropdown';
|
import { NetworkDropdown } from './NetworkDropdown';
|
||||||
import { Account, AccountsState } from '../types';
|
import { Account, AccountsState } from '../types';
|
||||||
import Accounts from './Accounts';
|
import Accounts from './Accounts';
|
||||||
|
import CreateWallet from './CreateWallet';
|
||||||
|
import ResetWalletDialog from './ResetWalletDialog';
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
const HomeScreen = () => {
|
const HomeScreen = () => {
|
||||||
const [isWalletCreated, setIsWalletCreated] = useState<boolean>(false);
|
const [isWalletCreated, setIsWalletCreated] = useState<boolean>(false);
|
||||||
@ -27,12 +30,12 @@ const HomeScreen = () => {
|
|||||||
const createWalletHandler = async () => {
|
const createWalletHandler = async () => {
|
||||||
setIsWalletCreating(true);
|
setIsWalletCreating(true);
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
const { ethWalletInfo, cosmosWalletInfo } = await createWallet();
|
const { ethAccounts, cosmosAccounts } = await createWallet();
|
||||||
ethWalletInfo &&
|
ethAccounts &&
|
||||||
cosmosWalletInfo &&
|
cosmosAccounts &&
|
||||||
setAccounts({
|
setAccounts({
|
||||||
ethAccounts: [...accounts.ethAccounts, ethWalletInfo],
|
ethAccounts: [...accounts.ethAccounts, ethAccounts],
|
||||||
cosmosAccounts: [...accounts.cosmosAccounts, cosmosWalletInfo],
|
cosmosAccounts: [...accounts.cosmosAccounts, cosmosAccounts],
|
||||||
});
|
});
|
||||||
setWalletDialog(true);
|
setWalletDialog(true);
|
||||||
setIsWalletCreated(true);
|
setIsWalletCreated(true);
|
||||||
@ -79,64 +82,53 @@ const HomeScreen = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<ScrollView style={{ marginTop: 24, paddingHorizontal: 24 }}>
|
<View style={styles.appContainer}>
|
||||||
<DialogComponent
|
<DialogComponent
|
||||||
visible={walletDialog}
|
visible={walletDialog}
|
||||||
hideDialog={hideWalletDialog}
|
hideDialog={hideWalletDialog}
|
||||||
contentText="Wallet created"
|
contentText="Wallet created"
|
||||||
/>
|
/>
|
||||||
<Portal>
|
<ResetWalletDialog
|
||||||
<Dialog visible={resetWalletDialog} onDismiss={hideResetDialog}>
|
visible={resetWalletDialog}
|
||||||
<Dialog.Title>Reset Wallet</Dialog.Title>
|
hideDialog={hideResetDialog}
|
||||||
<Dialog.Content>
|
onConfirm={confirmResetWallet}
|
||||||
<Text variant="bodyMedium">Are you sure?</Text>
|
/>
|
||||||
</Dialog.Content>
|
|
||||||
<Dialog.Actions>
|
|
||||||
<Button textColor="red" onPress={confirmResetWallet}>
|
|
||||||
Yes
|
|
||||||
</Button>
|
|
||||||
<Button onPress={hideResetDialog}>No</Button>
|
|
||||||
</Dialog.Actions>
|
|
||||||
</Dialog>
|
|
||||||
</Portal>
|
|
||||||
{isWalletCreated ? (
|
{isWalletCreated ? (
|
||||||
<View>
|
<>
|
||||||
<NetworkDropdown
|
<NetworkDropdown
|
||||||
selectedNetwork={network}
|
selectedNetwork={network}
|
||||||
updateNetwork={updateNetwork}
|
updateNetwork={updateNetwork}
|
||||||
/>
|
/>
|
||||||
<Accounts
|
<View style={styles.accountComponent}>
|
||||||
network={network}
|
<Accounts
|
||||||
accounts={accounts}
|
network={network}
|
||||||
currentIndex={currentIndex}
|
accounts={accounts}
|
||||||
updateIndex={updateIndex}
|
currentIndex={currentIndex}
|
||||||
updateAccounts={updateAccounts}
|
updateIndex={updateIndex}
|
||||||
/>
|
updateAccounts={updateAccounts}
|
||||||
<View style={{ marginTop: 200, alignSelf: 'center' }}>
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.resetContainer}>
|
||||||
<Button
|
<Button
|
||||||
|
style={styles.resetButton}
|
||||||
mode="contained"
|
mode="contained"
|
||||||
buttonColor="#B82B0D"
|
buttonColor="#B82B0D"
|
||||||
onPress={async () => {
|
onPress={() => {
|
||||||
setResetWalletDialog(true);
|
setResetWalletDialog(true);
|
||||||
}}>
|
}}>
|
||||||
Reset Wallet
|
Reset Wallet
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<View>
|
<CreateWallet
|
||||||
<View style={{ marginTop: 20, width: 150, alignSelf: 'center' }}>
|
isWalletCreating={isWalletCreating}
|
||||||
<Button
|
createWalletHandler={createWalletHandler}
|
||||||
mode="contained"
|
/>
|
||||||
loading={isWalletCreating}
|
|
||||||
onPress={createWalletHandler}>
|
|
||||||
{isWalletCreating ? 'Creating' : 'Create Wallet'}{' '}
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { HomeScreen };
|
export default HomeScreen;
|
||||||
|
@ -3,38 +3,41 @@ import { View } from 'react-native';
|
|||||||
import { List } from 'react-native-paper';
|
import { List } from 'react-native-paper';
|
||||||
|
|
||||||
import { NetworkDropdownProps } from '../types';
|
import { NetworkDropdownProps } from '../types';
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
const NetworkDropdown: React.FC<NetworkDropdownProps> = ({ updateNetwork }) => {
|
const NetworkDropdown: React.FC<NetworkDropdownProps> = ({ updateNetwork }) => {
|
||||||
const [expanded, setExpanded] = useState<boolean>(false);
|
const [expanded, setExpanded] = useState<boolean>(false);
|
||||||
const [title, setTitle] = useState<string>('Ethereum');
|
const [selectedNetwork, setSelectedNetwork] = useState<string>('Ethereum');
|
||||||
|
|
||||||
const expandNetworks = () => setExpanded(!expanded);
|
const handleNetworkPress = (network: string, displayName: string) => {
|
||||||
|
updateNetwork(network);
|
||||||
|
setSelectedNetwork(displayName);
|
||||||
|
setExpanded(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ marginBottom: 20 }}>
|
<View style={styles.networkDropdown}>
|
||||||
<List.Accordion
|
<List.Accordion
|
||||||
title={title}
|
title={selectedNetwork}
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
onPress={expandNetworks}>
|
onPress={() => setExpanded(!expanded)}>
|
||||||
<List.Item
|
{networks.map(network => (
|
||||||
title="Ethereum"
|
<List.Item
|
||||||
onPress={() => {
|
key={network.value}
|
||||||
updateNetwork('eth');
|
title={network.displayName}
|
||||||
setTitle('Ethereum');
|
onPress={() =>
|
||||||
setExpanded(false);
|
handleNetworkPress(network.value, network.displayName)
|
||||||
}}
|
}
|
||||||
/>
|
/>
|
||||||
<List.Item
|
))}
|
||||||
title="Cosmos"
|
|
||||||
onPress={() => {
|
|
||||||
updateNetwork('cosmos');
|
|
||||||
setTitle('Cosmos');
|
|
||||||
setExpanded(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</List.Accordion>
|
</List.Accordion>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const networks = [
|
||||||
|
{ value: 'eth', displayName: 'Ethereum' },
|
||||||
|
{ value: 'cosmos', displayName: 'Cosmos' },
|
||||||
|
];
|
||||||
|
|
||||||
export { NetworkDropdown };
|
export { NetworkDropdown };
|
||||||
|
28
components/ResetWalletDialog.tsx
Normal file
28
components/ResetWalletDialog.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Portal, Dialog, Button, Text } from 'react-native-paper';
|
||||||
|
import { ResetDialogProps } from '../types';
|
||||||
|
|
||||||
|
const ResetWalletDialog = ({
|
||||||
|
visible,
|
||||||
|
hideDialog,
|
||||||
|
onConfirm,
|
||||||
|
}: ResetDialogProps) => {
|
||||||
|
return (
|
||||||
|
<Portal>
|
||||||
|
<Dialog visible={visible} onDismiss={hideDialog}>
|
||||||
|
<Dialog.Title>Reset Wallet</Dialog.Title>
|
||||||
|
<Dialog.Content>
|
||||||
|
<Text variant="bodyMedium">Are you sure?</Text>
|
||||||
|
</Dialog.Content>
|
||||||
|
<Dialog.Actions>
|
||||||
|
<Button textColor="red" onPress={onConfirm}>
|
||||||
|
Yes
|
||||||
|
</Button>
|
||||||
|
<Button onPress={hideDialog}>No</Button>
|
||||||
|
</Dialog.Actions>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResetWalletDialog;
|
@ -1,29 +0,0 @@
|
|||||||
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 (
|
|
||||||
<View style={styles.sectionContainer}>
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.sectionTitle,
|
|
||||||
{
|
|
||||||
color: isDarkMode ? Colors.white : Colors.black,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{title}
|
|
||||||
<Text style={styles.sectionDescription} />
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { Section };
|
|
@ -6,6 +6,7 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|||||||
|
|
||||||
import { StackParamsList } from '../types';
|
import { StackParamsList } from '../types';
|
||||||
import { signMessage } from '../utils';
|
import { signMessage } from '../utils';
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
type SignProps = NativeStackScreenProps<StackParamsList, 'SignMessage'>;
|
type SignProps = NativeStackScreenProps<StackParamsList, 'SignMessage'>;
|
||||||
|
|
||||||
@ -20,30 +21,43 @@ const SignMessage = ({ route }: SignProps) => {
|
|||||||
if (!account) {
|
if (!account) {
|
||||||
throw new Error('Account is not valid');
|
throw new Error('Account is not valid');
|
||||||
}
|
}
|
||||||
const signedMessage = await signMessage(message, network, account.id);
|
const signedMessage = await signMessage({
|
||||||
|
message,
|
||||||
|
network,
|
||||||
|
accountId: account.id,
|
||||||
|
});
|
||||||
Alert.alert('Signature', signedMessage);
|
Alert.alert('Signature', signedMessage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={{ marginTop: 24, paddingHorizontal: 24 }}>
|
<ScrollView style={styles.signPage}>
|
||||||
<View style={{ marginTop: 24, marginBottom: 30 }}>
|
<View style={styles.accountInfo}>
|
||||||
<Text variant="bodyLarge">
|
<View>
|
||||||
<Text style={{ fontWeight: '700' }}>Address: </Text>
|
<Text variant="headlineSmall">
|
||||||
{account && account.address}
|
{account && `Account ${account.id + 1}`}
|
||||||
</Text>
|
</Text>
|
||||||
<Text variant="bodyLarge">
|
</View>
|
||||||
<Text style={{ fontWeight: '700' }}>Public Key: </Text>
|
<View style={styles.accountContainer}>
|
||||||
{account && account.pubKey}
|
<Text variant="bodyLarge">
|
||||||
</Text>
|
<Text style={styles.highlight}>Address: </Text>
|
||||||
|
{account?.address}
|
||||||
|
</Text>
|
||||||
|
<Text variant="bodyLarge">
|
||||||
|
<Text style={styles.highlight}>Public Key: </Text>
|
||||||
|
{account?.pubKey}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
mode="outlined"
|
mode="outlined"
|
||||||
placeholder="Enter your message"
|
placeholder="Enter your message"
|
||||||
onChangeText={text => setMessage(text)}
|
onChangeText={text => setMessage(text)}
|
||||||
value={message}
|
value={message}
|
||||||
/>
|
/>
|
||||||
<View style={{ marginTop: 20, width: 150, alignSelf: 'center' }}>
|
|
||||||
|
<View style={styles.signButton}>
|
||||||
<Button mode="contained" onPress={signMessageHandler}>
|
<Button mode="contained" onPress={signMessageHandler}>
|
||||||
Sign
|
Sign
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
export const COSMOS_SIGNATURE =
|
|
||||||
'0x56da25d5a9704e0cd685d52ecee5c14bf6637fa2f95653e8499eac4e8285f37b2d9f446c027cac56f3b7840d1b3879ea943415190d7a358cdb3ee05451cdcf7c1c';
|
|
||||||
export const COSMOS_ADDRESS = 'cosmos1sulk9q5fmagur6m3pctmcnfeeku25gp2ectt75';
|
|
||||||
export const COSMOS_PUBKEY =
|
|
||||||
'cosmospub1addwnpepqt9d597c5f6zqqyxy3msrstyc7zl3vyvrl5ku02r4ueuwt5vusw4gmt70dd';
|
|
1
index.js
1
index.js
@ -1,3 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
import 'text-encoding-polyfill';
|
import 'text-encoding-polyfill';
|
||||||
import { AppRegistry } from 'react-native';
|
import { AppRegistry } from 'react-native';
|
||||||
import { PaperProvider } from 'react-native-paper';
|
import { PaperProvider } from 'react-native-paper';
|
||||||
|
@ -1,32 +1,59 @@
|
|||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
headerContainer: {
|
createWalletContainer: {
|
||||||
padding: 15,
|
marginTop: 20,
|
||||||
alignItems: 'center',
|
width: 150,
|
||||||
justifyContent: 'center',
|
alignSelf: 'center',
|
||||||
},
|
},
|
||||||
headerText: {
|
signLink: {
|
||||||
color: 'black',
|
alignItems: 'flex-end',
|
||||||
fontSize: 26,
|
marginTop: 24,
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
},
|
||||||
sectionContainer: {
|
hyperlink: {
|
||||||
marginTop: 32,
|
fontWeight: '500',
|
||||||
paddingHorizontal: 24,
|
textDecorationLine: 'underline',
|
||||||
},
|
|
||||||
sectionTitle: {
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: '600',
|
|
||||||
},
|
|
||||||
sectionDescription: {
|
|
||||||
marginTop: 8,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: '400',
|
|
||||||
},
|
},
|
||||||
highlight: {
|
highlight: {
|
||||||
fontWeight: '700',
|
fontWeight: '700',
|
||||||
},
|
},
|
||||||
|
accountContainer: {
|
||||||
|
marginTop: 24,
|
||||||
|
},
|
||||||
|
addAccountButton: {
|
||||||
|
marginTop: 24,
|
||||||
|
alignSelf: 'center',
|
||||||
|
},
|
||||||
|
accountComponent: {
|
||||||
|
flex: 4,
|
||||||
|
},
|
||||||
|
appContainer: {
|
||||||
|
flexGrow: 1,
|
||||||
|
marginTop: 24,
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
},
|
||||||
|
resetContainer: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
resetButton: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
},
|
||||||
|
signButton: {
|
||||||
|
marginTop: 20,
|
||||||
|
width: 150,
|
||||||
|
alignSelf: 'center',
|
||||||
|
},
|
||||||
|
signPage: {
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
},
|
||||||
|
accountInfo: {
|
||||||
|
marginTop: 24,
|
||||||
|
marginBottom: 30,
|
||||||
|
},
|
||||||
|
networkDropdown: {
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default styles;
|
export default styles;
|
||||||
|
21
types.ts
21
types.ts
@ -10,8 +10,8 @@ export type Account = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type WalletDetails = {
|
export type WalletDetails = {
|
||||||
ethAccount: Account;
|
ethAccounts: Account | undefined;
|
||||||
cosmosAccount: Account;
|
cosmosAccounts: Account | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AccountsProps = {
|
export type AccountsProps = {
|
||||||
@ -34,3 +34,20 @@ export type AccountsState = {
|
|||||||
ethAccounts: Account[];
|
ethAccounts: Account[];
|
||||||
cosmosAccounts: Account[];
|
cosmosAccounts: Account[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SignMessageParams = {
|
||||||
|
message: string;
|
||||||
|
network: string;
|
||||||
|
accountId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateWalletProps = {
|
||||||
|
isWalletCreating: boolean;
|
||||||
|
createWalletHandler: () => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ResetDialogProps = {
|
||||||
|
visible: boolean;
|
||||||
|
hideDialog: () => void;
|
||||||
|
onConfirm: () => void;
|
||||||
|
};
|
||||||
|
42
utils.ts
42
utils.ts
@ -14,10 +14,9 @@ import {
|
|||||||
import { AccountData, Secp256k1HdWallet } from '@cosmjs/amino';
|
import { AccountData, Secp256k1HdWallet } from '@cosmjs/amino';
|
||||||
import { stringToPath } from '@cosmjs/crypto';
|
import { stringToPath } from '@cosmjs/crypto';
|
||||||
|
|
||||||
const createWallet = async (): Promise<{
|
import { Account, SignMessageParams, WalletDetails } from './types';
|
||||||
ethWalletInfo: { id: number; pubKey: string; address: string } | undefined;
|
|
||||||
cosmosWalletInfo: { id: number; pubKey: string; address: string } | undefined;
|
const createWallet = async (): Promise<WalletDetails> => {
|
||||||
}> => {
|
|
||||||
try {
|
try {
|
||||||
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32));
|
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(32));
|
||||||
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
|
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
|
||||||
@ -43,35 +42,26 @@ const createWallet = async (): Promise<{
|
|||||||
await setInternetCredentials('eth:accountIndices', 'ethAccount', '0');
|
await setInternetCredentials('eth:accountIndices', 'ethAccount', '0');
|
||||||
await setInternetCredentials('cosmos:accountIndices', 'cosmosAccount', '0');
|
await setInternetCredentials('cosmos:accountIndices', 'cosmosAccount', '0');
|
||||||
|
|
||||||
const ethWalletInfo = {
|
const ethAccounts = {
|
||||||
id: 0,
|
id: 0,
|
||||||
pubKey: ethNode.publicKey,
|
pubKey: ethNode.publicKey,
|
||||||
address: ethAddress,
|
address: ethAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
const cosmosWalletInfo = {
|
const cosmosAccounts = {
|
||||||
id: 0,
|
id: 0,
|
||||||
pubKey: cosmosNode.publicKey,
|
pubKey: cosmosNode.publicKey,
|
||||||
address: cosmosAddress,
|
address: cosmosAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ethWalletInfo, cosmosWalletInfo };
|
return { ethAccounts, cosmosAccounts };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating HD wallet:', error);
|
console.error('Error creating HD wallet:', error);
|
||||||
return { ethWalletInfo: undefined, cosmosWalletInfo: undefined };
|
return { ethAccounts: undefined, cosmosAccounts: undefined };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const addAccount = async (
|
const addAccount = async (network: string): Promise<Account | undefined> => {
|
||||||
network: string,
|
|
||||||
): Promise<
|
|
||||||
| {
|
|
||||||
pubKey: string;
|
|
||||||
address: string;
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
> => {
|
|
||||||
try {
|
try {
|
||||||
const mnemonicStore = await getInternetCredentials('mnemonicServer');
|
const mnemonicStore = await getInternetCredentials('mnemonicServer');
|
||||||
if (!mnemonicStore) {
|
if (!mnemonicStore) {
|
||||||
@ -138,16 +128,16 @@ const addAccount = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const signMessage = async (
|
const signMessage = async ({
|
||||||
message: string,
|
message,
|
||||||
walletType: string,
|
network,
|
||||||
id: number,
|
accountId,
|
||||||
): Promise<string | undefined> => {
|
}: SignMessageParams): Promise<string | undefined> => {
|
||||||
switch (walletType) {
|
switch (network) {
|
||||||
case 'eth':
|
case 'eth':
|
||||||
return await signEthMessage(message, id);
|
return await signEthMessage(message, accountId);
|
||||||
case 'cosmos':
|
case 'cosmos':
|
||||||
return await signCosmosMessage(message, id);
|
return await signCosmosMessage(message, accountId);
|
||||||
default:
|
default:
|
||||||
throw new Error('Invalid wallet type');
|
throw new Error('Invalid wallet type');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user