on master help sign in
keys: address PR feedback, refactor keyfile gen

This commit refactors keyfile generation to use the same base hook `useKeyfileGenerator` in both the Activation and Home views. The hook is refactored to accept an array of one or more seeds, and an optional Point instance. Then, two wrapper hooks are created to reuse the base logic. The difference is in how the seeds are derived for consumption by the base hook.

commit63bd5243d473d23cb24583effc1d45ab6be3a1aa authortomholford <tomholford@users.noreply.github.com> dateSun 6 Feb 2022, 13:39 (5 years ago) parent1226972
9 files changed+232−249
src/lib/useKeyfileGenerator.ts+163−50 src/lib/useMultiKeyfileGenerator.ts−180 src/lib/useRoller.ts+1−6 src/urbit-key-generation.d.ts+56 src/views/Activate/MasterKeyDownload.tsx+4−5 src/views/UrbitID/DownloadKeys.js+2−2 src/views/UrbitID/Home.tsx+2−2 src/views/UrbitOS/Home.tsx+2−2 src/views/UrbitOS/NetworkKeys.tsx+2−2
src/lib/useKeyfileGenerator.ts+163−50
@@ -1,44 +1,66 @@
11import { useCallback, useMemo, useEffect, useState } from 'react';
2−import { Just, Nothing } from 'folktale/maybe';
2+import { Just } from 'folktale/maybe';
33import saveAs from 'file-saver';
4−
54import { useWallet } from 'store/wallet';
6−import { useRollerStore } from 'store/rollerStore';
7−
5+import { EMPTY_POINT, useRollerStore } from 'store/rollerStore';
86import { generateCode } from 'lib/networkCode';
9−
107import {
118 attemptNetworkSeedDerivation,
9+ deriveNetworkSeedFromUrbitWallet,
1210 keysMatchChain,
1311 deriveNetworkKeys,
1412 compileMultiKey,
1513} from './keys';
1614import { stripSigPrefix } from 'form/formatters';
15+import useRoller from './useRoller';
16+import Point from './types/Point';
17+import { toL1Details } from './utils/point';
18+import { ETH_ZERO_ADDR } from './constants';
1719
1820interface useKeyfileGeneratorArgs {
19− seed?: string;
21+ point?: Point;
22+ seeds: string[];
2023}
2124
2225/**
23− * seed - (optional) derived from wallet, mnemonic, or token by default (if possible)
26+ * The default Keyfile Generator. Can be used by itself, or composed with
27+ * other hooks (see `useActivationKeyfileGenerator` and `useHomeKeyfileGenerator`).
28+ *
29+ * @param point Point - (optional) the Point for which to generate keys
30+ * @param seeds string[] - (required) one or more seeds consumed by deriveNetworkKeys
31+ *
2432 */
25−export default function useKeyfileGenerator({ seed }: useKeyfileGeneratorArgs) {
26− const { urbitWallet, wallet, authMnemonic, authToken }: any = useWallet();
27− const { point } = useRollerStore();
28−
33+function useKeyfileGenerator({ point, seeds }: useKeyfileGeneratorArgs) {
34+ // exported keyfile generator properties
2935 const [notice, setNotice] = useState('Deriving networking keys...');
3036 const [downloaded, setDownloaded] = useState(false);
3137 const [generating, setGenerating] = useState(true);
3238 const [keyfile, setKeyfile] = useState<boolean | string>(false);
3339 const [code, setCode] = useState(false);
3440
35− const networkRevision = Number(point.keyRevisionNumber);
36− const canManage = point.isOwner || point.isManagementProxy;
41+ // resolved point
42+ const { point: storedPoint } = useRollerStore();
43+ const resolvedPoint = useMemo(() => {
44+ return point || storedPoint;
45+ }, [point, storedPoint]);
46+
47+ const networkRevision = useMemo(() => {
48+ return Number(resolvedPoint.keyRevisionNumber);
49+ }, [resolvedPoint]);
50+ const canManage = useMemo(() => {
51+ return resolvedPoint.isOwner || resolvedPoint.isManagementProxy;
52+ }, [resolvedPoint]);
3753
3854 const hasNetworkKeys = networkRevision > 0;
3955 const available = canManage && hasNetworkKeys && !!keyfile;
4056
4157 const generate = useCallback(async () => {
58+ // Point still loading ...
59+ if (resolvedPoint.value === EMPTY_POINT.value) {
60+ console.log('Loading point data ...');
61+ return;
62+ }
63+
4264 if (!hasNetworkKeys) {
4365 setGenerating(false);
4466 setNotice('Network keys not yet set.');
@@ -48,19 +70,9 @@ export default function useKeyfileGenerator({ seed }: useKeyfileGeneratorArgs) {
4870 return;
4971 }
5072
51− const networkSeed = seed
52− ? Just(seed)
53− : await attemptNetworkSeedDerivation({
54− urbitWallet,
55− wallet,
56− authMnemonic,
57− details: point,
58− authToken,
59− point: point.value,
60− revision: networkRevision,
61− });
62−
63− if (Nothing.hasInstance(networkSeed)) {
73+ // seeds were either generated non-deterministically,
74+ // or still being derived ...
75+ if (seeds.length === 0) {
6476 setGenerating(false);
6577 setNotice(
6678 'Custom or nondeterministic networking keys cannot be re-downloaded.'
@@ -69,11 +81,10 @@ export default function useKeyfileGenerator({ seed }: useKeyfileGeneratorArgs) {
6981 return;
7082 }
7183
72− const _networkSeed = networkSeed.value;
73−
74− const pair = deriveNetworkKeys(_networkSeed);
84+ const pairs = seeds.map(seed => deriveNetworkKeys(seed));
85+ const firstPair = pairs[0];
7586
76− if (!keysMatchChain(pair, point)) {
87+ if (!keysMatchChain(firstPair, resolvedPoint)) {
7788 setGenerating(false);
7889 setNotice('Derived networking keys do not match on-chain details.');
7990 console.log(`keys do not match details for revision ${networkRevision}`);
@@ -81,31 +92,22 @@ export default function useKeyfileGenerator({ seed }: useKeyfileGeneratorArgs) {
8192 }
8293
8394 setNotice('');
84− setCode(generateCode(pair));
95+ setCode(generateCode(firstPair));
8596 setKeyfile(
86− compileMultiKey(point.value, [
87− {
88− revision: networkRevision,
89− pair: pair,
90− },
91− ])
97+ compileMultiKey(
98+ resolvedPoint.value,
99+ pairs.map((pair, k) => {
100+ return { revision: networkRevision + k, pair };
101+ })
102+ )
92103 );
104+ console.log(`keyfile generated for revision ${networkRevision}`);
93105 setGenerating(false);
94− }, [
95− networkRevision,
96− hasNetworkKeys,
97− seed,
98− urbitWallet,
99− wallet,
100− authMnemonic,
101− setCode,
102− point,
103− authToken,
104− ]);
106+ }, [hasNetworkKeys, seeds, resolvedPoint, networkRevision]);
105107
106108 const filename = useMemo(() => {
107− return `${stripSigPrefix(point.patp)}-${networkRevision}.key`;
108− }, [point, networkRevision]);
109+ return `${stripSigPrefix(resolvedPoint.patp)}-${networkRevision}.key`;
110+ }, [resolvedPoint, networkRevision]);
109111
110112 const download = useCallback(() => {
111113 if (typeof keyfile !== 'string') {
@@ -138,3 +140,114 @@ export default function useKeyfileGenerator({ seed }: useKeyfileGeneratorArgs) {
138140
139141 return { ...values, bind: values };
140142}
143+
144+interface ActivationKeyfileGeneratorArgs {
145+ pointId: number;
146+ wallets: UrbitWallet[];
147+}
148+
149+/**
150+ * This Activation Keyfile Generator is used to derive a multikey during the
151+ * Activation Flow. At the time of generation, there is no Point yet set in
152+ * the Roller Store, so we need to look it up by Point ID (to retreive the
153+ * current key revision via API).
154+ *
155+ * @param pointId number - (required) the point ID for which to generate keys
156+ * @param wallets UrbitWallet[] - (required) for each wallet,
157+ * a seed + revision pair is generated and consumed by `compileMultiKey`.
158+ * It should be an array of [deterministic invite wallet, non-deterministic
159+ * master ticket wallet] (the sending and receiving wallets)
160+ */
161+export const useActivationKeyfileGenerator = ({
162+ pointId,
163+ wallets,
164+}: ActivationKeyfileGeneratorArgs) => {
165+ // resolve point
166+ const { api } = useRoller();
167+ const [point, setPoint] = useState<Point>(EMPTY_POINT);
168+
169+ const resolvePoint = useCallback(async () => {
170+ const resolved = new Point({
171+ value: pointId,
172+ details: toL1Details(await api.getPoint(pointId)),
173+ address: ETH_ZERO_ADDR,
174+ });
175+
176+ setPoint(resolved);
177+ }, [api, pointId]);
178+
179+ useEffect(() => {
180+ resolvePoint();
181+ }, [resolvePoint]);
182+
183+ // derive seeds from wallets
184+ const [seeds, setSeeds] = useState<string[]>([]);
185+ const deriveSeeds = useCallback(async () => {
186+ if (!('keyRevisionNumber' in point)) {
187+ return;
188+ }
189+
190+ const derivedSeeds = await Promise.all(
191+ wallets.map(async (w, i) => {
192+ return deriveNetworkSeedFromUrbitWallet(w, point.keyRevisionNumber + i);
193+ })
194+ );
195+
196+ setSeeds(
197+ derivedSeeds
198+ .map(maybeSeed => maybeSeed.getOrElse(null))
199+ .filter(s => s !== null)
200+ );
201+ }, [point, wallets]);
202+
203+ useEffect(() => {
204+ deriveSeeds();
205+ // eslint-disable-next-line react-hooks/exhaustive-deps
206+ }, [point]);
207+
208+ return useKeyfileGenerator({ point, seeds });
209+};
210+
211+interface HomeKeyfileGeneratorArgs {
212+ seed?: string;
213+}
214+
215+/**
216+ * This Home Keyfile Generator is used to derive a multikey in multiple views
217+ * in the Bridge dashboard (Set Network Keys, Home > ID, Home > OS views).
218+ *
219+ * * @param seed string - (optional) default: provided by the logged in wallet
220+ */
221+export const useHomeKeyfileGenerator = ({ seed }: HomeKeyfileGeneratorArgs) => {
222+ // use provided seed, or fallback to deriving from logged in wallet
223+ const { point } = useRollerStore();
224+ const { authMnemonic, authToken, urbitWallet, wallet }: any = useWallet();
225+ const [seeds, setSeeds] = useState<string[]>([]);
226+
227+ const deriveSeeds = useCallback(async () => {
228+ if (seed) {
229+ setSeeds([seed]);
230+ return;
231+ }
232+
233+ const derivedSeed = await attemptNetworkSeedDerivation({
234+ urbitWallet,
235+ wallet,
236+ authMnemonic,
237+ details: point,
238+ authToken,
239+ point: point.value,
240+ revision: point.keyRevisionNumber,
241+ });
242+
243+ if (Just.hasInstance(derivedSeed)) {
244+ setSeeds([derivedSeed.value]);
245+ }
246+ }, [authMnemonic, authToken, point, seed, urbitWallet, wallet]);
247+
248+ useEffect(() => {
249+ deriveSeeds();
250+ }, [deriveSeeds]);
251+
252+ return useKeyfileGenerator({ seeds });
253+};
src/lib/useMultiKeyfileGenerator.tsdeleted−180
@@ -1,180 +0,0 @@
1−import saveAs from 'file-saver';
2−import ob from 'urbit-ob';
3−import { Nothing } from 'folktale/maybe';
4−
5−import { useCallback, useEffect, useMemo, useState } from 'react';
6−import { deriveNetworkKeys } from 'urbit-key-generation';
7−import {
8− compileMultiKey,
9− deriveNetworkSeedFromUrbitWallet,
10− keysMatchChain,
11−} from './keys';
12−import { generateCode } from './networkCode';
13−import { stripSigPrefix } from 'form/formatters';
14−import useRoller from './useRoller';
15−import Point from './types/Point';
16−
17−interface useMultiKeyfileGeneratorArgs {
18− point: number;
19− inviteWallet: UrbitWallet;
20− inviteMasterTicketWallet: UrbitWallet;
21−}
22−
23−/**
24− * defaults:
25− * - point: the activating point
26− * - inviteWallet: determinstic invite wallet (generated during invite creation)
27− * - inviteMasterTicketWallet: the non-deterministic wallet (generated during invite acceptance);
28− * it is the wallet that receives the point transfer during Activation (and accessed by Master Ticket)
29− *
30− * This should only be used during the Activation flow,
31− * because the point will be "in between" key revisions.
32− * (0 --> 1 is when the invite is generated, 1 --> 2 is upon invite acceptance).
33− *
34− * For other keyfile use cases, see: useKeyfileGenerator
35− */
36−export default function useMultiKeyfileGenerator({
37− point,
38− inviteWallet,
39− inviteMasterTicketWallet,
40−}: useMultiKeyfileGeneratorArgs) {
41− const [notice, setNotice] = useState('Deriving networking keys...');
42− const [downloaded, setDownloaded] = useState(false);
43− const [generating, setGenerating] = useState(true);
44− const [keyfile, setKeyfile] = useState<boolean | string>(false);
45− const [code, setCode] = useState(false);
46− const [pointDetails, setPointDetails] = useState<Point | null>(null);
47− const { initPoint } = useRoller();
48−
49− const fetchPoint = useCallback(async () => {
50− setPointDetails(await initPoint(point));
51− }, [initPoint, point]);
52−
53− useEffect(() => {
54− fetchPoint();
55− }, [fetchPoint]);
56−
57− const currentRevision = useMemo(
58− () => (pointDetails ? pointDetails.keyRevisionNumber : 0),
59− [pointDetails]
60− );
61− const nextRevision = useMemo(() => currentRevision + 1, [currentRevision]);
62−
63− const pairFromRevision = useCallback(
64− async (revision: number, derivationWallet) => {
65− if (!pointDetails) {
66− return;
67− }
68−
69− const networkSeed = await deriveNetworkSeedFromUrbitWallet({
70− urbitWallet: derivationWallet,
71− revision,
72− });
73−
74− if (Nothing.hasInstance(networkSeed)) {
75− setGenerating(false);
76− setNotice(
77− 'Custom or nondeterministic networking keys cannot be re-downloaded.'
78− );
79− console.log(`seed is nondeterminable for revision ${revision}`);
80− return;
81− }
82−
83− const _networkSeed = networkSeed.value;
84−
85− return deriveNetworkKeys(_networkSeed);
86− },
87− [pointDetails]
88− );
89−
90− const hasNetworkKeys = currentRevision > 0;
91−
92− const generate = useCallback(async () => {
93− if (!hasNetworkKeys) {
94− setGenerating(false);
95− setNotice('Network keys not yet set.');
96− console.log(
97− `no networking keys available for revision ${currentRevision}`
98− );
99− return;
100− }
101−
102− const currentPair = await pairFromRevision(currentRevision, inviteWallet);
103−
104− if (!currentPair || !keysMatchChain(currentPair, pointDetails || {})) {
105− setGenerating(false);
106− setNotice('Derived networking keys do not match on-chain details.');
107− console.log(`keys do not match details for revision ${currentRevision}`);
108− return;
109− }
110−
111− // During the activation flow, we pass in the
112− // inviteMasterTicketWallet to derive the multikey
113− // During the activation flow, we want to use the invite wallet for the next pair
114− const nextPair = await pairFromRevision(
115− nextRevision,
116− inviteMasterTicketWallet
117− );
118−
119− setNotice('');
120− setCode(generateCode(currentPair));
121− setKeyfile(
122− compileMultiKey(point, [
123− {
124− revision: currentRevision,
125− pair: currentPair,
126− },
127− {
128− revision: nextRevision,
129− pair: nextPair,
130− },
131− ])
132− );
133− setGenerating(false);
134− }, [
135− hasNetworkKeys,
136− pairFromRevision,
137− currentRevision,
138− inviteWallet,
139− pointDetails,
140− nextRevision,
141− inviteMasterTicketWallet,
142− point,
143− ]);
144−
145− const filename = useMemo(() => {
146− return `${stripSigPrefix(
147− ob.patp(point)
148− )}-${currentRevision}-${nextRevision}.key`;
149− }, [point, currentRevision, nextRevision]);
150−
151− const download = useCallback(() => {
152− if (typeof keyfile !== 'string') {
153− return;
154− }
155−
156− saveAs(
157− new Blob([keyfile], {
158− type: 'text/plain;charset=utf-8',
159− }),
160− filename
161− );
162− setDownloaded(true);
163− }, [filename, keyfile]);
164−
165− useEffect(() => {
166− generate();
167− }, [generate]);
168−
169− const output = {
170− generating,
171− downloaded,
172− download,
173− filename,
174− notice,
175− keyfile,
176− code,
177− };
178−
179− return { ...output, bind: output };
180−}
src/lib/useRoller.ts+1−6
@@ -31,12 +31,7 @@ import {
3131 registerProxyAddress,
3232 isL2Spawn,
3333} from './utils/roller';
34−import {
35− ETH_ZERO_ADDR,
36− POINT_DOMINIONS,
37− ROLLER_HOSTS,
38− TEN_SECONDS,
39−} from './constants';
34+import { POINT_DOMINIONS, ROLLER_HOSTS, TEN_SECONDS } from './constants';
4035
4136import {
4237 Config,
src/urbit-key-generation.d.ts+56
@@ -1,3 +1,18 @@
1+type ValueOf<T> = T[keyof T];
2+
3+type CHILD_SEED_TYPES = {
4+ OWNERSHIP: 'ownership';
5+ TRANSFER: 'transfer';
6+ SPAWN: 'spawn';
7+ VOTING: 'voting';
8+ MANAGEMENT: 'management';
9+ NETWORK: 'network';
10+ BITCOIN_MAINNET: 'bitcoinMainnet';
11+ BITCOIN_TESTNET: 'bitcoinTestnet';
12+};
13+
14+type ChildSeedType = ValueOf<CHILD_SEED_TYPES>;
15+
116interface NetworkKeys {
217 crypt: {
318 private: string;
@@ -23,6 +38,8 @@ interface WalletNode {
2338 derivationPath: string;
2439}
2540
41+interface BitcoinWallet extends WalletNode {}
42+
2643interface WalletConfig {
2744 ticket: string;
2845 ship: number;
@@ -55,15 +72,54 @@ interface UrbitWallet {
5572 | {};
5673 voting?: WalletNode;
5774 spawn?: WalletNode;
75+ bitcoinTestnet: BitcoinWallet;
76+ bitcoinMainnet: BitcoinWallet;
5877}
5978
6079declare module 'urbit-key-generation' {
80+ const CHILD_SEED_TYPES: CHILD_SEED_TYPES;
81+ function addressFromSecp256k1Public(pub: string): string;
82+ function argon2u(entropy: Buffer, ship: number): Promise<Uint8Array>;
6183 function combine(shards: string[]): string;
84+ function deriveNetworkInfo(
85+ mnemonic: string,
86+ revision: number,
87+ passphrase?: string
88+ ): { type: 'network'; seed: string; keys: WalletNodeKeys };
6289 function deriveNetworkKeys(hex: string): NetworkKeys;
90+ function deriveNetworkSeed(
91+ mnemonic: string,
92+ passphrase: string,
93+ revision: number
94+ ): string;
95+ function deriveNode(
96+ master: Uint8Array,
97+ type: ChildSeedType,
98+ derivationPath: string,
99+ passphrase?: string
100+ ): WalletNode;
101+ function deriveNodeKeys(
102+ mnemonic: string,
103+ derivationPath: string,
104+ passphrase?: string
105+ ): WalletNodeKeys;
106+ function deriveNodeSeed(master: Uint8Array, type: ChildSeedType): string;
107+ function generateCode(pair: NetworkKeys, step: number): string;
108+ function generateKeyfile(
109+ pair: NetworkKeys,
110+ point: number,
111+ revision: number
112+ ): string;
113+ function generateOwnershipWallet({
114+ ticket,
115+ ship,
116+ passphrase,
117+ }: WalletConfig): UrbitWallet;
63118 function generateWallet({
64119 ticket,
65120 ship,
66121 passphrase,
67122 boot,
68123 }: WalletConfig): UrbitWallet;
124+ function shard(ticket: string): string[];
69125}
src/views/Activate/MasterKeyDownload.tsx+4−5
@@ -18,7 +18,7 @@ import { DEFAULT_FADE_TIMEOUT, MASTER_KEY_DURATION } from 'lib/constants';
1818import { timeout } from 'lib/timeout';
1919import { downloadWallet } from 'lib/invite';
2020import View from 'components/View';
21−import useMultiKeyfileGenerator from 'lib/useMultiKeyfileGenerator';
21+import { useActivationKeyfileGenerator } from 'lib/useKeyfileGenerator';
2222
2323const MasterKeyDownload = () => {
2424 const {
@@ -46,10 +46,9 @@ const MasterKeyDownload = () => {
4646 Just: (p: any) => p.value.toFixed(),
4747 });
4848
49− const { keyfile, filename } = useMultiKeyfileGenerator({
50− point,
51− inviteWallet,
52− inviteMasterTicketWallet,
49+ const { keyfile, filename } = useActivationKeyfileGenerator({
50+ pointId: point,
51+ wallets: [inviteWallet.value, inviteMasterTicketWallet.value],
5352 });
5453
5554 // sync paper value to activation state
src/views/UrbitID/DownloadKeys.js+2−2
@@ -9,7 +9,7 @@ import { DownloadButton, RestartButton } from 'components/Buttons';
99import PaperBuilder from 'components/PaperBuilder';
1010
1111import { downloadWallet } from 'lib/invite';
12−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
12+import { useHomeKeyfileGenerator } from 'lib/useKeyfileGenerator';
1313
1414import { useWallet } from 'store/wallet';
1515import { Grid, P } from 'indigo-react';
@@ -26,7 +26,7 @@ export default function AdminRedownload() {
2626 const _urbitWallet = need.wallet(urbitWallet);
2727 const point = need.point(pointCursor);
2828
29− const { keyfile, filename } = useKeyfileGenerator({});
29+ const { keyfile, filename } = useHomeKeyfileGenerator({});
3030
3131 const [paper, setPaper] = useState(Nothing());
3232 const [downloaded, setDownloaded] = useState(false);
src/views/UrbitID/Home.tsx+2−2
@@ -13,7 +13,7 @@ import {
1313} from 'lib/constants';
1414import { abbreviateAddress } from 'lib/utils/address';
1515import { downloadWallet } from 'lib/invite';
16−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
16+import { useHomeKeyfileGenerator } from 'lib/useKeyfileGenerator';
1717
1818import { useWallet } from 'store/wallet';
1919import { useRollerStore } from 'store/rollerStore';
@@ -43,7 +43,7 @@ export default function UrbitIDHome() {
4343 return null;
4444 }
4545 }, [urbitWallet]);
46− const { keyfile, filename } = useKeyfileGenerator({});
46+ const { keyfile, filename } = useHomeKeyfileGenerator({});
4747 const [paper, setPaper] = useState(Nothing());
4848
4949 const downloadKeys = useCallback(() => {
src/views/UrbitOS/Home.tsx+2−2
@@ -9,7 +9,7 @@ import BodyPane from 'components/L2/Window/BodyPane';
99import { ReactComponent as KeyfileIcon } from 'assets/keyfile.svg';
1010
1111import { useLocalRouter } from 'lib/LocalRouter';
12−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
12+import { useHomeKeyfileGenerator } from 'lib/useKeyfileGenerator';
1313import { Box, Button, Row } from '@tlon/indigo-react';
1414import CopiableWithTooltip from 'components/copiable/CopiableWithTooltip';
1515
@@ -42,7 +42,7 @@ export default function UrbitOSHome() {
4242 names,
4343 ]);
4444
45− const { code, download } = useKeyfileGenerator({});
45+ const { code, download } = useHomeKeyfileGenerator({});
4646
4747 return (
4848 <Window className="os-home">
src/views/UrbitOS/NetworkKeys.tsx+2−2
@@ -27,7 +27,7 @@ import {
2727import useEthereumTransaction from 'lib/useEthereumTransaction';
2828import { GAS_LIMITS, ONE_SECOND } from 'lib/constants';
2929import { addHexPrefix } from 'lib/utils/address';
30−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
30+import { useHomeKeyfileGenerator } from 'lib/useKeyfileGenerator';
3131
3232import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
3333import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
@@ -66,7 +66,7 @@ function useSetKeys(
6666 generating: keyfileGenerating,
6767 filename,
6868 bind: keyfileBind,
69− } = useKeyfileGenerator({ seed: manualNetworkSeed });
69+ } = useHomeKeyfileGenerator({ seed: manualNetworkSeed });
7070
7171 const buildNetworkSeed = useCallback(
7272 async manualSeed => {