Skip to content

Commit

Permalink
key recovery updates
Browse files Browse the repository at this point in the history
  • Loading branch information
armaniferrante committed Mar 21, 2023
1 parent a9f0aab commit e355988
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { useState } from "react";
import type { KeyringType } from "@coral-xyz/common";
import { toTitleCase } from "@coral-xyz/common";
import { HardwareWalletIcon, PrimaryButton } from "@coral-xyz/react-common";
import {
HardwareWalletIcon,
PrimaryButton,
SecondaryButton,
} from "@coral-xyz/react-common";
import { Box } from "@mui/material";

import { Header, HeaderIcon, SubtextParagraph } from "../../common";
Expand All @@ -12,6 +17,7 @@ export const KeyringTypeSelector = ({
action: "create" | "import" | "recover" | string;
onNext: (keyringType: KeyringType) => void;
}) => {
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
return (
<div
style={{
Expand Down Expand Up @@ -58,23 +64,39 @@ export const KeyringTypeSelector = ({
>
<Box style={{ marginBottom: "16px" }}>
<PrimaryButton
label={`${toTitleCase(action)} with recovery phrase`}
label={`${toTitleCase(action)} with secret phrase`}
onClick={() => onNext("mnemonic")}
/>
</Box>
{action === "import" || action === "recover" ? (
<Box style={{ marginBottom: "16px" }}>
<PrimaryButton
label={`${toTitleCase(action)} with private key`}
onClick={() => onNext("private-key")}
/>
</Box>
) : null}
<SubtextParagraph onClick={() => onNext("ledger")}>
{action === "recover"
? "Recover using a hardware wallet"
: "I have a hardware wallet"}
</SubtextParagraph>
{showAdvancedOptions ? (
<>
{action === "import" || action === "recover" ? (
<Box style={{ marginBottom: "16px" }}>
<SecondaryButton
label={`${toTitleCase(action)} with private key`}
onClick={() => onNext("private-key")}
/>
</Box>
) : null}
<Box style={{ marginBottom: "16px" }}>
<SecondaryButton
label={
action === "recover"
? "Recover using a hardware wallet"
: "I have a hardware wallet"
}
onClick={() => onNext("ledger")}
/>
</Box>
<SubtextParagraph onClick={() => setShowAdvancedOptions(false)}>
Hide advanced options
</SubtextParagraph>
</>
) : (
<SubtextParagraph onClick={() => setShowAdvancedOptions(true)}>
Show advanced options
</SubtextParagraph>
)}
</Box>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ import {
UI_RPC_METHOD_KEYRING_IMPORT_SECRET_KEY,
UI_RPC_METHOD_KEYRING_IMPORT_WALLET,
UI_RPC_METHOD_KEYRING_SET_MNEMONIC,
UI_RPC_METHOD_KEYRING_STORE_MNEMONIC_SYNC,
} from "@coral-xyz/common";
import { PrimaryButton, TextInput } from "@coral-xyz/react-common";
import { useBackgroundClient, useRpcRequests } from "@coral-xyz/recoil";
import {
useBackgroundClient,
useDehydratedWallets,
useRpcRequests,
} from "@coral-xyz/recoil";
import { useCustomTheme } from "@coral-xyz/themes";
import { Box } from "@mui/material";

Expand Down Expand Up @@ -48,6 +53,7 @@ export function ImportMnemonic({
const { step, nextStep } = useSteps();
const { close: closeParentDrawer } = useDrawerContext();
const { signMessageForWallet } = useRpcRequests();
const dehydratedWallets = useDehydratedWallets();

const [openDrawer, setOpenDrawer] = useState(false);
const [mnemonic, setMnemonic] = useState<string | true>(true);
Expand Down Expand Up @@ -78,6 +84,15 @@ export function ImportMnemonic({
method: UI_RPC_METHOD_KEYRING_IMPORT_WALLET,
params: [signedWalletDescriptor],
});
const walletsToSync = dehydratedWallets.filter(
(w) => w.publicKey !== publicKey
);
if (walletsToSync.length > 0) {
await background.request({
method: UI_RPC_METHOD_KEYRING_STORE_MNEMONIC_SYNC,
params: [walletsToSync],
});
}
} else {
if (!inputMnemonic) {
if (keyringExists) {
Expand Down Expand Up @@ -149,27 +164,31 @@ export function ImportMnemonic({
recovery={publicKey}
allowMultiple={false}
onNext={async (walletDescriptors: Array<WalletDescriptor>) => {
// Should only be one wallet descriptor
const walletDescriptor = walletDescriptors[0];
const message = getAddMessage(walletDescriptor.publicKey);
const signature = await signMessageForWallet(
walletDescriptor.blockchain,
walletDescriptor.publicKey,
message,
{
mnemonic,
signedWalletDescriptors: [
{
...walletDescriptor,
signature: "",
},
],
}
);
await onComplete({
...walletDescriptor,
signature,
});
try {
// Should only be one wallet descriptor
const walletDescriptor = walletDescriptors[0];
const message = getAddMessage(walletDescriptor.publicKey);
const signature = await signMessageForWallet(
walletDescriptor.blockchain,
walletDescriptor.publicKey,
message,
{
mnemonic,
signedWalletDescriptors: [
{
...walletDescriptor,
signature: "",
},
],
}
);
await onComplete({
...walletDescriptor,
signature,
});
} catch (err) {
console.log("ARMANI HERE ERR", err);
}
}}
/>,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
UI_RPC_METHOD_KEYRING_IMPORT_WALLET,
} from "@coral-xyz/common";
import {
BackpackMnemonicIcon,
CheckIcon,
HardwareIcon,
ImportedIcon,
Expand All @@ -24,6 +25,7 @@ import {
import {
useAvatarUrl,
useBackgroundClient,
useEnabledBlockchains,
useKeyringHasMnemonic,
useRpcRequests,
useUser,
Expand Down Expand Up @@ -191,64 +193,58 @@ export function AddWalletMenu({ blockchain }: { blockchain: Blockchain }) {
if (loading) {
return;
}
if (hasMnemonic) {
setOpenDrawer(true);
setLoading(true);
let newPublicKey;
if (!keyringExists || !hasHdPublicKeys) {
// No keyring or no existing mnemonic public keys so can't derive next
const walletDescriptor = await background.request({
method: UI_RPC_METHOD_FIND_WALLET_DESCRIPTOR,
params: [blockchain, 0],
});
const signature = await signMessageForWallet(
blockchain,
walletDescriptor.publicKey,
getAddMessage(walletDescriptor.publicKey),
{
mnemonic: true,
signedWalletDescriptors: [
{
...walletDescriptor,
signature: "",
},
],
}
);
const signedWalletDescriptor = { ...walletDescriptor, signature };
if (!keyringExists) {
// Keyring doesn't exist, create it
await background.request({
method: UI_RPC_METHOD_BLOCKCHAIN_KEYRINGS_ADD,
params: [
{
mnemonic: true, // Use the existing mnemonic
signedWalletDescriptors: [signedWalletDescriptor],
},
],
});
} else {
// Keyring exists but the hd keyring is not initialised, import
await background.request({
method: UI_RPC_METHOD_KEYRING_IMPORT_WALLET,
params: [signedWalletDescriptor],
});

setOpenDrawer(true);
setLoading(true);
let newPublicKey;
if (!keyringExists || !hasHdPublicKeys) {
// No keyring or no existing mnemonic public keys so can't derive next
const walletDescriptor = await background.request({
method: UI_RPC_METHOD_FIND_WALLET_DESCRIPTOR,
params: [blockchain, 0],
});
const signature = await signMessageForWallet(
blockchain,
walletDescriptor.publicKey,
getAddMessage(walletDescriptor.publicKey),
{
mnemonic: true,
signedWalletDescriptors: [
{
...walletDescriptor,
signature: "",
},
],
}
newPublicKey = walletDescriptor.publicKey;
);
const signedWalletDescriptor = { ...walletDescriptor, signature };
if (!keyringExists) {
// Keyring doesn't exist, create it
await background.request({
method: UI_RPC_METHOD_BLOCKCHAIN_KEYRINGS_ADD,
params: [
{
mnemonic: true, // Use the existing mnemonic
signedWalletDescriptors: [signedWalletDescriptor],
},
],
});
} else {
newPublicKey = await background.request({
method: UI_RPC_METHOD_KEYRING_DERIVE_WALLET,
params: [blockchain],
// Keyring exists but the hd keyring is not initialised, import
await background.request({
method: UI_RPC_METHOD_KEYRING_IMPORT_WALLET,
params: [signedWalletDescriptor],
});
}
setNewPublicKey(newPublicKey);
setLoading(false);
newPublicKey = walletDescriptor.publicKey;
} else {
nav.push("create-or-import-mnemonic", {
blockchain,
keyringExists,
newPublicKey = await background.request({
method: UI_RPC_METHOD_KEYRING_DERIVE_WALLET,
params: [blockchain],
});
}
setNewPublicKey(newPublicKey);
setLoading(false);
};

return (
Expand All @@ -268,8 +264,14 @@ export function AddWalletMenu({ blockchain }: { blockchain: Blockchain }) {
</Box>
<SettingsList
menuItems={{
"Create a new wallet": {
onClick: () => createNewWithPhrase(),
[hasMnemonic ? "Create a new wallet" : "Setup recovery phrase"]: {
onClick: () =>
hasMnemonic
? createNewWithPhrase()
: nav.push("create-or-import-mnemonic", {
blockchain,
keyringExists,
}),
icon: (props: any) => <PlusCircleIcon {...props} />,
},
"Advanced wallet import": {
Expand Down Expand Up @@ -316,22 +318,35 @@ export function RecoverWalletMenu({
publicKey: string;
}) {
const nav = useNavigation();
const hasMnemonic = useKeyringHasMnemonic();
const enabledBlockchains = useEnabledBlockchains();
const keyringExists = enabledBlockchains.includes(blockchain);

const recoverMenu = {
"Hardware wallet": {
const recoverMenu = {} as any;

if (!hasMnemonic) {
recoverMenu["Backpack recovery phrase"] = {
onClick: () => {
openConnectHardware(blockchain, "search", publicKey);
window.close();
nav.push("import-from-mnemonic", {
blockchain,
keyringExists,
inputMnemonic: true,
forceSetMnemonic: true,
publicKey,
});
},
icon: (props: any) => <HardwareIcon {...props} />,
icon: (props: any) => <BackpackMnemonicIcon {...props} />,
detailIcon: <PushDetail />,
},
};
}

Object.assign(recoverMenu, {
"Other recovery phrase": {
onClick: () =>
nav.push("import-from-mnemonic", {
blockchain,
inputMnemonic: true,
keyringExists: true,
keyringExists,
publicKey,
}),
icon: (props: any) => <MnemonicIcon {...props} />,
Expand All @@ -346,7 +361,15 @@ export function RecoverWalletMenu({
icon: (props: any) => <PlusCircleIcon {...props} />,
detailIcon: <PushDetail />,
},
};
"Hardware wallet": {
onClick: () => {
openConnectHardware(blockchain, "search", publicKey);
window.close();
},
icon: (props: any) => <HardwareIcon {...props} />,
detailIcon: <PushDetail />,
},
});

return (
<div
Expand Down

0 comments on commit e355988

Please sign in to comment.