forked from cerc-io/laconic-wallet
Compare commits
1 Commits
main
...
iv-import-
Author | SHA1 | Date | |
---|---|---|---|
|
899cb90d40 |
@ -1,5 +1,5 @@
|
|||||||
import { View } from 'react-native';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { View } from 'react-native';
|
||||||
import { Button } from 'react-native-paper';
|
import { Button } from 'react-native-paper';
|
||||||
|
|
||||||
import { CreateWalletProps } from '../types';
|
import { CreateWalletProps } from '../types';
|
||||||
|
60
src/components/ImportWalletDialog.tsx
Normal file
60
src/components/ImportWalletDialog.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { View, TextInput } from 'react-native';
|
||||||
|
import { Dialog, Portal, Paragraph, Button } from 'react-native-paper';
|
||||||
|
|
||||||
|
import styles from '../styles/stylesheet';
|
||||||
|
|
||||||
|
const ImportWalletDialog = ({
|
||||||
|
visible,
|
||||||
|
hideDialog,
|
||||||
|
importWalletHandler,
|
||||||
|
}: {
|
||||||
|
visible: boolean;
|
||||||
|
hideDialog: () => void;
|
||||||
|
importWalletHandler: (recoveryPhrase: string) => Promise<void>;
|
||||||
|
}) => {
|
||||||
|
const [words, setWords] = useState<string[]>(Array(12).fill(''));
|
||||||
|
|
||||||
|
const handleWordChange = (index: number, value: string) => {
|
||||||
|
const newWords = [...words];
|
||||||
|
newWords[index] = value;
|
||||||
|
setWords(newWords);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Portal>
|
||||||
|
<Dialog visible={visible} onDismiss={hideDialog}>
|
||||||
|
<Dialog.Title>Import your wallet from your mnemonic</Dialog.Title>
|
||||||
|
<Dialog.Content>
|
||||||
|
<Paragraph>
|
||||||
|
(You can paste your entire mnemonic into the first textbox)
|
||||||
|
</Paragraph>
|
||||||
|
<View style={styles.container}>
|
||||||
|
{words.map((word, index) => (
|
||||||
|
<View style={styles.inputContainer} key={index}>
|
||||||
|
<TextInput
|
||||||
|
value={word}
|
||||||
|
onChangeText={text => handleWordChange(index, text)}
|
||||||
|
placeholder={`Word ${index + 1}`}
|
||||||
|
style={styles.textInput}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</Dialog.Content>
|
||||||
|
<Dialog.Actions>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => importWalletHandler(words.join(' '))}>
|
||||||
|
Import Wallet
|
||||||
|
</Button>
|
||||||
|
<Button mode="text" onPress={hideDialog}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</Dialog.Actions>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImportWalletDialog;
|
@ -8,7 +8,7 @@ import styles from '../styles/stylesheet';
|
|||||||
import GridView from './Grid';
|
import GridView from './Grid';
|
||||||
import { CustomDialogProps } from '../types';
|
import { CustomDialogProps } from '../types';
|
||||||
|
|
||||||
const DialogComponent = ({
|
const MnemonicDialog = ({
|
||||||
visible,
|
visible,
|
||||||
hideDialog,
|
hideDialog,
|
||||||
contentText,
|
contentText,
|
||||||
@ -55,4 +55,4 @@ const DialogComponent = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { DialogComponent };
|
export { MnemonicDialog };
|
@ -1,16 +1,15 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { Image, ScrollView, View } from 'react-native';
|
import { Image, ScrollView, View } from 'react-native';
|
||||||
import { Button, Text, TextInput } from 'react-native-paper';
|
import { Button, Text, TextInput } from 'react-native-paper';
|
||||||
import { SvgUri } from 'react-native-svg';
|
import { SvgUri } from 'react-native-svg';
|
||||||
import Config from 'react-native-config';
|
import Config from 'react-native-config';
|
||||||
import { MsgCreateValidator } from 'cosmjs-types/cosmos/staking/v1beta1/tx';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NativeStackNavigationProp,
|
NativeStackNavigationProp,
|
||||||
NativeStackScreenProps,
|
NativeStackScreenProps,
|
||||||
} from '@react-navigation/native-stack';
|
} from '@react-navigation/native-stack';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { DirectSecp256k1Wallet, EncodeObject } from '@cosmjs/proto-signing';
|
import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing';
|
||||||
import { LaconicClient } from '@cerc-io/registry-sdk';
|
import { LaconicClient } from '@cerc-io/registry-sdk';
|
||||||
import { GasPrice, calculateFee } from '@cosmjs/stargate';
|
import { GasPrice, calculateFee } from '@cosmjs/stargate';
|
||||||
import { formatJsonRpcError } from '@json-rpc-tools/utils';
|
import { formatJsonRpcError } from '@json-rpc-tools/utils';
|
||||||
@ -43,6 +42,7 @@ const ApproveTransaction = ({ route }: ApproveTransactionProps) => {
|
|||||||
const requestName = requestSession.peer.metadata.name;
|
const requestName = requestSession.peer.metadata.name;
|
||||||
const requestIcon = requestSession.peer.metadata.icons[0];
|
const requestIcon = requestSession.peer.metadata.icons[0];
|
||||||
const requestURL = requestSession.peer.metadata.url;
|
const requestURL = requestSession.peer.metadata.url;
|
||||||
|
const transactionMessage = route.params.transactionMessage;
|
||||||
const signer = route.params.signer;
|
const signer = route.params.signer;
|
||||||
const requestEvent = route.params.requestEvent;
|
const requestEvent = route.params.requestEvent;
|
||||||
const chainId = requestEvent.params.chainId;
|
const chainId = requestEvent.params.chainId;
|
||||||
@ -69,20 +69,6 @@ const ApproveTransaction = ({ route }: ApproveTransactionProps) => {
|
|||||||
);
|
);
|
||||||
const namespace = requestedNetwork!.namespace;
|
const namespace = requestedNetwork!.namespace;
|
||||||
|
|
||||||
const transactionMessage = useMemo((): EncodeObject => {
|
|
||||||
const inputTxMsg = route.params.transactionMessage;
|
|
||||||
|
|
||||||
// If it's a MsgCreateValidator, decode the tx msg value using MsgCreateValidator type
|
|
||||||
if (inputTxMsg.typeUrl.includes('MsgCreateValidator')) {
|
|
||||||
return {
|
|
||||||
typeUrl: inputTxMsg.typeUrl,
|
|
||||||
value: MsgCreateValidator.fromJSON(inputTxMsg.value),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputTxMsg;
|
|
||||||
}, [route.params.transactionMessage]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (namespace !== COSMOS) {
|
if (namespace !== COSMOS) {
|
||||||
return;
|
return;
|
||||||
@ -158,7 +144,7 @@ const ApproveTransaction = ({ route }: ApproveTransactionProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const gasEstimation = await cosmosStargateClient!.simulate(
|
const gasEstimation = await cosmosStargateClient!.simulate(
|
||||||
signer,
|
transactionMessage.value.participant!,
|
||||||
[transactionMessage],
|
[transactionMessage],
|
||||||
MEMO,
|
MEMO,
|
||||||
);
|
);
|
||||||
@ -182,7 +168,6 @@ const ApproveTransaction = ({ route }: ApproveTransactionProps) => {
|
|||||||
requestEventId,
|
requestEventId,
|
||||||
topic,
|
topic,
|
||||||
web3wallet,
|
web3wallet,
|
||||||
signer,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -258,13 +243,6 @@ const ApproveTransaction = ({ route }: ApproveTransactionProps) => {
|
|||||||
navigation.navigate('Laconic');
|
navigation.navigate('Laconic');
|
||||||
};
|
};
|
||||||
|
|
||||||
const replacer = (key: string, value: any): any => {
|
|
||||||
if (value instanceof Uint8Array) {
|
|
||||||
return Buffer.from(value).toString('hex');
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ScrollView contentContainerStyle={styles.approveTransaction}>
|
<ScrollView contentContainerStyle={styles.approveTransaction}>
|
||||||
@ -289,7 +267,7 @@ const ApproveTransaction = ({ route }: ApproveTransactionProps) => {
|
|||||||
</Text>
|
</Text>
|
||||||
<View style={styles.messageBody}>
|
<View style={styles.messageBody}>
|
||||||
<Text variant="bodyLarge">
|
<Text variant="bodyLarge">
|
||||||
{JSON.stringify(transactionMessage, replacer, 2)}
|
{JSON.stringify(transactionMessage, null, 2)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<>
|
<>
|
||||||
|
@ -7,7 +7,8 @@ import { useNavigation } from '@react-navigation/native';
|
|||||||
import { getSdkError } from '@walletconnect/utils';
|
import { getSdkError } from '@walletconnect/utils';
|
||||||
|
|
||||||
import { createWallet, resetWallet, retrieveAccounts } from '../utils/accounts';
|
import { createWallet, resetWallet, retrieveAccounts } from '../utils/accounts';
|
||||||
import { DialogComponent } from '../components/Dialog';
|
import { MnemonicDialog } from '../components/MnemonicDialog';
|
||||||
|
import ImportWalletDialog from '../components/ImportWalletDialog';
|
||||||
import { NetworkDropdown } from '../components/NetworkDropdown';
|
import { NetworkDropdown } from '../components/NetworkDropdown';
|
||||||
import Accounts from '../components/Accounts';
|
import Accounts from '../components/Accounts';
|
||||||
import CreateWallet from '../components/CreateWallet';
|
import CreateWallet from '../components/CreateWallet';
|
||||||
@ -55,12 +56,13 @@ const HomeScreen = () => {
|
|||||||
|
|
||||||
const [isWalletCreated, setIsWalletCreated] = useState<boolean>(false);
|
const [isWalletCreated, setIsWalletCreated] = useState<boolean>(false);
|
||||||
const [isWalletCreating, setIsWalletCreating] = useState<boolean>(false);
|
const [isWalletCreating, setIsWalletCreating] = useState<boolean>(false);
|
||||||
const [walletDialog, setWalletDialog] = useState<boolean>(false);
|
const [importWalletDialog, setImportWalletDialog] = useState<boolean>(false);
|
||||||
|
const [mnemonicDialog, setMnemonicDialog] = useState<boolean>(false);
|
||||||
const [resetWalletDialog, setResetWalletDialog] = useState<boolean>(false);
|
const [resetWalletDialog, setResetWalletDialog] = useState<boolean>(false);
|
||||||
const [isAccountsFetched, setIsAccountsFetched] = useState<boolean>(false);
|
const [isAccountsFetched, setIsAccountsFetched] = useState<boolean>(false);
|
||||||
const [phrase, setPhrase] = useState('');
|
const [phrase, setPhrase] = useState('');
|
||||||
|
|
||||||
const hideWalletDialog = () => setWalletDialog(false);
|
const hideMnemonicDialog = () => setMnemonicDialog(false);
|
||||||
const hideResetDialog = () => setResetWalletDialog(false);
|
const hideResetDialog = () => setResetWalletDialog(false);
|
||||||
|
|
||||||
const fetchAccounts = useCallback(async () => {
|
const fetchAccounts = useCallback(async () => {
|
||||||
@ -83,12 +85,22 @@ const HomeScreen = () => {
|
|||||||
const mnemonic = await createWallet(networksData);
|
const mnemonic = await createWallet(networksData);
|
||||||
if (mnemonic) {
|
if (mnemonic) {
|
||||||
fetchAccounts();
|
fetchAccounts();
|
||||||
setWalletDialog(true);
|
setMnemonicDialog(true);
|
||||||
setPhrase(mnemonic);
|
setPhrase(mnemonic);
|
||||||
setSelectedNetwork(networksData[0]);
|
setSelectedNetwork(networksData[0]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const importWalletHandler = async (recoveryPhrase: string) => {
|
||||||
|
const mnemonic = await createWallet(networksData, recoveryPhrase);
|
||||||
|
if (mnemonic) {
|
||||||
|
fetchAccounts();
|
||||||
|
setPhrase(mnemonic);
|
||||||
|
setSelectedNetwork(networksData[0]);
|
||||||
|
setImportWalletDialog(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const confirmResetWallet = useCallback(async () => {
|
const confirmResetWallet = useCallback(async () => {
|
||||||
setIsWalletCreated(false);
|
setIsWalletCreated(false);
|
||||||
setIsWalletCreating(false);
|
setIsWalletCreating(false);
|
||||||
@ -152,14 +164,28 @@ const HomeScreen = () => {
|
|||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
<CreateWallet
|
<CreateWallet
|
||||||
isWalletCreating={isWalletCreating}
|
isWalletCreating={isWalletCreating}
|
||||||
createWalletHandler={createWalletHandler}
|
createWalletHandler={createWalletHandler}
|
||||||
/>
|
/>
|
||||||
|
<View style={styles.createWalletContainer}>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => setImportWalletDialog(true)}>
|
||||||
|
Import Wallet
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<DialogComponent
|
<ImportWalletDialog
|
||||||
visible={walletDialog}
|
visible={importWalletDialog}
|
||||||
hideDialog={hideWalletDialog}
|
hideDialog={() => setImportWalletDialog(false)}
|
||||||
|
importWalletHandler={importWalletHandler}
|
||||||
|
/>
|
||||||
|
<MnemonicDialog
|
||||||
|
visible={mnemonicDialog}
|
||||||
|
hideDialog={hideMnemonicDialog}
|
||||||
contentText={phrase}
|
contentText={phrase}
|
||||||
/>
|
/>
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
|
@ -117,6 +117,12 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
},
|
},
|
||||||
|
textInput: {
|
||||||
|
height: 40,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 4,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
},
|
||||||
requestMessage: {
|
requestMessage: {
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
|
@ -27,12 +27,25 @@ import { COSMOS, EIP155 } from './constants';
|
|||||||
|
|
||||||
const createWallet = async (
|
const createWallet = async (
|
||||||
networksData: NetworksDataState[],
|
networksData: NetworksDataState[],
|
||||||
|
recoveryPhrase?: string,
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
const mnemonic = utils.entropyToMnemonic(utils.randomBytes(16));
|
const mnemonic = recoveryPhrase
|
||||||
|
? recoveryPhrase
|
||||||
|
: utils.entropyToMnemonic(utils.randomBytes(16));
|
||||||
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
|
await setInternetCredentials('mnemonicServer', 'mnemonic', mnemonic);
|
||||||
|
|
||||||
const hdNode = HDNode.fromMnemonic(mnemonic);
|
const hdNode = HDNode.fromMnemonic(mnemonic);
|
||||||
|
|
||||||
|
await createWalletFromMnemonic(networksData, hdNode, mnemonic);
|
||||||
|
|
||||||
|
return mnemonic;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createWalletFromMnemonic = async (
|
||||||
|
networksData: NetworksDataState[],
|
||||||
|
hdNode: HDNode,
|
||||||
|
mnemonic: string,
|
||||||
|
): Promise<void> => {
|
||||||
for (const network of networksData) {
|
for (const network of networksData) {
|
||||||
const hdPath = `m/44'/${network.coinType}'/0'/0/0`;
|
const hdPath = `m/44'/${network.coinType}'/0'/0/0`;
|
||||||
const node = hdNode.derivePath(hdPath);
|
const node = hdNode.derivePath(hdPath);
|
||||||
@ -73,8 +86,6 @@ const createWallet = async (
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mnemonic;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const addAccount = async (
|
const addAccount = async (
|
||||||
|
Loading…
Reference in New Issue
Block a user