diff --git a/package.json b/package.json
index 50cbe93a..71d7a227 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/pages/LoginPage.js b/src/pages/LoginPage.js
index 69f599c4..424400e4 100644
--- a/src/pages/LoginPage.js
+++ b/src/pages/LoginPage.js
@@ -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';
@@ -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';
@@ -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 (
@@ -342,16 +358,22 @@ function DerivedAccounts({ goBack, mnemonic, seed, password }) {
Derivable Accounts
- setUseBip44(!useBip44)}
- />
- }
- labelPlacement={'start'}
- label={useBip44 ? 'BIP 44' : 'Deprecated'}
- />
+
+
+
{accounts.map((acc) => {
return (
@@ -381,3 +403,27 @@ function DerivedAccounts({ goBack, mnemonic, seed, password }) {
);
}
+
+// 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}`);
+ }
+}
diff --git a/src/utils/walletProvider/localStorage.js b/src/utils/walletProvider/localStorage.js
index ec530b4a..fbabc166 100644
--- a/src/utils/walletProvider/localStorage.js
+++ b/src/utils/walletProvider/localStorage.js
@@ -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}`);
}
diff --git a/yarn.lock b/yarn.lock
index ecb295fe..ac65f31e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -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"
@@ -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==
@@ -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"
@@ -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"