Derive path for eth derivation (#4732)

* derivae path for eth derivation

* remove consoles

* lint

* Apply suggestions from code review

Co-authored-by: Jaco Greeff <jacogr@gmail.com>

* applied suggestions

* lint and modifs

* Apply suggestions from code review

thanks for the suggestions!

Co-authored-by: Jaco Greeff <jacogr@gmail.com>

* Apply suggestions from code review

Co-authored-by: Jaco Greeff <jacogr@gmail.com>

* more suggestions and cleaning"

Co-authored-by: Jaco Greeff <jacogr@gmail.com>
This commit is contained in:
Antoine Estienne 2021-02-26 11:46:35 +01:00 committed by GitHub
parent c9d262a382
commit 199c9a3dfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -17,7 +17,7 @@ import { useApi, useLedger, useStepper } from '@polkadot/react-hooks';
import { keyring } from '@polkadot/ui-keyring';
import { settings } from '@polkadot/ui-settings';
import { isHex, u8aToHex } from '@polkadot/util';
import { hdLedger, keyExtractSuri, mnemonicGenerate, mnemonicValidate, randomAsU8a } from '@polkadot/util-crypto';
import { hdLedger, hdValidatePath, keyExtractSuri, mnemonicGenerate, mnemonicValidate, randomAsU8a } from '@polkadot/util-crypto';
import { useTranslation } from '../translate';
import CreateConfirmation from './CreateConfirmation';
@ -25,6 +25,8 @@ import CreateSuriLedger from './CreateSuriLedger';
import ExternalWarning from './ExternalWarning';
import PasswordInput from './PasswordInput';
const ETH_DEFAULT_PATH = "m/44'/60'/0'/0/0";
type PairType = 'ecdsa' | 'ed25519' | 'ed25519-ledger' | 'ethereum' | 'sr25519';
interface Props extends ModalProps {
@ -64,12 +66,14 @@ const STEPS_COUNT = 3;
function getSuri (seed: string, derivePath: string, pairType: PairType): string {
return pairType === 'ed25519-ledger'
? u8aToHex(hdLedger(seed, derivePath).secretKey.slice(0, 32))
: `${seed}${derivePath}`;
: pairType === 'ethereum'
? `${seed}/${derivePath}`
: `${seed}${derivePath}`;
}
function deriveValidate (seed: string, seedType: SeedType, derivePath: string, pairType: PairType): DeriveValidationOutput {
try {
const { password, path } = keyExtractSuri(`${seed}${derivePath}`);
const { password, path } = keyExtractSuri(pairType === 'ethereum' ? `${seed}/${derivePath}` : `${seed}${derivePath}`);
let result: DeriveValidationOutput = {};
// show a warning in case the password contains an unintended / character
@ -87,6 +91,10 @@ function deriveValidate (seed: string, seedType: SeedType, derivePath: string, p
return { ...result, error: 'PASSWORD_IGNORED' };
}
if (pairType === 'ethereum' && !hdValidatePath(derivePath)) {
return { ...result, error: 'INVALID_DERIVATION_PATH' };
}
return result;
} catch (error) {
return { error: (error as Error).message };
@ -134,19 +142,18 @@ function generateSeed (_seed: string | undefined | null, derivePath: string, see
}
function updateAddress (seed: string, derivePath: string, seedType: SeedType, pairType: PairType): AddressState {
const deriveValidation = deriveValidate(seed, seedType, derivePath, pairType);
let address: string | null = null;
let deriveValidation: DeriveValidationOutput = deriveValidate(seed, seedType, derivePath, pairType);
let isSeedValid = seedType === 'raw'
? rawValidate(seed)
: mnemonicValidate(seed);
let address: string | null = null;
if (!deriveValidation?.error && isSeedValid) {
try {
address = addressFromSeed(seed, derivePath, pairType);
} catch (error) {
console.error(error);
deriveValidation = { error: (error as Error).message ? (error as Error).message : (error as Error).toString() };
isSeedValid = false;
}
}
@ -197,7 +204,11 @@ function Create ({ className = '', onClose, onStatusChange, seed: propsSeed, typ
const { t } = useTranslation();
const { api, isDevelopment, isEthereum } = useApi();
const { isLedgerEnabled } = useLedger();
const [{ address, derivePath, deriveValidation, isSeedValid, pairType, seed, seedType }, setAddress] = useState<AddressState>(() => generateSeed(propsSeed, '', propsSeed ? 'raw' : 'bip', isEthereum ? 'ethereum' : propsType));
const [{ address, derivePath, deriveValidation, isSeedValid, pairType, seed, seedType }, setAddress] = useState<AddressState>(() => generateSeed(
propsSeed,
isEthereum ? ETH_DEFAULT_PATH : '',
propsSeed ? 'raw' : 'bip', isEthereum ? 'ethereum' : propsType
));
const [isMnemonicSaved, setIsMnemonicSaved] = useState<boolean>(false);
const [step, nextStep, prevStep] = useStepper();
const [isBusy, setIsBusy] = useState(false);
@ -208,6 +219,7 @@ function Create ({ className = '', onClose, onStatusChange, seed: propsSeed, typ
const isValid = isFirstStepValid && isSecondStepValid;
const errorIndex = useRef<Record<string, string>>({
INVALID_DERIVATION_PATH: t<string>('This is an invalid derivation path.'),
PASSWORD_IGNORED: t<string>('Password are ignored for hex seed'),
SOFT_NOT_ALLOWED: t<string>('Soft derivation paths are not allowed on ed25519'),
WARNING_SLASH_PASSWORD: t<string>('Your password contains at least one "/" character. Disregard this warning if it is intended.')
@ -240,9 +252,9 @@ function Create ({ className = '', onClose, onStatusChange, seed: propsSeed, typ
const _onChangePairType = useCallback(
(newPairType: PairType) => setAddress(
updateAddress(seed, '', seedType, newPairType)
updateAddress(seed, isEthereum ? ETH_DEFAULT_PATH : '', seedType, newPairType)
),
[seed, seedType]
[seed, seedType, isEthereum]
);
const _selectSeedType = useCallback(
@ -387,13 +399,15 @@ function Create ({ className = '', onClose, onStatusChange, seed: propsSeed, typ
label={t<string>('secret derivation path')}
onChange={_onChangePath}
placeholder={
seedType === 'raw'
? pairType === 'sr25519'
? t<string>('//hard/soft')
: t<string>('//hard')
: pairType === 'sr25519'
? t<string>('//hard/soft///password')
: t<string>('//hard///password')
pairType === 'ethereum'
? ETH_DEFAULT_PATH
: seedType === 'raw'
? pairType === 'sr25519'
? t<string>('//hard/soft')
: t<string>('//hard')
: pairType === 'sr25519'
? t<string>('//hard/soft///password')
: t<string>('//hard///password')
}
tabIndex={-1}
value={derivePath}