Skip to content

Commit 7620032

Browse files
Support secp256k1 for numbers (#395)
* 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
1 parent 25beb8c commit 7620032

File tree

10 files changed

+154
-317
lines changed

10 files changed

+154
-317
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Grid, TextField } from '@mui/material';
2+
import { FC, FocusEvent } from 'react';
3+
import styles from './styles.module.css';
4+
import { useNetwork } from '../../../contexts';
5+
6+
export interface SecretNumberInputProps {
7+
id: string;
8+
label: string;
9+
error: string;
10+
onBlur: (e: FocusEvent<HTMLInputElement>) => void;
11+
}
12+
13+
export const SecretNumberInput: FC<SecretNumberInputProps> = ({ id, label, error, onBlur }) => {
14+
const { hasOfflineBanner } = useNetwork();
15+
16+
return (
17+
<Grid item xs={6}>
18+
<TextField
19+
size="small"
20+
id={id}
21+
name={id}
22+
label={label}
23+
error={Boolean(error)}
24+
helperText={error}
25+
style={{
26+
marginTop: '10px',
27+
marginBottom: error ? '0px' : hasOfflineBanner ? '10px' : '20px',
28+
width: '110px'
29+
}}
30+
className={styles.textField}
31+
autoComplete="off"
32+
onBlur={onBlur}
33+
/>
34+
</Grid>
35+
);
36+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './SecretNumberInput';

packages/extension/src/components/pages/AddNewWallet/ImportNewWallet/ImportSecretNumbers/styles.module.css renamed to packages/extension/src/components/atoms/SecretNumberInput/styles.module.css

File renamed without changes.

packages/extension/src/components/atoms/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from './Logo';
44
export * from './NFTImage';
55
export * from './NumericInput';
66
export * from './PrivateRoute';
7+
export * from './SecretNumberInput';
78
export * from './TileLoader';
89
export * from './TokenLoader';
910
export * from './Tokens';

packages/extension/src/components/pages/AddNewWallet/ImportNewWallet/ImportSecretNumbers/SecretNumbers.test.tsx renamed to packages/extension/src/components/pages/AddNewWallet/ImportNewWallet/ImportSecretNumbers/ImportSecretNumbers.test.tsx

File renamed without changes.
Lines changed: 52 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { FC, useCallback, useState, FocusEvent } from 'react';
22

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

6-
import { ERROR_RED, LIST_WALLETS_PATH } from '../../../../../constants';
7-
import { useWallet } from '../../../../../contexts';
7+
import { ERROR_RED, LIST_WALLETS_PATH, SECONDARY_GRAY } from '../../../../../constants';
8+
import { useNetwork, useWallet } from '../../../../../contexts';
89
import { PageWithStepper } from '../../../../templates';
9-
import styles from './styles.module.css';
10-
11-
const schemaInput = new RegExp(/^[0-9]{6}$/);
10+
import { ECDSA } from 'xrpl';
11+
import { SecretNumberInput } from '../../../../atoms';
1212

1313
type InputErrors = {
1414
numbersA: string;
@@ -22,6 +22,8 @@ type InputErrors = {
2222
};
2323

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

2628
export interface ImportSecretNumbersProps {
2729
activeStep: number;
@@ -36,6 +38,8 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
3638
}) => {
3739
const navigate = useNavigate();
3840
const { importNumbers } = useWallet();
41+
const { hasOfflineBanner } = useNetwork();
42+
const [isSecp256k1, setSecp256k1] = useState(false);
3943
const [numbersError, setNumbersError] = useState('');
4044
const [inputErrors, setInputErrors] = useState<InputErrors>({
4145
numbersA: '',
@@ -71,7 +75,11 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
7175
);
7276

7377
if (numbers.find((number) => !schemaInput.test(number)) === undefined) {
74-
const isValidNumbers = importNumbers(password, numbers);
78+
const isValidNumbers = importNumbers({
79+
password,
80+
numbers,
81+
algorithm: isSecp256k1 ? ECDSA.secp256k1 : undefined
82+
});
7583
if (isValidNumbers) {
7684
navigate(LIST_WALLETS_PATH);
7785
} else if (isValidNumbers === false) {
@@ -80,7 +88,7 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
8088
setNumbersError('This wallet is already imported');
8189
}
8290
}
83-
}, [importNumbers, inputErrors, navigate, password]);
91+
}, [importNumbers, inputErrors, isSecp256k1, navigate, password]);
8492

8593
return (
8694
<PageWithStepper
@@ -96,159 +104,50 @@ export const ImportSecretNumbers: FC<ImportSecretNumbersProps> = ({
96104
<Typography
97105
variant="subtitle1"
98106
component="h2"
99-
style={{ marginTop: '20px', marginBottom: '10px' }}
107+
style={
108+
hasOfflineBanner
109+
? { marginTop: '10px', marginBottom: '5px' }
110+
: { marginTop: '20px', marginBottom: '10px' }
111+
}
100112
>
101113
Please enter your secret numbers in order to load your wallet to GemWallet.
102114
</Typography>
103115
<Grid container rowSpacing={0} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
104-
<Grid item xs={6}>
105-
<TextField
106-
size="small"
107-
id="numbersA"
108-
name="numbersA"
109-
label="Numbers A"
110-
error={Boolean(inputErrors.numbersA)}
111-
helperText={inputErrors.numbersA}
112-
style={{
113-
marginTop: '15px',
114-
marginBottom: inputErrors.numbersA ? '0px' : '20px',
115-
width: '110px'
116-
}}
117-
className={styles.textField}
118-
autoComplete="off"
119-
onBlur={handleOnBlurInput}
120-
/>
121-
</Grid>
122-
<Grid item xs={6}>
123-
<TextField
124-
size="small"
125-
id="numbersB"
126-
name="numbersB"
127-
label="Numbers B"
128-
error={Boolean(inputErrors.numbersB)}
129-
helperText={inputErrors.numbersB}
130-
style={{
131-
marginTop: '15px',
132-
marginBottom: inputErrors.numbersB ? '0px' : '20px',
133-
width: '110px'
134-
}}
135-
className={styles.textField}
136-
autoComplete="off"
137-
onBlur={handleOnBlurInput}
138-
/>
139-
</Grid>
140-
<Grid item xs={6}>
141-
<TextField
142-
size="small"
143-
id="numbersC"
144-
name="numbersC"
145-
label="Numbers C"
146-
error={Boolean(inputErrors.numbersC)}
147-
helperText={inputErrors.numbersC}
148-
style={{
149-
marginTop: '15px',
150-
marginBottom: inputErrors.numbersC ? '0px' : '20px',
151-
width: '110px'
152-
}}
153-
className={styles.textField}
154-
autoComplete="off"
155-
onBlur={handleOnBlurInput}
156-
/>
157-
</Grid>
158-
<Grid item xs={6}>
159-
<TextField
160-
size="small"
161-
id="numbersD"
162-
name="numbersD"
163-
label="Numbers D"
164-
error={Boolean(inputErrors.numbersD)}
165-
helperText={inputErrors.numbersD}
166-
style={{
167-
marginTop: '15px',
168-
marginBottom: inputErrors.numbersD ? '0px' : '20px',
169-
width: '110px'
170-
}}
171-
className={styles.textField}
172-
autoComplete="off"
173-
onBlur={handleOnBlurInput}
174-
/>
175-
</Grid>
176-
<Grid item xs={6}>
177-
<TextField
178-
size="small"
179-
id="numbersE"
180-
name="numbersE"
181-
label="Numbers E"
182-
error={Boolean(inputErrors.numbersE)}
183-
helperText={inputErrors.numbersE}
184-
style={{
185-
marginTop: '15px',
186-
marginBottom: inputErrors.numbersE ? '0px' : '20px',
187-
width: '110px'
188-
}}
189-
className={styles.textField}
190-
autoComplete="off"
191-
onBlur={handleOnBlurInput}
192-
/>
193-
</Grid>
194-
<Grid item xs={6}>
195-
<TextField
196-
size="small"
197-
id="numbersF"
198-
name="numbersF"
199-
label="Numbers F"
200-
error={Boolean(inputErrors.numbersF)}
201-
helperText={inputErrors.numbersF}
202-
style={{
203-
marginTop: '15px',
204-
marginBottom: inputErrors.numbersF ? '0px' : '20px',
205-
width: '110px'
206-
}}
207-
className={styles.textField}
208-
autoComplete="off"
209-
onBlur={handleOnBlurInput}
210-
/>
211-
</Grid>
212-
<Grid item xs={6}>
213-
<TextField
214-
size="small"
215-
id="numbersG"
216-
name="numbersG"
217-
label="Numbers G"
218-
error={Boolean(inputErrors.numbersG)}
219-
helperText={inputErrors.numbersG}
220-
style={{
221-
marginTop: '15px',
222-
marginBottom: inputErrors.numbersG ? '0px' : '20px',
223-
width: '110px'
224-
}}
225-
className={styles.textField}
226-
autoComplete="off"
227-
onBlur={handleOnBlurInput}
228-
/>
229-
</Grid>
230-
<Grid item xs={6}>
231-
<TextField
232-
size="small"
233-
id="numbersH"
234-
name="numbersH"
235-
label="Numbers H"
236-
error={Boolean(inputErrors.numbersH)}
237-
helperText={inputErrors.numbersH}
238-
style={{
239-
marginTop: '15px',
240-
marginBottom: inputErrors.numbersH ? '0px' : '20px',
241-
width: '110px'
242-
}}
243-
className={styles.textField}
244-
autoComplete="off"
245-
onBlur={handleOnBlurInput}
246-
/>
247-
</Grid>
116+
{Array.from({ length: NUMBERS_COUNT }, (_, i) => {
117+
const id = `numbers${String.fromCharCode(65 + i)}` as keyof InputErrors;
118+
return (
119+
<SecretNumberInput
120+
key={id}
121+
id={id}
122+
label={`Numbers ${String.fromCharCode(65 + i)}`}
123+
error={inputErrors[id]}
124+
onBlur={handleOnBlurInput}
125+
/>
126+
);
127+
})}
248128
</Grid>
249129
<Typography align="center" variant="caption" display="block" style={{ color: ERROR_RED }}>
250130
{numbersError}
251131
</Typography>
132+
<FormControlLabel
133+
control={
134+
<Checkbox
135+
checked={isSecp256k1}
136+
onChange={() => setSecp256k1(!isSecp256k1)}
137+
name="setSecp256k1"
138+
color="primary"
139+
style={{ transform: 'scale(0.9)' }}
140+
/>
141+
}
142+
label={
143+
<Typography style={{ display: 'flex', fontSize: '0.9rem' }} color={SECONDARY_GRAY}>
144+
Use "secp256k1" algorithm{' '}
145+
<Tooltip title="Note: if you don’t know what it means, you should probably keep it unchecked">
146+
<InfoOutlinedIcon style={{ marginLeft: '5px' }} fontSize="small" />
147+
</Tooltip>
148+
</Typography>
149+
}
150+
/>
252151
</PageWithStepper>
253152
);
254153
};

packages/extension/src/components/pages/ImportSecretNumbers/ImportSecretNumbers.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FC, useCallback, useState } from 'react';
22

3-
import { Wallet } from 'xrpl';
3+
import { ECDSA, Wallet } from 'xrpl';
44

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

20-
const handleSecretNumbers = useCallback((numbers: string[]) => {
20+
const handleSecretNumbers = useCallback((numbers: string[], algorithm: ECDSA | undefined) => {
2121
const seed = numbersToSeed(numbers);
22-
const wallet = Wallet.fromSeed(seed);
22+
const wallet = Wallet.fromSeed(seed, { algorithm });
2323
setWallet({
2424
publicAddress: wallet.address,
25-
seed
25+
seed,
26+
algorithm
2627
});
2728
setActiveStep(1);
2829
}, []);

0 commit comments

Comments
 (0)