Skip to content

Commit

Permalink
Support secp256k1 for numbers (#395)
Browse files Browse the repository at this point in the history
* Support secp256k1 for numbers

* Extract SecretNumberInput from ImportSecretNumbers page

* Rename test for ImportSecretNumbers

* Fix styling issues

* Make use of SecretNumberInput within SecretNumbers page

* Extract number count
  • Loading branch information
FlorianBouron authored Nov 24, 2024
1 parent 25beb8c commit 7620032
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 317 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Grid, TextField } from '@mui/material';
import { FC, FocusEvent } from 'react';
import styles from './styles.module.css';
import { useNetwork } from '../../../contexts';

export interface SecretNumberInputProps {
id: string;
label: string;
error: string;
onBlur: (e: FocusEvent<HTMLInputElement>) => void;
}

export const SecretNumberInput: FC<SecretNumberInputProps> = ({ id, label, error, onBlur }) => {
const { hasOfflineBanner } = useNetwork();

return (
<Grid item xs={6}>
<TextField
size="small"
id={id}
name={id}
label={label}
error={Boolean(error)}
helperText={error}
style={{
marginTop: '10px',
marginBottom: error ? '0px' : hasOfflineBanner ? '10px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={onBlur}
/>
</Grid>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './SecretNumberInput';
1 change: 1 addition & 0 deletions packages/extension/src/components/atoms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './Logo';
export * from './NFTImage';
export * from './NumericInput';
export * from './PrivateRoute';
export * from './SecretNumberInput';
export * from './TileLoader';
export * from './TokenLoader';
export * from './Tokens';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { FC, useCallback, useState, FocusEvent } from 'react';

import { Grid, TextField, Typography } from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import { Checkbox, FormControlLabel, Grid, Tooltip, Typography } from '@mui/material';
import { useNavigate } from 'react-router-dom';

import { ERROR_RED, LIST_WALLETS_PATH } from '../../../../../constants';
import { useWallet } from '../../../../../contexts';
import { ERROR_RED, LIST_WALLETS_PATH, SECONDARY_GRAY } from '../../../../../constants';
import { useNetwork, useWallet } from '../../../../../contexts';
import { PageWithStepper } from '../../../../templates';
import styles from './styles.module.css';

const schemaInput = new RegExp(/^[0-9]{6}$/);
import { ECDSA } from 'xrpl';
import { SecretNumberInput } from '../../../../atoms';

type InputErrors = {
numbersA: string;
Expand All @@ -22,6 +22,8 @@ type InputErrors = {
};

const DIGIT_ERROR = 'You need 6 digits';
const NUMBERS_COUNT = 8;
const schemaInput = new RegExp(/^[0-9]{6}$/);

export interface ImportSecretNumbersProps {
activeStep: number;
Expand All @@ -36,6 +38,8 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
}) => {
const navigate = useNavigate();
const { importNumbers } = useWallet();
const { hasOfflineBanner } = useNetwork();
const [isSecp256k1, setSecp256k1] = useState(false);
const [numbersError, setNumbersError] = useState('');
const [inputErrors, setInputErrors] = useState<InputErrors>({
numbersA: '',
Expand Down Expand Up @@ -71,7 +75,11 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
);

if (numbers.find((number) => !schemaInput.test(number)) === undefined) {
const isValidNumbers = importNumbers(password, numbers);
const isValidNumbers = importNumbers({
password,
numbers,
algorithm: isSecp256k1 ? ECDSA.secp256k1 : undefined
});
if (isValidNumbers) {
navigate(LIST_WALLETS_PATH);
} else if (isValidNumbers === false) {
Expand All @@ -80,7 +88,7 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
setNumbersError('This wallet is already imported');
}
}
}, [importNumbers, inputErrors, navigate, password]);
}, [importNumbers, inputErrors, isSecp256k1, navigate, password]);

return (
<PageWithStepper
Expand All @@ -96,159 +104,50 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
<Typography
variant="subtitle1"
component="h2"
style={{ marginTop: '20px', marginBottom: '10px' }}
style={
hasOfflineBanner
? { marginTop: '10px', marginBottom: '5px' }
: { marginTop: '20px', marginBottom: '10px' }
}
>
Please enter your secret numbers in order to load your wallet to GemWallet.
</Typography>
<Grid container rowSpacing={0} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={6}>
<TextField
size="small"
id="numbersA"
name="numbersA"
label="Numbers A"
error={Boolean(inputErrors.numbersA)}
helperText={inputErrors.numbersA}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersA ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersB"
name="numbersB"
label="Numbers B"
error={Boolean(inputErrors.numbersB)}
helperText={inputErrors.numbersB}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersB ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersC"
name="numbersC"
label="Numbers C"
error={Boolean(inputErrors.numbersC)}
helperText={inputErrors.numbersC}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersC ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersD"
name="numbersD"
label="Numbers D"
error={Boolean(inputErrors.numbersD)}
helperText={inputErrors.numbersD}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersD ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersE"
name="numbersE"
label="Numbers E"
error={Boolean(inputErrors.numbersE)}
helperText={inputErrors.numbersE}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersE ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersF"
name="numbersF"
label="Numbers F"
error={Boolean(inputErrors.numbersF)}
helperText={inputErrors.numbersF}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersF ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersG"
name="numbersG"
label="Numbers G"
error={Boolean(inputErrors.numbersG)}
helperText={inputErrors.numbersG}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersG ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
<Grid item xs={6}>
<TextField
size="small"
id="numbersH"
name="numbersH"
label="Numbers H"
error={Boolean(inputErrors.numbersH)}
helperText={inputErrors.numbersH}
style={{
marginTop: '15px',
marginBottom: inputErrors.numbersH ? '0px' : '20px',
width: '110px'
}}
className={styles.textField}
autoComplete="off"
onBlur={handleOnBlurInput}
/>
</Grid>
{Array.from({ length: NUMBERS_COUNT }, (_, i) => {
const id = `numbers${String.fromCharCode(65 + i)}` as keyof InputErrors;
return (
<SecretNumberInput
key={id}
id={id}
label={`Numbers ${String.fromCharCode(65 + i)}`}
error={inputErrors[id]}
onBlur={handleOnBlurInput}
/>
);
})}
</Grid>
<Typography align="center" variant="caption" display="block" style={{ color: ERROR_RED }}>
{numbersError}
</Typography>
<FormControlLabel
control={
<Checkbox
checked={isSecp256k1}
onChange={() => setSecp256k1(!isSecp256k1)}
name="setSecp256k1"
color="primary"
style={{ transform: 'scale(0.9)' }}
/>
}
label={
<Typography style={{ display: 'flex', fontSize: '0.9rem' }} color={SECONDARY_GRAY}>
Use "secp256k1" algorithm{' '}
<Tooltip title="Note: if you don’t know what it means, you should probably keep it unchecked">
<InfoOutlinedIcon style={{ marginLeft: '5px' }} fontSize="small" />
</Tooltip>
</Typography>
}
/>
</PageWithStepper>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC, useCallback, useState } from 'react';

import { Wallet } from 'xrpl';
import { ECDSA, Wallet } from 'xrpl';

import { numbersToSeed, WalletToSave } from '../../../utils';
import { Congratulations } from '../Congratulations';
Expand All @@ -17,12 +17,13 @@ export const ImportSecretNumbers: FC = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
}, []);

const handleSecretNumbers = useCallback((numbers: string[]) => {
const handleSecretNumbers = useCallback((numbers: string[], algorithm: ECDSA | undefined) => {
const seed = numbersToSeed(numbers);
const wallet = Wallet.fromSeed(seed);
const wallet = Wallet.fromSeed(seed, { algorithm });
setWallet({
publicAddress: wallet.address,
seed
seed,
algorithm
});
setActiveStep(1);
}, []);
Expand Down
Loading

0 comments on commit 7620032

Please sign in to comment.