Skip to content

Commit

Permalink
Path dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
armaniferrante committed Feb 12, 2021
1 parent 29acc4b commit 7b5c60f
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 29 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"bn.js": "^5.1.2",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.0",
"ed25519-hd-key": "^1.2.0",
"immutable-tuple": "^0.4.10",
"mdi-material-ui": "^6.21.0",
"notistack": "^1.0.2",
Expand Down
82 changes: 64 additions & 18 deletions src/pages/LoginPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import {
mnemonicToSeed,
storeMnemonicAndSeed,
} from '../utils/wallet-seed';
import { getAccountFromSeed } from '../utils/walletProvider/localStorage.js';
import { DERIVATION_PATH } from '../utils/walletProvider/localStorage';
import {
getAccountFromSeed,
DERIVATION_PATH,
} from '../utils/walletProvider/localStorage.js';
import { useSolanaExplorerUrlSuffix } from '../utils/connection';
import Container from '@material-ui/core/Container';
import LoadingIndicator from '../components/LoadingIndicator';
Expand All @@ -16,11 +18,15 @@ import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { Typography } from '@material-ui/core';
import TextField from '@material-ui/core/TextField';
import InputLabel from '@material-ui/core/InputLabel';
import Checkbox from '@material-ui/core/Checkbox';
import FormControl from '@material-ui/core/FormControl';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import CardActions from '@material-ui/core/CardActions';
import Button from '@material-ui/core/Button';
import Switch from '@material-ui/core/Switch';
import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import { useCallAsync } from '../utils/notifications';
import Link from '@material-ui/core/Link';
import { validateMnemonic } from 'bip39';
Expand Down Expand Up @@ -315,19 +321,29 @@ function RestoreWalletForm({ goBack }) {
}

function DerivedAccounts({ goBack, mnemonic, seed, password }) {
const [useBip44, setUseBip44] = useState(true);
const callAsync = useCallAsync();
const urlSuffix = useSolanaExplorerUrlSuffix();
const derivationPath = useBip44
? DERIVATION_PATH.bip44
: DERIVATION_PATH.deprecated;
const [dPathMenuItem, setDPathMenuItem] = useState(
DerivationPathMenuItem.Bip44,
);

const accounts = [...Array(10)].map((_, idx) => {
return getAccountFromSeed(Buffer.from(seed, 'hex'), idx, derivationPath);
return getAccountFromSeed(
Buffer.from(seed, 'hex'),
idx,
toDerivationPath(dPathMenuItem),
);
});

function submit() {
callAsync(storeMnemonicAndSeed(mnemonic, seed, password, derivationPath));
callAsync(
storeMnemonicAndSeed(
mnemonic,
seed,
password,
toDerivationPath(dPathMenuItem),
),
);
}

return (
Expand All @@ -342,16 +358,22 @@ function DerivedAccounts({ goBack, mnemonic, seed, password }) {
<Typography variant="h5" gutterBottom>
Derivable Accounts
</Typography>
<FormControlLabel
control={
<Switch
checked={useBip44}
onChange={() => setUseBip44(!useBip44)}
/>
}
labelPlacement={'start'}
label={useBip44 ? 'BIP 44' : 'Deprecated'}
/>
<FormControl variant="outlined">
<Select
value={dPathMenuItem}
onChange={(e) => setDPathMenuItem(e.target.value)}
>
<MenuItem value={DerivationPathMenuItem.Bip44}>
{`m/44'/501'/0'`}
</MenuItem>
<MenuItem value={DerivationPathMenuItem.Bip44Change}>
{`m/44'/501'/0'/0'`}
</MenuItem>
<MenuItem value={DerivationPathMenuItem.Deprecated}>
{`m/501'/0'/0/0 (deprecated)`}
</MenuItem>
</Select>
</FormControl>
</div>
{accounts.map((acc) => {
return (
Expand Down Expand Up @@ -381,3 +403,27 @@ function DerivedAccounts({ goBack, mnemonic, seed, password }) {
</Card>
);
}

// Material UI's Select doesn't render properly when using an `undefined` value,
// so we define this type and the subsequent `toDerivationPath` translaotr as a
// workaround.
//
// DERIVATION_PATH.deprecated is always undefined.
const DerivationPathMenuItem = {
Deprecated: 0,
Bip44: 1,
Bip44Change: 2,
};

function toDerivationPath(dPathMenuItem) {
switch (dPathMenuItem) {
case DerivationPathMenuItem.Deprecated:
return DERIVATION_PATH.deprecated;
case DerivationPathMenuItem.Bip44:
return DERIVATION_PATH.bip44;
case DerivationPathMenuItem.Bip44Change:
return DERIVATION_PATH.bip44Change;
default:
throw new Error(`invalid derivation path: ${dPathMenuItem}`);
}
}
18 changes: 13 additions & 5 deletions src/utils/walletProvider/localStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,37 @@ import * as bip32 from 'bip32';
import nacl from 'tweetnacl';
import { Account } from '@solana/web3.js';
import bs58 from 'bs58';
import { derivePath } from 'ed25519-hd-key';

export const DERIVATION_PATH = {
deprecated: undefined,
bip44: 'bip44',
bip44Change: 'bip44Change',
};

// morning toast tornado know rebuild vote calm can middle prison census there
export function getAccountFromSeed(
seed,
walletIndex,
dPath = undefined,
accountIndex = 0,
) {
const path = derivationPath(walletIndex, dPath, accountIndex);
const derivedSeed = bip32.fromSeed(seed).derivePath(path).privateKey;
console.log('dpath', dPath);
const derivedSeed = deriveSeed(seed, walletIndex, dPath, accountIndex);
return new Account(nacl.sign.keyPair.fromSeed(derivedSeed).secretKey);
}

function derivationPath(walletIndex, derivationPath, accountIndex) {
function deriveSeed(seed, walletIndex, derivationPath, accountIndex) {
switch (derivationPath) {
case DERIVATION_PATH.deprecated:
return `m/501'/${walletIndex}'/0/${accountIndex}`;
const path = `m/501'/${walletIndex}'/0/${accountIndex}`;
return bip32.fromSeed(seed).derivePath(path).privateKey;
case DERIVATION_PATH.bip44:
return `m/44'/501'/${walletIndex}'/${accountIndex}`;
const path44 = `m/44'/501'/${walletIndex}'`;
return derivePath(path44, seed).key;
case DERIVATION_PATH.bip44Change:
const path44Change = `m/44'/501'/${walletIndex}'/0'`;
return derivePath(path44Change, seed).key;
default:
throw new Error(`invalid derivation path: ${derivationPath}`);
}
Expand Down
31 changes: 25 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3424,6 +3424,16 @@ bip32@^2.0.5:
typeforce "^1.11.5"
wif "^2.0.6"

bip39@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.2.tgz#2baf42ff3071fc9ddd5103de92e8f80d9257ee32"
integrity sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==
dependencies:
"@types/node" "11.11.6"
create-hash "^1.1.0"
pbkdf2 "^3.0.9"
randombytes "^2.0.1"

bip39@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.3.tgz#4a8b79067d6ed2e74f9199ac994a2ab61b176760"
Expand Down Expand Up @@ -4438,7 +4448,7 @@ create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
ripemd160 "^2.0.1"
sha.js "^2.4.0"

create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
create-hmac@1.1.7, create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
Expand Down Expand Up @@ -5159,6 +5169,15 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"

ed25519-hd-key@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/ed25519-hd-key/-/ed25519-hd-key-1.2.0.tgz#819d43c6a96477c9385bd121dccc94dbc6c6598c"
integrity sha512-pwES3tQ4Z8g3sfIBZEgtuTwFtHq5AlB9L8k9a48k7qPn74q2OmgrrgkdwyJ+P2GVTOBVCClAC7w21Wpksso3gw==
dependencies:
bip39 "3.0.2"
create-hmac "1.1.7"
tweetnacl "1.0.3"

ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
Expand Down Expand Up @@ -12715,16 +12734,16 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"

tweetnacl@1.0.3, tweetnacl@^1.0.0, tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==

tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=

tweetnacl@^1.0.0, tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==

type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
Expand Down

0 comments on commit 7b5c60f

Please sign in to comment.