mirror of
https://github.com/stake-house/wagyu-key-gen.git
synced 2026-01-09 12:48:05 -05:00
Cleaning up code and adding comments
This commit is contained in:
@@ -1,27 +1,34 @@
|
||||
import { CssBaseline, ThemeProvider, StyledEngineProvider } from "@mui/material";
|
||||
import { FC, ReactElement } from "react";
|
||||
import { HashRouter, Route, Switch } from "react-router-dom";
|
||||
|
||||
import BTECContextWrapper from "./BTECContext";
|
||||
import { OnlineDetector } from "./components/OnlineDetector";
|
||||
import VersionFooter from "./components/VersionFooter";
|
||||
import { paths } from "./constants";
|
||||
import GlobalContextWrapper from "./GlobalContext";
|
||||
import CreateMnemonic from "./pages/CreateMnemonic";
|
||||
import Home from "./pages/Home";
|
||||
import theme from "./theme";
|
||||
import ConfigureValidatorKeys from "./pages/ConfigureValidatorKeys";
|
||||
import MnemonicImport from "./pages/MnemonicImport";
|
||||
import ConfigureWithdrawalAddress from "./pages/ConfigureWithdrawalAddress";
|
||||
import { BTECImportPath, ConfigureBTECPath, ConfigureCreatePath, ConfigureExistingPath, CreateCredentialsPath, CreateKeysCreatePath, CreateKeysExistingPath, CreatePath, ExistingImportPath, FinishCreatePath, FinishCredentialsPath, FinishExistingPath } from "./constants";
|
||||
import CreateValidatorKeys from "./pages/CreateValidatorKeys";
|
||||
import KeyCreationContextWrapper from "./KeyCreationContext";
|
||||
import BTECContextWrapper from "./BTECContext";
|
||||
import FinishKeyGeneration from "./pages/FinishKeyGeneration";
|
||||
import ConfigureValidatorKeys from "./pages/ConfigureValidatorKeys";
|
||||
import ConfigureWithdrawalAddress from "./pages/ConfigureWithdrawalAddress";
|
||||
import CreateCredentialsChange from "./pages/CreateCredentialsChange";
|
||||
import CreateMnemonic from "./pages/CreateMnemonic";
|
||||
import CreateValidatorKeys from "./pages/CreateValidatorKeys";
|
||||
import FinishCredentialsGeneration from "./pages/FinishCredentialsGeneration";
|
||||
import FinishKeyGeneration from "./pages/FinishKeyGeneration";
|
||||
import Home from "./pages/Home";
|
||||
import MnemonicImport from "./pages/MnemonicImport";
|
||||
import theme from "./theme";
|
||||
|
||||
/**
|
||||
* The React app top level including theme and routing.
|
||||
* Routing for the application. Broken into four sections:
|
||||
* - Primary home page
|
||||
* - Routes for creating a mnemonic and validator keys
|
||||
* - Routes for using an existing mnemonic to create validator keys
|
||||
* - Routes for generating the credentials change
|
||||
*
|
||||
* @returns the react element containing the app
|
||||
* Each of the three flows is wrapped in a React Context that will store
|
||||
* the inputs of the user to be accessible across each page. This prevents
|
||||
* prop drilling
|
||||
*/
|
||||
const App: FC = (): ReactElement => {
|
||||
return (
|
||||
@@ -40,10 +47,10 @@ const App: FC = (): ReactElement => {
|
||||
{/* Create Mnemonic & Keys Flow */}
|
||||
<KeyCreationContextWrapper>
|
||||
<Switch>
|
||||
<Route path={CreatePath} children={() => <CreateMnemonic />} />
|
||||
<Route path={ConfigureCreatePath} children={() => <ConfigureValidatorKeys />} />
|
||||
<Route path={CreateKeysCreatePath} children={() => <CreateValidatorKeys />} />
|
||||
<Route path={FinishCreatePath} children={() => <FinishKeyGeneration />} />
|
||||
<Route path={paths.CREATE_MNEMONIC} children={() => <CreateMnemonic />} />
|
||||
<Route path={paths.CONFIGURE_CREATE} children={() => <ConfigureValidatorKeys />} />
|
||||
<Route path={paths.CREATE_KEYS_CREATE} children={() => <CreateValidatorKeys />} />
|
||||
<Route path={paths.FINISH_CREATE} children={() => <FinishKeyGeneration />} />
|
||||
</Switch>
|
||||
</KeyCreationContextWrapper>
|
||||
|
||||
@@ -51,10 +58,10 @@ const App: FC = (): ReactElement => {
|
||||
{/* Import Mnemonic & Generate Keys Flow */}
|
||||
<KeyCreationContextWrapper>
|
||||
<Switch>
|
||||
<Route path={ExistingImportPath} render={() => <MnemonicImport />} />
|
||||
<Route path={ConfigureExistingPath} render={() => <ConfigureValidatorKeys />} />
|
||||
<Route path={CreateKeysExistingPath} render={() => <CreateValidatorKeys />} />
|
||||
<Route path={FinishExistingPath} render={() => <FinishKeyGeneration />} />
|
||||
<Route path={paths.EXISTING_IMPORT} render={() => <MnemonicImport />} />
|
||||
<Route path={paths.CONFIGURE_EXISTING} render={() => <ConfigureValidatorKeys />} />
|
||||
<Route path={paths.CREATE_KEYS_EXISTING} render={() => <CreateValidatorKeys />} />
|
||||
<Route path={paths.FINISH_EXISTING} render={() => <FinishKeyGeneration />} />
|
||||
</Switch>
|
||||
</KeyCreationContextWrapper>
|
||||
|
||||
@@ -62,10 +69,10 @@ const App: FC = (): ReactElement => {
|
||||
{/* Update Withdrawal Credentials Flow */}
|
||||
<BTECContextWrapper>
|
||||
<Switch>
|
||||
<Route path={BTECImportPath} render={() => <MnemonicImport />} />
|
||||
<Route path={ConfigureBTECPath} render={() => <ConfigureWithdrawalAddress />} />
|
||||
<Route path={CreateCredentialsPath} render={() => <CreateCredentialsChange />} />
|
||||
<Route path={FinishCredentialsPath} render={() => <FinishCredentialsGeneration />} />
|
||||
<Route path={paths.BTEC_IMPORT} render={() => <MnemonicImport />} />
|
||||
<Route path={paths.CONFIGURE_BTEC} render={() => <ConfigureWithdrawalAddress />} />
|
||||
<Route path={paths.CREATE_CREDENTIALS} render={() => <CreateCredentialsChange />} />
|
||||
<Route path={paths.FINISH_CREDENTIALS} render={() => <FinishCredentialsGeneration />} />
|
||||
</Switch>
|
||||
</BTECContextWrapper>
|
||||
</Route>
|
||||
|
||||
@@ -30,6 +30,9 @@ export const BTECContext = createContext<BTECContextType>({
|
||||
setWithdrawalAddress: () => {},
|
||||
});
|
||||
|
||||
/**
|
||||
* Context for making the withdrawal credentials change
|
||||
*/
|
||||
const BTECContextWrapper = ({ children }: { children: React.ReactNode}) => {
|
||||
const [btecIndices, setBTECIndices] = useState<string>("");
|
||||
const [btecCredentials, setBTECCredentials] = useState<string>("");
|
||||
|
||||
@@ -30,6 +30,9 @@ export const KeyCreationContext = createContext<KeyCreationContextType>({
|
||||
setWithdrawalAddress: () => {},
|
||||
});
|
||||
|
||||
/**
|
||||
* Context for generating a validator key for both using an existing mnemonic or a new one
|
||||
*/
|
||||
const KeyCreationContextWrapper = ({ children }: { children: React.ReactNode}) => {
|
||||
const [folderLocation, setFolderLocation] = useState<string>("");
|
||||
const [index, setIndex] = useState<number>(0);
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { OpenDialogOptions, OpenDialogReturnValue } from 'electron';
|
||||
import { useState } from "react";
|
||||
|
||||
import { errors } from "../constants";
|
||||
|
||||
interface FolderSelectorParams {
|
||||
onFolderSelect: (folder: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component to select a folder and will use onFolderSelect param to provide
|
||||
* selected folder to parent
|
||||
* @param onFolderSelect callback to provide selected folder
|
||||
*/
|
||||
const FolderSelector = ({ onFolderSelect }: FolderSelectorParams) => {
|
||||
const [displayFolderPicker, setDisplayFolderPicker] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
/**
|
||||
* Called upon selecting a folder. Will verify the folder exists and is writable
|
||||
* @param folderPath the path of the folder to verify
|
||||
*/
|
||||
const verifyFolder = (folderPath: string) => {
|
||||
window.bashUtils.doesDirectoryExist(folderPath)
|
||||
.then((exists) => {
|
||||
@@ -30,6 +40,9 @@ const FolderSelector = ({ onFolderSelect }: FolderSelectorParams) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Will open a dialog to allow the user to select a folder
|
||||
*/
|
||||
const chooseFolder = () => {
|
||||
const options: OpenDialogOptions = {
|
||||
properties: ['openDirectory']
|
||||
|
||||
@@ -2,14 +2,16 @@ interface LoaderParams {
|
||||
message: string;
|
||||
}
|
||||
|
||||
const Loader = ({ message }: LoaderParams) => {
|
||||
return (
|
||||
<div className="tw-flex tw-flex-col tw-gap-8 tw-items-center">
|
||||
<div className="tw-px-12">{message}</div>
|
||||
/**
|
||||
* Simple loading spinner component with dynamic message
|
||||
* @param message message to display to the user
|
||||
*/
|
||||
const Loader = ({ message }: LoaderParams) => (
|
||||
<div className="tw-flex tw-flex-col tw-gap-8 tw-items-center">
|
||||
<div className="tw-px-12">{message}</div>
|
||||
|
||||
<div className="tw-border-4 tw-border-solid tw-border-gray1 tw-border-t-mediumBlue tw-rounded-full tw-w-[50px] tw-h-[50px] tw-animate-LoaderSpin" />
|
||||
</div>
|
||||
)
|
||||
};
|
||||
<div className="tw-border-4 tw-border-solid tw-border-gray1 tw-border-t-mediumBlue tw-rounded-full tw-w-[50px] tw-h-[50px] tw-animate-LoaderSpin" />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Loader;
|
||||
|
||||
@@ -1,25 +1,14 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
Typography,
|
||||
styled,
|
||||
} from "@mui/material";
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import PermScanWifiIcon from "@mui/icons-material/PermScanWifi";
|
||||
import React from "react";
|
||||
|
||||
import OnlineWarningModal from "../modals/OnlineWarningModal";
|
||||
|
||||
/**
|
||||
* This will add an event listener to detect the users internet connectivity.
|
||||
* If active, a pulsing warning icon with text will appear on the screen that
|
||||
* when clicked will show a dialog warning the user of the danger of internet
|
||||
* when clicked will show a modal to warn the user of the danger of internet
|
||||
* connectivity.
|
||||
*
|
||||
* @returns the warning and dialog component to render if necessary
|
||||
*/
|
||||
export const OnlineDetector = () => {
|
||||
const [open, setOpen] = React.useState<boolean>(false);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Grid, TextField } from "@mui/material";
|
||||
import { Dispatch, ReactNode, SetStateAction, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { Network } from "../types";
|
||||
import { Dispatch, SetStateAction, useContext, useRef, useState } from "react";
|
||||
|
||||
import { errors } from "../constants";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
import { Network } from "../types";
|
||||
|
||||
interface VerifyMnemonicParams {
|
||||
hasError: boolean;
|
||||
@@ -11,13 +13,22 @@ interface VerifyMnemonicParams {
|
||||
onVerifyMnemonic: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a grid of inputs if on mainnet or a single textbox for ease of testing.
|
||||
* The user fills the form with the mnemonic and the input will be provided to the
|
||||
* onVerifyMnemonic for futher action
|
||||
*
|
||||
* mnemonicToVerify is provided as a param instead of existing only in this component
|
||||
* so the parent can fill the value if the user goes back in navigation
|
||||
*/
|
||||
const VerifyMnemonic = ({
|
||||
hasError = false,
|
||||
mnemonicToVerify,
|
||||
setMnemonicToVerify,
|
||||
onVerifyMnemonic,
|
||||
}: VerifyMnemonicParams) => {
|
||||
const { mnemonic, network } = useContext(GlobalContext);
|
||||
const { mnemonic } = useContext(KeyCreationContext);
|
||||
const { network } = useContext(GlobalContext);
|
||||
const [mnemonicToVerifyArray, setMnemonicToVerifyArray] = useState<string[]>(
|
||||
mnemonicToVerify ? mnemonicToVerify.split(' ') : Array(24).fill(''));
|
||||
const inputRefs = useRef<HTMLInputElement[]>([]);
|
||||
@@ -41,8 +52,11 @@ const VerifyMnemonic = ({
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Will focus on a new input depending on the pressed key
|
||||
* @param index the current input index
|
||||
*/
|
||||
const handleKeysForWord = (index: number) => (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
// Navigate phrase confirmation with spacebar or arrowkeys
|
||||
let nextFocus = index;
|
||||
const currentTextFieldValue = mnemonicToVerifyArray[index];
|
||||
|
||||
|
||||
@@ -1,32 +1,15 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import styled from "styled-components";
|
||||
|
||||
declare var VERSION: string;
|
||||
declare var COMMITHASH: string;
|
||||
|
||||
const SoftText = styled(Typography)`
|
||||
color: gray;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
`;
|
||||
|
||||
const Container = styled.div`
|
||||
position: fixed;
|
||||
bottom: 35;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
/**
|
||||
* This component is a footer used to display the version and commit hash.
|
||||
*
|
||||
* @returns the footer component containing the version and commit hash
|
||||
* Footer to display the version and commit hash
|
||||
*/
|
||||
const VersionFooter = () => {
|
||||
return(
|
||||
<Container>
|
||||
<SoftText>Version: {VERSION} - Commit Hash: {COMMITHASH}</SoftText>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
const VersionFooter = () => (
|
||||
<div className="tw-fixed tw-bottom-9 tw-w-full">
|
||||
<Typography className="tw-text-gray tw-text-center tw-text-xxs">Version: {VERSION} - Commit Hash: {COMMITHASH}</Typography>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default VersionFooter;
|
||||
export default VersionFooter;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ReactNode, useContext } from "react";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { Step, StepLabel, Stepper, Typography } from "@mui/material";
|
||||
|
||||
import { stepLabels } from "../constants";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { StepKey } from "../types";
|
||||
|
||||
interface WizardWrapperParams {
|
||||
@@ -12,6 +13,15 @@ interface WizardWrapperParams {
|
||||
title: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper of a page to display the network, title, stepper, and action bar buttons.
|
||||
*
|
||||
* @param actionBarItems A list of buttons to display
|
||||
* @param activeTimelineIndex The index of the timelineItems array that is active
|
||||
* @param children The inner content of the page
|
||||
* @param timelineItems A list of steps to display
|
||||
* @param title The title to appear at the top of the page
|
||||
*/
|
||||
const WizardWrapper = ({
|
||||
actionBarItems,
|
||||
activeTimelineIndex,
|
||||
|
||||
@@ -53,17 +53,19 @@ export const CreateMnemonicFlow = [StepKey.MnemonicGeneration, StepKey.KeyConfig
|
||||
export const ExistingMnemonicFlow = [StepKey.MnemonicImport, StepKey.KeyConfiguration, StepKey.KeyGeneration, StepKey.Finish];
|
||||
export const BTECFlow = [StepKey.MnemonicImport, StepKey.BTECConfiguration, StepKey.BTECGeneration, StepKey.FinishBTEC];
|
||||
|
||||
export const CreatePath = "/create";
|
||||
export const ConfigureCreatePath = "/configure-create";
|
||||
export const CreateKeysCreatePath = "/create-keys";
|
||||
export const FinishCreatePath ="/finish-create";
|
||||
export const paths = {
|
||||
CREATE_MNEMONIC: "/create",
|
||||
CONFIGURE_CREATE: "/configure-create",
|
||||
CREATE_KEYS_CREATE: "/create-keys",
|
||||
FINISH_CREATE:"/finish-create",
|
||||
|
||||
export const ExistingImportPath = "/import-existing";
|
||||
export const ConfigureExistingPath = "/configure-existing";
|
||||
export const CreateKeysExistingPath = "/create-existing-keys";
|
||||
export const FinishExistingPath = "/finish-existing";
|
||||
EXISTING_IMPORT: "/import-existing",
|
||||
CONFIGURE_EXISTING: "/configure-existing",
|
||||
CREATE_KEYS_EXISTING: "/create-existing-keys",
|
||||
FINISH_EXISTING: "/finish-existing",
|
||||
|
||||
export const BTECImportPath = "/import-btec";
|
||||
export const ConfigureBTECPath = "/configure-btec";
|
||||
export const CreateCredentialsPath = "/create-btec";
|
||||
export const FinishCredentialsPath = "/finish-btec";
|
||||
BTEC_IMPORT: "/import-btec",
|
||||
CONFIGURE_BTEC: "/configure-btec",
|
||||
CREATE_CREDENTIALS: "/create-btec",
|
||||
FINISH_CREDENTIALS: "/finish-btec",
|
||||
};
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
import { Dispatch, SetStateAction, createContext, useState } from "react";
|
||||
|
||||
import { Network } from "./types";
|
||||
|
||||
interface GlobalContextType {
|
||||
mnemonic: string;
|
||||
setMnemonic: Dispatch<SetStateAction<string>>;
|
||||
network: Network;
|
||||
setNetwork: Dispatch<SetStateAction<Network>>;
|
||||
}
|
||||
|
||||
export const GlobalContext = createContext<GlobalContextType>({
|
||||
mnemonic: "",
|
||||
setMnemonic: () => {},
|
||||
network: Network.MAINNET,
|
||||
setNetwork: () => {},
|
||||
});
|
||||
|
||||
/**
|
||||
* Global context for the network which is used across the application
|
||||
*/
|
||||
const GlobalContextWrapper = ({ children }: { children: React.ReactNode}) => {
|
||||
const [mnemonic, setMnemonic] = useState<string>("");
|
||||
const [network, setNetwork] = useState<Network>(Network.MAINNET);
|
||||
|
||||
return (
|
||||
<GlobalContext.Provider value={{ mnemonic, setMnemonic, network, setNetwork }}>
|
||||
<GlobalContext.Provider value={{ network, setNetwork }}>
|
||||
{children}
|
||||
</GlobalContext.Provider>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Helper function to clean the mnemonic of invalid characters and extraneous spacing
|
||||
* @param mnemonic the mnemonic to clean
|
||||
* @returns the cleaned mnemonic
|
||||
*/
|
||||
export const cleanMnemonic = (mnemonic: String): string => {
|
||||
const punctuationRemoved = mnemonic.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, " ");
|
||||
const singleSpace = punctuationRemoved.replace(/\s\s+/g, " ");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
import 'typeface-roboto';
|
||||
|
||||
import App from "./App";
|
||||
import './index.css';
|
||||
|
||||
// We find our app DOM element as before
|
||||
|
||||
@@ -7,9 +7,10 @@ import {
|
||||
RadioGroup,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Network } from "../types";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { Network } from "../types";
|
||||
import WagyuModal from "./WagyuModal";
|
||||
|
||||
interface NetworkPickerModalParams {
|
||||
@@ -17,6 +18,9 @@ interface NetworkPickerModalParams {
|
||||
showModal: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal to allow the user to pick the Ethereum Network
|
||||
*/
|
||||
const NetworkPickerModal = ({onClose, showModal}: NetworkPickerModalParams) => {
|
||||
const { network, setNetwork } = useContext(GlobalContext);
|
||||
const [formNetwork, setFormNetwork] = useState<Network>(Network.MAINNET);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
|
||||
import WagyuModal from "./WagyuModal";
|
||||
|
||||
interface OlineWarningModalParams {
|
||||
@@ -7,49 +8,50 @@ interface OlineWarningModalParams {
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
const OnlineWarningModal = ({ onClose, onHideWarning, open }: OlineWarningModalParams) => {
|
||||
return (
|
||||
<WagyuModal
|
||||
className="tw-w-[600px]"
|
||||
open={open}
|
||||
>
|
||||
<div className="tw-py-8 tw-px-4">
|
||||
<div className="tw-text-3xl tw-text-center tw-mb-8">Internet Connection Detected</div>
|
||||
<div className="tw-text-left tw-min-h-[250px]">
|
||||
<Typography className="tw-mb-2" variant="body1">
|
||||
Being connected to the internet while using this tool drastically increases the risk of exposing your Secret Recovery Phrase.
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
You can avoid this risk by having a live OS such as Tails installed on a USB drive and run on a computer with network capabilities disabled.
|
||||
</Typography>
|
||||
/**
|
||||
* Modal to display to the user to explain the risks of using this tool with network connectivity
|
||||
*/
|
||||
const OnlineWarningModal = ({ onClose, onHideWarning, open }: OlineWarningModalParams) => (
|
||||
<WagyuModal
|
||||
className="tw-w-[600px]"
|
||||
open={open}
|
||||
>
|
||||
<div className="tw-py-8 tw-px-4">
|
||||
<div className="tw-text-3xl tw-text-center tw-mb-8">Internet Connection Detected</div>
|
||||
<div className="tw-text-left tw-min-h-[250px]">
|
||||
<Typography className="tw-mb-2" variant="body1">
|
||||
Being connected to the internet while using this tool drastically increases the risk of exposing your Secret Recovery Phrase.
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
You can avoid this risk by having a live OS such as Tails installed on a USB drive and run on a computer with network capabilities disabled.
|
||||
</Typography>
|
||||
|
||||
<Typography className="tw-mt-6 tw-mb-2" variant="body1">
|
||||
You can visit https://tails.net/install/ for instructions on how to download, install, and run Tails on a USB device.
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
If you have any questions you can get help at https://dsc.gg/ethstaker
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
className="tw-mr-2"
|
||||
color="secondary"
|
||||
onClick={() => onHideWarning()}
|
||||
variant="contained"
|
||||
>
|
||||
Hide Warning
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={() => onClose()}
|
||||
variant="contained"
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
<Typography className="tw-mt-6 tw-mb-2" variant="body1">
|
||||
You can visit https://tails.net/install/ for instructions on how to download, install, and run Tails on a USB device.
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
If you have any questions you can get help at https://dsc.gg/ethstaker
|
||||
</Typography>
|
||||
</div>
|
||||
</WagyuModal>
|
||||
);
|
||||
};
|
||||
<div>
|
||||
<Button
|
||||
className="tw-mr-2"
|
||||
color="secondary"
|
||||
onClick={() => onHideWarning()}
|
||||
variant="contained"
|
||||
>
|
||||
Hide Warning
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={() => onClose()}
|
||||
variant="contained"
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</WagyuModal>
|
||||
);
|
||||
|
||||
export default OnlineWarningModal;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Button, Tooltip } from "@mui/material";
|
||||
|
||||
import { ReuseMnemonicAction } from "../types";
|
||||
import WagyuModal from "./WagyuModal";
|
||||
|
||||
@@ -8,35 +9,38 @@ interface ReuseMnemonicActionModalParams {
|
||||
showModal: boolean;
|
||||
}
|
||||
|
||||
const ReuseMnemonicActionModal = ({ onClose, onSubmit, showModal}: ReuseMnemonicActionModalParams) => {
|
||||
return (
|
||||
<WagyuModal
|
||||
className="tw-w-[560px] tw-h-[260px]"
|
||||
open={showModal}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="tw-flex tw-flex-col tw-h-full tw-my-7">
|
||||
<div className="tw-text-2xl">How would you like to use your existing secret recovery phrase?</div>
|
||||
/**
|
||||
* Modal for the user to pick which action they would like to take when reusing a mnemonic
|
||||
*
|
||||
* Options are: Generate existing keys or Generate BLS change
|
||||
*/
|
||||
const ReuseMnemonicActionModal = ({ onClose, onSubmit, showModal}: ReuseMnemonicActionModalParams) => (
|
||||
<WagyuModal
|
||||
className="tw-w-[560px] tw-h-[260px]"
|
||||
open={showModal}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="tw-flex tw-flex-col tw-h-full tw-my-7">
|
||||
<div className="tw-text-2xl">How would you like to use your existing secret recovery phrase?</div>
|
||||
|
||||
<div className="tw-grow" />
|
||||
<div className="tw-grow" />
|
||||
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-align-middle">
|
||||
<div>
|
||||
<Button variant="contained" color="primary" onClick={() => onSubmit(ReuseMnemonicAction.RegenerateKeys)}>
|
||||
Generate existing or new validator keys
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-align-middle">
|
||||
<div>
|
||||
<Button variant="contained" color="primary" onClick={() => onSubmit(ReuseMnemonicAction.RegenerateKeys)}>
|
||||
Generate existing or new validator keys
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip title="If you initially created your validator keys without adding a withdrawal address, you can generate this BLS to execution change to add one once.">
|
||||
<Button variant="contained" color="primary" onClick={() => onSubmit(ReuseMnemonicAction.GenerateBLSToExecutionChange)}>
|
||||
Generate your BLS to execution change<br />(Add a withdrawal address)
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip title="If you initially created your validator keys without adding a withdrawal address, you can generate this BLS to execution change to add one once.">
|
||||
<Button variant="contained" color="primary" onClick={() => onSubmit(ReuseMnemonicAction.GenerateBLSToExecutionChange)}>
|
||||
Generate your BLS to execution change<br />(Add a withdrawal address)
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</WagyuModal>
|
||||
)
|
||||
};
|
||||
</div>
|
||||
</WagyuModal>
|
||||
);
|
||||
|
||||
export default ReuseMnemonicActionModal;
|
||||
|
||||
@@ -5,17 +5,18 @@ interface WagyuModalParams {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const WagyuModal = ({ children, className, onClose, open}: WagyuModalParams & ModalProps) => {
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className={`tw-flex tw-flex-col tw-bg-backgroundLight tw-rounded-3xl tw-text-center tw-m-auto tw-mt-[150px] ${className || ""}`}>
|
||||
{children}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
/**
|
||||
* Wrapper for modal usages to keep consistent styling.
|
||||
*/
|
||||
const WagyuModal = ({ children, className, onClose, open}: WagyuModalParams & ModalProps) => (
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className={`tw-flex tw-flex-col tw-bg-backgroundLight tw-rounded-3xl tw-text-center tw-m-auto tw-mt-[150px] ${className || ""}`}>
|
||||
{children}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
export default WagyuModal;
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import { Button, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { ConfigureExistingPath, CreateKeysCreatePath, CreateKeysExistingPath, CreateMnemonicFlow, CreatePath, ExistingImportPath, ExistingMnemonicFlow, errors, tooltips } from "../constants";
|
||||
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { CreateMnemonicFlow, ExistingMnemonicFlow, errors, paths, tooltips } from "../constants";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
|
||||
/**
|
||||
* Form to provide number of keys, index, password, and optional withdrawal address necessary to
|
||||
* complete the validator key creation process.
|
||||
*
|
||||
* User will provide the necessary inputs and a verification of the password will be done before
|
||||
* they can continue the flow
|
||||
*/
|
||||
const ConfigureValidatorKeys = () => {
|
||||
const {
|
||||
mnemonic,
|
||||
@@ -14,7 +22,7 @@ const ConfigureValidatorKeys = () => {
|
||||
setWithdrawalAddress,
|
||||
} = useContext(KeyCreationContext);
|
||||
const history = useHistory();
|
||||
const usingExistingFlow = history.location.pathname === ConfigureExistingPath;
|
||||
const usingExistingFlow = history.location.pathname === paths.CONFIGURE_EXISTING;
|
||||
|
||||
const [passwordToVerify, setPasswordToVerify] = useState("");
|
||||
const [verifyPassword, setVerifyPassword] = useState(false);
|
||||
@@ -34,7 +42,7 @@ const ConfigureValidatorKeys = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!mnemonic) {
|
||||
history.replace(usingExistingFlow ? ExistingImportPath : CreatePath);
|
||||
history.replace(usingExistingFlow ? paths.EXISTING_IMPORT : paths.CREATE_MNEMONIC);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -56,6 +64,10 @@ const ConfigureValidatorKeys = () => {
|
||||
setInputWithdrawalAddress(e.target.value.trim());
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates each value simultaneously and if there are no errors will show the
|
||||
* user the password verification input
|
||||
*/
|
||||
const validateInputs = async () => {
|
||||
let isError = false;
|
||||
|
||||
@@ -103,6 +115,9 @@ const ConfigureValidatorKeys = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifies the passwords match and will move the user to the next step in the flow if so
|
||||
*/
|
||||
const checkPassword = () => {
|
||||
if (inputPassword.localeCompare(passwordToVerify) == 0) {
|
||||
setPasswordVerifyError(false);
|
||||
@@ -113,7 +128,7 @@ const ConfigureValidatorKeys = () => {
|
||||
setPassword(inputPassword);
|
||||
setWithdrawalAddress(inputWithdrawalAddress);
|
||||
|
||||
history.push(usingExistingFlow ? CreateKeysExistingPath : CreateKeysCreatePath);
|
||||
history.push(usingExistingFlow ? paths.CREATE_KEYS_EXISTING : paths.CREATE_KEYS_CREATE);
|
||||
} else {
|
||||
setPasswordVerifyError(true);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { Button, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { BTECFlow, BTECImportPath, CreateCredentialsPath, errors, tooltips } from "../constants";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import Loader from "../components/Loader";
|
||||
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import Loader from "../components/Loader";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { BTECFlow, errors, paths, tooltips } from "../constants";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
|
||||
/**
|
||||
* Form to provide start index, validator indices, current withdrawal credentials, and the
|
||||
* desired withdrawal address to be set.
|
||||
*/
|
||||
const ConfigureWithdrawalAddress = () => {
|
||||
const {
|
||||
btecCredentials,
|
||||
@@ -35,7 +40,7 @@ const ConfigureWithdrawalAddress = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!mnemonic) {
|
||||
history.replace(BTECImportPath);
|
||||
history.replace(paths.BTEC_IMPORT);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -56,6 +61,14 @@ const ConfigureWithdrawalAddress = () => {
|
||||
setInputWithdrawalAddress(e.target.value.trim());
|
||||
};
|
||||
|
||||
/**
|
||||
* Three step function:
|
||||
* - Validate all inputs and make sure there are no errors
|
||||
* - If no errors, validate the provided BLS credentials
|
||||
* - If successful, send user to the creation step
|
||||
*
|
||||
* Any errors the user will be provided a corresponding error message
|
||||
*/
|
||||
const validateInputs = async () => {
|
||||
let isError = false;
|
||||
|
||||
@@ -139,7 +152,7 @@ const ConfigureWithdrawalAddress = () => {
|
||||
setIndex(inputIndex);
|
||||
setWithdrawalAddress(inputWithdrawalAddress);
|
||||
|
||||
history.push(CreateCredentialsPath);
|
||||
history.push(paths.CREATE_CREDENTIALS);
|
||||
}).catch(() => {
|
||||
setValidatingCredentials(false);
|
||||
setCredentialsError(errors.BLS_CREDENTIALS_NO_MATCH);
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { BTECFlow, BTECImportPath, FinishCredentialsPath } from "../constants";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import Loader from "../components/Loader";
|
||||
import FolderSelector from "../components/FolderSelector";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import FolderSelector from "../components/FolderSelector";
|
||||
import Loader from "../components/Loader";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { BTECFlow, paths } from "../constants";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
|
||||
/**
|
||||
* Allows the user to select a folder where the credentials will be saved
|
||||
* and after which will attempt to generate the credential change and save
|
||||
* to the specified folder
|
||||
*/
|
||||
const CreateCredentialsChange = () => {
|
||||
const { network } = useContext(GlobalContext);
|
||||
const {
|
||||
@@ -26,7 +32,7 @@ const CreateCredentialsChange = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!mnemonic) {
|
||||
history.replace(BTECImportPath);
|
||||
history.replace(paths.BTEC_IMPORT);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -34,6 +40,10 @@ const CreateCredentialsChange = () => {
|
||||
setSelectedFolder(folder);
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts to generate the credentials change and if successful send the user
|
||||
* to the final step of the flow
|
||||
*/
|
||||
const handleBTECFileGeneration = () => {
|
||||
setCreatingCredentialsChange(true);
|
||||
let appendedWithdrawalAddress = withdrawalAddress;
|
||||
@@ -52,7 +62,7 @@ const CreateCredentialsChange = () => {
|
||||
appendedWithdrawalAddress,
|
||||
).then(() => {
|
||||
setFolderLocation(selectedFolder);
|
||||
history.push(FinishCredentialsPath);
|
||||
history.push(paths.FINISH_CREDENTIALS);
|
||||
}).catch((error) => {
|
||||
const errorMsg = ('stderr' in error) ? error.stderr : error.message;
|
||||
setGenerationError(errorMsg);
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import { Button, Grid, IconButton, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { StepKey } from "../types";
|
||||
import Loader from "../components/Loader";
|
||||
import { useContext, useEffect, useMemo, useState } from "react";
|
||||
import { FileCopy } from "@mui/icons-material";
|
||||
import VerifyMnemonic from "../components/VerifyMnemonic";
|
||||
import { cleanMnemonic } from '../helpers';
|
||||
import { Button, Grid, IconButton, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import { useContext, useEffect, useMemo, useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { ConfigureCreatePath } from "../constants";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
|
||||
import Loader from "../components/Loader";
|
||||
import VerifyMnemonic from "../components/VerifyMnemonic";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { paths } from "../constants";
|
||||
import { cleanMnemonic } from '../helpers';
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
import { StepKey } from "../types";
|
||||
|
||||
/**
|
||||
* Creates a new mnemonic for the user which will then be validated to make sure the
|
||||
* user has stored it properly.
|
||||
*/
|
||||
const CreateMnemonic = () => {
|
||||
const {mnemonic, setMnemonic} = useContext(KeyCreationContext);
|
||||
const history = useHistory();
|
||||
@@ -76,6 +81,9 @@ const CreateMnemonic = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an array of inputs that will display each word of the mnemonic
|
||||
*/
|
||||
const createMnemonicDisplay = () => {
|
||||
return(
|
||||
<Grid container item xs={10} spacing={2}>
|
||||
@@ -124,7 +132,7 @@ const CreateMnemonic = () => {
|
||||
|
||||
if (cleanedMnemonic.localeCompare(cleanedMnemonicToVerify) === 0) {
|
||||
setMnemonicValidationError(false);
|
||||
history.push(ConfigureCreatePath);
|
||||
history.push(paths.CONFIGURE_CREATE);
|
||||
} else {
|
||||
setMnemonicValidationError(true);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { CreateKeysExistingPath, CreateMnemonicFlow, CreatePath, ExistingImportPath, ExistingMnemonicFlow, FinishCreatePath, FinishExistingPath } from "../constants";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
|
||||
import FolderSelector from "../components/FolderSelector";
|
||||
import Loader from "../components/Loader";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { CreateMnemonicFlow, ExistingMnemonicFlow, paths } from "../constants";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
|
||||
/**
|
||||
* Allows the user to select a destination folder for the validator keys.
|
||||
* After which the user can attempt to generate the keys.
|
||||
*/
|
||||
const CreateValidatorKeys = () => {
|
||||
const {
|
||||
setFolderLocation,
|
||||
@@ -19,7 +24,7 @@ const CreateValidatorKeys = () => {
|
||||
} = useContext(KeyCreationContext);
|
||||
const { network } = useContext(GlobalContext);
|
||||
const history = useHistory();
|
||||
const usingExistingFlow = history.location.pathname === CreateKeysExistingPath;
|
||||
const usingExistingFlow = history.location.pathname === paths.CREATE_KEYS_EXISTING;
|
||||
|
||||
const [creatingKeys, setCreatingKeys] = useState(false);
|
||||
const [generationError, setGenerationError] = useState("");
|
||||
@@ -27,7 +32,7 @@ const CreateValidatorKeys = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (!mnemonic) {
|
||||
history.replace(usingExistingFlow ? ExistingImportPath : CreatePath);
|
||||
history.replace(usingExistingFlow ? paths.EXISTING_IMPORT : paths.CREATE_MNEMONIC);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -35,6 +40,10 @@ const CreateValidatorKeys = () => {
|
||||
setSelectedFolder(folder);
|
||||
};
|
||||
|
||||
/**
|
||||
* Will attempt to generate the validator keys with the provided folder and if successful
|
||||
* will send the user to the final step of the flow
|
||||
*/
|
||||
const createKeys = () => {
|
||||
setCreatingKeys(true);
|
||||
|
||||
@@ -54,7 +63,7 @@ const CreateValidatorKeys = () => {
|
||||
selectedFolder,
|
||||
).then(() => {
|
||||
setFolderLocation(selectedFolder);
|
||||
history.push(usingExistingFlow ? FinishExistingPath : FinishCreatePath);
|
||||
history.push(usingExistingFlow ? paths.FINISH_EXISTING : paths.FINISH_CREATE);
|
||||
}).catch((error) => {
|
||||
const errorMsg = ('stderr' in error) ? error.stderr : error.message;
|
||||
setGenerationError(errorMsg);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { Button, Link, Typography } from "@mui/material";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { BTECFlow } from "../constants";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { BTECContext } from "../BTECContext";
|
||||
|
||||
/**
|
||||
* Final step of the credentials generation flow.
|
||||
* Shows the user the location where the files were stored and provides
|
||||
* some additional information.
|
||||
*/
|
||||
const FinishCredentialsGeneration = () => {
|
||||
const { folderLocation } = useContext(BTECContext);
|
||||
const history = useHistory();
|
||||
@@ -15,6 +21,9 @@ const FinishCredentialsGeneration = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Will open a directory explorer where the credential change file was saved
|
||||
*/
|
||||
const openKeyLocation = () => {
|
||||
window.bashUtils.findFirstFile(folderLocation, "keystore")
|
||||
.then((keystoreFile) => {
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { CreateMnemonicFlow, ExistingMnemonicFlow, FinishExistingPath } from "../constants";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { Button, Link, Typography } from "@mui/material";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { CreateMnemonicFlow, ExistingMnemonicFlow, paths } from "../constants";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
|
||||
/**
|
||||
* Final step of creating validator keys. Will show the folder of where
|
||||
* the keys were created and additional information
|
||||
*/
|
||||
const FinishKeyGeneration = () => {
|
||||
const { folderLocation } = useContext(KeyCreationContext);
|
||||
const history = useHistory();
|
||||
const usingExistingFlow = history.location.pathname === FinishExistingPath;
|
||||
const usingExistingFlow = history.location.pathname === paths.FINISH_EXISTING;
|
||||
|
||||
useEffect(() => {
|
||||
if (!folderLocation) {
|
||||
@@ -16,6 +21,9 @@ const FinishKeyGeneration = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Will open a directory explorer where the validator keys were saved
|
||||
*/
|
||||
const openKeyLocation = () => {
|
||||
window.bashUtils.findFirstFile(folderLocation, "keystore")
|
||||
.then((keystoreFile) => {
|
||||
@@ -38,7 +46,7 @@ const FinishKeyGeneration = () => {
|
||||
timelineItems={usingExistingFlow ? ExistingMnemonicFlow : CreateMnemonicFlow}
|
||||
title="Create Keys"
|
||||
>
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-ml-28">
|
||||
<div className="tw-flex tw-flex-col tw-gap-2 tw-mx-28">
|
||||
<Typography variant="body1">
|
||||
Your keys have been created here:{" "}
|
||||
<Link
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import { Button, Tooltip, Typography } from "@mui/material";
|
||||
import { useContext, useMemo, useState } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import { paths, tooltips } from "../constants";
|
||||
import { GlobalContext } from "../GlobalContext";
|
||||
import { Button, Tooltip, Typography } from "@mui/material";
|
||||
import NetworkPickerModal from "../modals/NetworkPickerModal";
|
||||
import { KeyIcon } from "../icons/KeyIcon";
|
||||
import { BTECImportPath, CreatePath, ExistingImportPath, tooltips } from "../constants";
|
||||
import NetworkPickerModal from "../modals/NetworkPickerModal";
|
||||
import ReuseMnemonicActionModal from "../modals/ReuseMnemonicActionModal";
|
||||
import { ReuseMnemonicAction } from "../types";
|
||||
|
||||
/**
|
||||
* Landed page of the application.
|
||||
* The user will be able to select a network and choose the primary action
|
||||
* they wish to make.
|
||||
*/
|
||||
const Home = () => {
|
||||
const { network } = useContext(GlobalContext);
|
||||
const [wasNetworkModalOpened, setWasNetworkModalOpened] = useState(false);
|
||||
@@ -40,7 +46,7 @@ const Home = () => {
|
||||
if (!wasNetworkModalOpened) {
|
||||
handleOpenNetworkModal();
|
||||
} else {
|
||||
history.push(CreatePath)
|
||||
history.push(paths.CREATE_MNEMONIC)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -62,10 +68,10 @@ const Home = () => {
|
||||
setShowReuseMnemonicModal(false);
|
||||
if (action === ReuseMnemonicAction.RegenerateKeys) {
|
||||
|
||||
history.push(ExistingImportPath);
|
||||
history.push(paths.EXISTING_IMPORT);
|
||||
} else if (action === ReuseMnemonicAction.GenerateBLSToExecutionChange) {
|
||||
|
||||
history.push(BTECImportPath);
|
||||
history.push(paths.BTEC_IMPORT);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import { useContext, useState } from "react";
|
||||
import { cleanMnemonic } from "../helpers";
|
||||
import { BTECFlow, BTECImportPath, ConfigureBTECPath, ConfigureExistingPath, ExistingMnemonicFlow, MNEMONIC_ERROR_SEARCH, VALID_MNEMONIC_LENGTHS, errors } from "../constants";
|
||||
import Loader from "../components/Loader";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import { BTECContext } from "../BTECContext";
|
||||
import Loader from "../components/Loader";
|
||||
import WizardWrapper from "../components/WizardWrapper";
|
||||
import {
|
||||
BTECFlow,
|
||||
ExistingMnemonicFlow,
|
||||
MNEMONIC_ERROR_SEARCH,
|
||||
VALID_MNEMONIC_LENGTHS,
|
||||
errors,
|
||||
paths,
|
||||
} from "../constants";
|
||||
import { cleanMnemonic } from "../helpers";
|
||||
import { KeyCreationContext } from "../KeyCreationContext";
|
||||
|
||||
/**
|
||||
* Allows the user to import an existing mnemonic to kickstart either the
|
||||
* validator key creation or withdrawal credentials change flow
|
||||
*/
|
||||
const MnemonicImport = () => {
|
||||
const {mnemonic: btecMnemonic, setMnemonic: setBTECMnemonic} = useContext(BTECContext);
|
||||
const {mnemonic, setMnemonic} = useContext(KeyCreationContext);
|
||||
const history = useHistory();
|
||||
const usingBTEC = history.location.pathname === BTECImportPath;
|
||||
const usingBTEC = history.location.pathname === paths.BTEC_IMPORT;
|
||||
|
||||
const [error, setError] = useState("");
|
||||
const [inputMnemonic, setInputMnemonic] = useState(usingBTEC ? btecMnemonic : mnemonic);
|
||||
const [validatingMnemonic, setValidatingMnemonic] = useState(false);
|
||||
|
||||
/**
|
||||
* Verifies the mnemonic is valid and will notify the user if not
|
||||
*/
|
||||
const verifyMnemonic = () => {
|
||||
setError("");
|
||||
|
||||
@@ -37,7 +52,7 @@ const MnemonicImport = () => {
|
||||
setMnemonic(cleanedMnemonic);
|
||||
}
|
||||
setValidatingMnemonic(false);
|
||||
history.push(usingBTEC ? ConfigureBTECPath : ConfigureExistingPath);
|
||||
history.push(usingBTEC ? paths.CONFIGURE_BTEC : paths.CONFIGURE_EXISTING);
|
||||
}).catch((error) => {
|
||||
const errorMsg = ('stderr' in error) ? error.stderr : error.message;
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ module.exports = {
|
||||
orange: "#F2994A",
|
||||
},
|
||||
extend: {
|
||||
fontSize: {
|
||||
xxs: ".625rem",
|
||||
},
|
||||
keyframes: {
|
||||
OnlinePulse: {
|
||||
"0%": {
|
||||
|
||||
Reference in New Issue
Block a user