on master help sign in
Merge pull request #849 from urbit/t/activate-key-generation

network-keys: generated keyfiles use multikey format

commiteb4d5a97aa2ba1d65e6baa09aff8620ece23ec14 authortomholford <16504501+tomholford@users.noreply.github.com> dateThu 16 Dec 2021, 17:13 (5 years ago) parent349ddc70174dd5
22 files changed+433−68
src/components/DownloadKeyfileButton.js+1−1 src/lib/keys.js+27−3 src/lib/types/BridgeWallet.ts+1 src/lib/types/Keypair.ts+7 src/lib/types/L2Transaction.ts+3−2 src/lib/types/NetworkKeys.ts+11 src/lib/useKeyfileGenerator.js → src/lib/useKeyfileGenerator.ts+35−13 src/lib/useMultikeyFileGenerator.ts+203 src/lib/useRoller.ts+7−7 src/lib/wallet.ts+5−1 src/urbit-key-generation.d.ts+68 src/urbit-ob.d.ts−1 src/views/Activate/ActivateCodeForm.tsx+14−8 src/views/Activate/MasterKeyDownload.tsx+11−9 src/views/Activate/MasterKeyTransfer.tsx+3−8 src/views/Activate/useActivateFlowState.js+25−3 src/views/UrbitID/DownloadKeys.js+2−2 src/views/UrbitID/Home.tsx+2−2 src/views/UrbitOS/AccessCode.test.tsx+2−2 src/views/UrbitOS/Home.tsx+3−3 src/views/UrbitOS/NetworkKeys.tsx+2−2 src/worker/worker.ts+1−1
src/components/DownloadKeyfileButton.js+1−1
@@ -4,7 +4,7 @@ import { B } from 'indigo-react';
44import { DownloadButton } from 'components/Buttons';
55
66export default function DownloadKeyfileButton({
7− // useKeyfileGenerator.bind
7+ // useMultikeyFileGenerator.bind
88 generating,
99 available,
1010 downloaded,
src/lib/keys.js+27−3
@@ -76,12 +76,36 @@ export const compileNetworkKey = (pair, point, revision) => {
7676 noun.Atom.fromInt(point),
7777 noun.Atom.fromInt(revision),
7878 noun.Atom.fromString(bnsec.toString()),
79− noun.Atom.yes
79+ noun.Atom.fromInt(0)
8080 );
8181
8282 return b64(jam(sed));
8383};
8484
85+/**
86+ * @param {number} point
87+ * @param {array<{revision: number, pair: object}>} keys
88+ * @return {string}
89+ */
90+export const compileMultiKey = (point, keys) => {
91+ const kyz = keys.map(k => {
92+ const bnsec = new BN(createRing(k.pair), 'hex');
93+ return noun.dwim(
94+ noun.Atom.fromInt(k.revision),
95+ noun.Atom.fromString(bnsec.toString())
96+ );
97+ });
98+ kyz.push(noun.Atom.fromInt(0));
99+
100+ const fed = noun.dwim(
101+ noun.dwim(noun.Atom.fromInt(1), noun.Atom.fromInt(0)), // version
102+ noun.Atom.fromInt(point), // ship
103+ noun.dwim(kyz) // keys
104+ );
105+
106+ return b64(jam(fed));
107+};
108+
85109/**
86110 * @param {object} urbitWallet
87111 * @param {number} revision
@@ -198,8 +222,8 @@ export const attemptNetworkSeedDerivation = async ({
198222
199223/**
200224 *
201− * @param {object} pair
202− * @param {object} details
225+ * @param {object} pair - type NetworkKeys
226+ * @param {object} details - type L1Point
203227 * @return {boolean}
204228 */
205229export const keysMatchChain = (pair, details) => {
src/lib/types/BridgeWallet.ts+1
@@ -2,4 +2,5 @@ import { BIP32Interface } from 'bitcoinjs-lib';
22
33export default interface BridgeWallet extends BIP32Interface {
44 address: string;
5+ passphrase?: string;
56}
src/lib/types/Keypair.tsnew file+7
@@ -0,0 +1,7 @@
1+// returned from urbit/key-generation#deriveNodes
2+export interface Keypair {
3+ public: string;
4+ private: string;
5+ chain: string;
6+ address: string;
7+}
src/lib/types/L2Transaction.ts+3−2
@@ -1,5 +1,6 @@
11import RollerRPCAPI, { EthAddress, Proxy, Ship } from '@urbit/roller-api';
22import WalletConnect from '@walletconnect/client';
3+import BridgeWallet from './BridgeWallet';
34
45export type TransactionType =
56 | 'transferPoint'
@@ -43,6 +44,6 @@ export interface ReticketParams {
4344 point: Ship;
4445 to: EthAddress;
4546 manager: EthAddress;
46− fromWallet: any; // TODO: wallet type
47− toWallet: any; // TODO: wallet type
47+ fromWallet: BridgeWallet;
48+ toWallet: UrbitWallet;
4849}
src/lib/types/NetworkKeys.tsnew file+11
@@ -0,0 +1,11 @@
1+// returned from urbit/key-generation#deriveNetworkKeys
2+export interface NetworkKeys {
3+ crypt: {
4+ private: string;
5+ public: string;
6+ };
7+ auth: {
8+ private: string;
9+ public: string;
10+ };
11+}
src/lib/useKeyfileGenerator.js → src/lib/useKeyfileGenerator.tsrenamed+35−13
@@ -18,20 +18,39 @@ import {
1818} from './keys';
1919import useCurrentPermissions from './useCurrentPermissions';
2020import { convertToInt } from './convertToInt';
21+import { stripSigPrefix } from 'form/formatters';
22+
23+// overrideable defaults:
24+// seed - derived from wallet, mnemonic, or token (if posisble)
25+// point - the current pointCursor
26+interface useKeyfileGeneratorArgs {
27+ seed?: string;
28+ point?: number;
29+}
2130
22−export default function useKeyfileGenerator(manualNetworkSeed) {
23− const { urbitWallet, wallet, authMnemonic, authToken } = useWallet();
24− const { pointCursor } = usePointCursor();
25− const { getDetails } = usePointCache();
31+/**
32+ * @deprecated
33+ * Use `useMultikeyFileGenerator` instead
34+ */
35+export default function useKeyfileGenerator({
36+ seed,
37+ point,
38+}: useKeyfileGeneratorArgs) {
39+ const { urbitWallet, wallet, authMnemonic, authToken }: any = useWallet();
40+ const { pointCursor }: any = usePointCursor();
41+ const { syncDetails, getDetails }: any = usePointCache();
2642
2743 const [notice, setNotice] = useState('Deriving networking keys...');
2844 const [downloaded, setDownloaded] = useState(false);
2945 const [generating, setGenerating] = useState(true);
30− const [keyfile, setKeyfile] = useState(false);
31−
46+ const [keyfile, setKeyfile] = useState<boolean | string>(false);
3247 const [code, setCode] = useState(false);
3348
34− const _point = need.point(pointCursor);
49+ const _point = point || need.point(pointCursor);
50+ useEffect(() => {
51+ syncDetails(_point);
52+ }, [_point, syncDetails]);
53+
3554 const details = getDetails(_point);
3655
3756 const networkRevision = details.matchWith({
@@ -56,8 +75,8 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
5675
5776 const _details = need.details(details);
5877
59− const networkSeed = manualNetworkSeed
60− ? Just(manualNetworkSeed)
78+ const networkSeed = seed
79+ ? Just(seed)
6180 : await attemptNetworkSeedDerivation({
6281 urbitWallet,
6382 wallet,
@@ -88,14 +107,14 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
88107 return;
89108 }
90109
91− setNotice();
110+ setNotice('');
92111 setCode(generateCode(pair));
93112 setKeyfile(compileNetworkKey(pair, _point, networkRevision));
94113 setGenerating(false);
95114 }, [
96115 networkRevision,
97116 hasNetworkKeys,
98− manualNetworkSeed,
117+ seed,
99118 urbitWallet,
100119 wallet,
101120 authMnemonic,
@@ -106,11 +125,14 @@ export default function useKeyfileGenerator(manualNetworkSeed) {
106125 ]);
107126
108127 const filename = useMemo(() => {
109− return `${ob.patp(_point).slice(1)}-${networkRevision}.key`;
110− // TODO: ^ unifiy "remove tilde" calls
128+ return `${stripSigPrefix(ob.patp(_point))}-${networkRevision}.key`;
111129 }, [_point, networkRevision]);
112130
113131 const download = useCallback(() => {
132+ if (typeof keyfile !== 'string') {
133+ return;
134+ }
135+
114136 saveAs(
115137 new Blob([keyfile], {
116138 type: 'text/plain;charset=utf-8',
src/lib/useMultikeyFileGenerator.tsnew file+203
@@ -0,0 +1,203 @@
1+import * as need from 'lib/need';
2+import saveAs from 'file-saver';
3+import ob from 'urbit-ob';
4+import { Just, Nothing } from 'folktale/maybe';
5+
6+import { useCallback, useEffect, useMemo, useState } from 'react';
7+import { usePointCache } from 'store/pointCache';
8+import { usePointCursor } from 'store/pointCursor';
9+import { useWallet } from 'store/wallet';
10+import { deriveNetworkKeys } from 'urbit-key-generation';
11+import { convertToInt } from './convertToInt';
12+import {
13+ attemptNetworkSeedDerivation,
14+ compileMultiKey,
15+ keysMatchChain,
16+} from './keys';
17+import { generateCode } from './networkCode';
18+import { L1Point } from './types/L1Point';
19+import useCurrentPermissions from './useCurrentPermissions';
20+import { stripSigPrefix } from 'form/formatters';
21+
22+interface useMultikeyFileGeneratorArgs {
23+ seed?: string;
24+ point?: number;
25+ seedWallet?: any;
26+}
27+
28+/**
29+ * defaults:
30+ * - seed: derived from wallet, mnemonic, or token (if posisble)
31+ * - point: the current pointCursor
32+ */
33+export default function useMultikeyFileGenerator({
34+ seed,
35+ point,
36+ seedWallet,
37+}: useMultikeyFileGeneratorArgs) {
38+ const { urbitWallet, wallet, authMnemonic, authToken }: any = useWallet();
39+ const { pointCursor }: any = usePointCursor();
40+ const { syncDetails, getDetails }: any = usePointCache();
41+ const { isOwner, isManagementProxy } = useCurrentPermissions();
42+
43+ const [notice, setNotice] = useState('Deriving networking keys...');
44+ const [downloaded, setDownloaded] = useState(false);
45+ const [generating, setGenerating] = useState(true);
46+ const [keyfile, setKeyfile] = useState<boolean | string>(false);
47+ const [code, setCode] = useState(false);
48+
49+ const _point = useMemo(() => point || need.point(pointCursor), [
50+ point,
51+ pointCursor,
52+ ]);
53+ const details = getDetails(_point);
54+ const _details: L1Point | null = useMemo(
55+ () =>
56+ details.matchWith({
57+ Just: d => need.details(d),
58+ Nothing: () => null,
59+ }),
60+ [details]
61+ );
62+
63+ const currentRevision: number = useMemo(
64+ () =>
65+ details.matchWith({
66+ Just: ({ value }) => convertToInt(value.keyRevisionNumber, 10),
67+ Nothing: () => 0,
68+ }),
69+ [details]
70+ );
71+ const nextRevision = useMemo(() => currentRevision + 1, [currentRevision]);
72+
73+ const pairFromRevision = useCallback(
74+ async (revision: number) => {
75+ if (!_details) {
76+ return;
77+ }
78+
79+ const networkSeed = seed
80+ ? Just(seed)
81+ : await attemptNetworkSeedDerivation({
82+ urbitWallet: seedWallet || urbitWallet,
83+ wallet,
84+ authMnemonic,
85+ details: _details,
86+ authToken,
87+ point: _point,
88+ revision: revision,
89+ });
90+
91+ if (Nothing.hasInstance(networkSeed)) {
92+ setGenerating(false);
93+ setNotice(
94+ 'Custom or nondeterministic networking keys cannot be re-downloaded.'
95+ );
96+ console.log(`seed is nondeterminable for revision ${revision}`);
97+ return;
98+ }
99+
100+ const _networkSeed = networkSeed.value;
101+
102+ return deriveNetworkKeys(_networkSeed);
103+ },
104+ [
105+ _details,
106+ _point,
107+ authMnemonic,
108+ authToken,
109+ seed,
110+ urbitWallet,
111+ wallet,
112+ seedWallet,
113+ ]
114+ );
115+
116+ const hasNetworkKeys = currentRevision > 0;
117+ const available =
118+ (isOwner || isManagementProxy) && hasNetworkKeys && !!keyfile;
119+
120+ const generate = useCallback(async () => {
121+ if (!hasNetworkKeys) {
122+ setGenerating(false);
123+ setNotice('Network keys not yet set.');
124+ console.log(
125+ `no networking keys available for revision ${currentRevision}`
126+ );
127+ return;
128+ }
129+
130+ const currentPair = await pairFromRevision(currentRevision);
131+
132+ if (!currentPair || !keysMatchChain(currentPair, _details || {})) {
133+ setGenerating(false);
134+ setNotice('Derived networking keys do not match on-chain details.');
135+ console.log(`keys do not match details for revision ${currentRevision}`);
136+ return;
137+ }
138+
139+ const nextPair = await pairFromRevision(nextRevision);
140+
141+ setNotice('');
142+ setCode(generateCode(currentPair));
143+ setKeyfile(
144+ compileMultiKey(_point, [
145+ {
146+ revision: currentRevision,
147+ pair: currentPair,
148+ },
149+ {
150+ revision: nextRevision,
151+ pair: nextPair,
152+ },
153+ ])
154+ );
155+ setGenerating(false);
156+ }, [
157+ _details,
158+ _point,
159+ currentRevision,
160+ hasNetworkKeys,
161+ nextRevision,
162+ pairFromRevision,
163+ ]);
164+
165+ const filename = useMemo(() => {
166+ return `${stripSigPrefix(ob.patp(_point))}-${currentRevision}.key`;
167+ }, [_point, currentRevision]);
168+
169+ const download = useCallback(() => {
170+ if (typeof keyfile !== 'string') {
171+ return;
172+ }
173+
174+ saveAs(
175+ new Blob([keyfile], {
176+ type: 'text/plain;charset=utf-8',
177+ }),
178+ filename
179+ );
180+ setDownloaded(true);
181+ }, [filename, keyfile]);
182+
183+ useEffect(() => {
184+ syncDetails(_point);
185+ }, [_point, syncDetails]);
186+
187+ useEffect(() => {
188+ generate();
189+ }, [generate]);
190+
191+ const output = {
192+ generating,
193+ available,
194+ downloaded,
195+ download,
196+ filename,
197+ notice,
198+ keyfile,
199+ code,
200+ };
201+
202+ return { ...output, bind: output };
203+}
src/lib/useRoller.ts+7−7
@@ -22,7 +22,7 @@ import { usePointCache } from 'store/pointCache';
2222
2323import { getUpdatedPointMessage, isPlanet, toL1Details } from './utils/point';
2424import { convertToInt } from './convertToInt';
25−import { isDevelopment, isRopsten } from './flags';
25+import { isDevelopment, isMainnet, isRopsten } from './flags';
2626import {
2727 generateInviteWallet,
2828 getPendingSpawns,
@@ -113,13 +113,13 @@ export default function useRoller() {
113113 const [config, setConfig] = useState<Config | null>(null);
114114
115115 const options: Options = useMemo(() => {
116− const type = isRopsten || !isDevelopment ? 'https' : 'http';
117− const host = isRopsten
116+ const type = isMainnet || isRopsten ? 'https' : 'http';
117+ const host = isMainnet
118+ ? ROLLER_HOSTS.MAINNET
119+ : isRopsten
118120 ? ROLLER_HOSTS.ROPSTEN
119− : isDevelopment
120− ? ROLLER_HOSTS.LOCAL
121− : ROLLER_HOSTS.MAINNET;
122− const port = isDevelopment && !isRopsten ? 8080 : 443;
121+ : ROLLER_HOSTS.LOCAL;
122+ const port = isMainnet || isRopsten ? 443 : 8080;
123123 const path = '/v1/roller';
124124
125125 return {
src/lib/wallet.ts+5−1
@@ -12,7 +12,11 @@ export function EthereumWallet(privateKey) {
1212 this.address = publicToAddress(this.publicKey);
1313}
1414
15−export const urbitWalletFromTicket = async (ticket, point, passphrase) => {
15+export const urbitWalletFromTicket = async (
16+ ticket: string,
17+ point: number,
18+ passphrase?: string
19+) => {
1620 return await kg.generateWallet({
1721 ticket: ticket,
1822 ship: point,
src/urbit-key-generation.d.tsnew file+68
@@ -0,0 +1,68 @@
1+interface NetworkKeys {
2+ crypt: {
3+ private: string;
4+ public: string;
5+ };
6+ auth: {
7+ private: string;
8+ public: string;
9+ };
10+}
11+
12+interface WalletNodeKeys {
13+ public: string;
14+ private: string;
15+ chain: string;
16+ address: string;
17+}
18+
19+interface WalletNode {
20+ type: string;
21+ seed: string;
22+ keys: WalletNodeKeys;
23+ derivationPath: string;
24+}
25+
26+interface WalletConfig {
27+ ticket: string;
28+ ship: number;
29+ passphrase?: string;
30+ boot?: boolean;
31+}
32+
33+interface UrbitWallet {
34+ meta: {
35+ generator: {
36+ name: string;
37+ version: string;
38+ };
39+ spec: string;
40+ ship: string;
41+ patp: string;
42+ tier: string;
43+ passphrase: string;
44+ };
45+ masterSeed: string;
46+ ownership: WalletNode;
47+ management: WalletNode;
48+ transfer: WalletNode;
49+ network:
50+ | {
51+ type: string;
52+ seed: string;
53+ keys: string;
54+ }
55+ | {};
56+ voting?: WalletNode;
57+ spawn?: WalletNode;
58+}
59+
60+declare module 'urbit-key-generation' {
61+ function deriveNetworkKeys(hex: string): NetworkKeys;
62+ function generateWallet({
63+ ticket,
64+ ship,
65+ passphrase,
66+ boot,
67+ }: WalletConfig): UrbitWallet;
68+}
src/urbit-ob.d.ts−1
@@ -1,2 +1 @@
1−// azimuth-js.d.ts
21declare module 'urbit-ob';
src/views/Activate/ActivateCodeForm.tsx+14−8
@@ -18,9 +18,8 @@ import { useActivateFlow } from './ActivateFlow';
1818import WarningBox from 'components/WarningBox';
1919import useRoller from 'lib/useRoller';
2020import useImpliedTicket from 'lib/useImpliedTicket';
21−import { generateOwnershipWallet } from 'lib/walletgen';
22−import { generateWallet } from 'lib/invite';
23−import { walletFromMnemonic } from 'lib/wallet';
21+import { generateWallet } from 'lib/walletgen';
22+import { urbitWalletFromTicket, walletFromMnemonic } from 'lib/wallet';
2423import { DEFAULT_HD_PATH, POINT_PROXIES } from 'lib/constants';
2524import useBreakpoints from 'lib/useBreakpoints';
2625import { Ship } from '@urbit/roller-api';
@@ -46,6 +45,7 @@ const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
4645 setDerivedWallet,
4746 setInviteWallet,
4847 setIsIn,
48+ setSendWallet,
4949 } = useActivateFlow();
5050
5151 // this is a pretty naive way to detect if we're on a mobile device
@@ -109,11 +109,17 @@ const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
109109 const { ticket, point } = getTicketAndPoint(
110110 impliedTicket || values.ticket
111111 );
112− const { seed } = await generateOwnershipWallet(point, ticket);
113− const inviteWallet = walletFromMnemonic(seed, DEFAULT_HD_PATH);
112+
113+ const inviteWallet = Just(await urbitWalletFromTicket(ticket, point));
114114 setInviteWallet(inviteWallet);
115− const _inviteWallet = need.wallet(inviteWallet);
116− const inviteAddress = _inviteWallet.address;
115+ const _inviteWallet: UrbitWallet = need.wallet(inviteWallet);
116+ const inviteAddress = _inviteWallet.ownership.keys.address;
117+
118+ const sendWallet = await walletFromMnemonic(
119+ _inviteWallet.ownership.seed,
120+ DEFAULT_HD_PATH
121+ );
122+ setSendWallet(sendWallet);
117123
118124 let incoming = await loadPoints(inviteAddress);
119125
@@ -136,7 +142,7 @@ const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
136142 setDerivedPatp(Just(ob.patp(point)));
137143 setDerivedPoint(Just(point));
138144 setDerivedPointDominion(Just(rollerPoint.dominion));
139− setDerivedWallet(Just(await generateWallet(point, true)));
145+ setDerivedWallet(Just(await generateWallet(point, ticket, true)));
140146 setIsIn(false);
141147 await timeout(100);
142148 } else {
src/views/Activate/MasterKeyDownload.tsx+11−9
@@ -1,7 +1,6 @@
11import React, { useCallback, useEffect, useMemo, useState } from 'react';
22import { Just, Nothing } from 'folktale/maybe';
33import * as need from 'lib/need';
4−import * as ob from 'urbit-ob';
54
65import { ActivateSteps } from './ActivateSteps';
76import { Box } from '@tlon/indigo-react';
@@ -14,17 +13,18 @@ import { FadeableMasterKeyPresenter as MasterKeyPresenter } from './MasterKeyPre
1413import { useActivateFlow } from './ActivateFlow';
1514import ActivateView from './ActivateView';
1615import { useLocalRouter } from 'lib/LocalRouter';
17−import { compileNetworkKey } from 'lib/keys';
18−import { downloadWallet } from 'lib/invite';
1916import PaperBuilder from 'components/PaperBuilder';
2017import { DEFAULT_FADE_TIMEOUT, MASTER_KEY_DURATION } from 'lib/constants';
2118import { timeout } from 'lib/timeout';
2219import View from 'components/View';
20+import useMultikeyFileGenerator from 'lib/useMultikeyFileGenerator';
21+import { downloadWallet } from 'lib/invite';
2322
2423const MasterKeyDownload = () => {
2524 const {
2625 derivedPoint,
2726 derivedWallet,
27+ inviteWallet,
2828 isIn,
2929 setGenerated,
3030 setIsIn,
@@ -46,12 +46,10 @@ const MasterKeyDownload = () => {
4646 Just: p => p.value.toFixed(),
4747 });
4848
49− const download = useCallback(async () => {
50− const netkey = compileNetworkKey(wallet.network.keys, point, 1);
51− //TODO could be deduplicated with useKeyfileGenerator's logic
52− const filename = ob.patp(point).slice(1) + '-1.key';
53− await downloadWallet(paper.getOrElse([]), netkey, filename);
54− }, [paper, wallet, point]);
49+ const { keyfile, filename } = useMultikeyFileGenerator({
50+ point,
51+ seedWallet: inviteWallet,
52+ });
5553
5654 // sync paper value to activation state
5755 useEffect(
@@ -65,6 +63,10 @@ const MasterKeyDownload = () => {
6563 [paper, setGenerated]
6664 );
6765
66+ const download = useCallback(async () => {
67+ await downloadWallet(paper.getOrElse([]), keyfile, filename);
68+ }, [paper, keyfile, filename]);
69+
6870 const onDownloadClick = useCallback(async () => {
6971 await download();
7072 setIsIn(false);
src/views/Activate/MasterKeyTransfer.tsx+3−8
@@ -20,7 +20,7 @@ const MasterKeyTransfer = () => {
2020 derivedPatp,
2121 derivedPoint,
2222 derivedWallet,
23− inviteWallet,
23+ sendWallet,
2424 } = useActivateFlow();
2525 const [error, setError] = useState();
2626
@@ -33,18 +33,13 @@ const MasterKeyTransfer = () => {
3333 to: derivedWallet.value.ownership.keys.address,
3434 manager: derivedWallet.value.management.keys.address,
3535 toWallet: derivedWallet.value,
36− fromWallet: inviteWallet.value,
36+ fromWallet: sendWallet.value,
3737 });
3838 } catch (e) {
3939 console.error(e);
4040 setError(e);
4141 }
42− }, [
43− derivedWallet,
44− performL2Reticket,
45− derivedPoint.value,
46− inviteWallet.value,
47− ]);
42+ }, [derivedWallet, performL2Reticket, derivedPoint.value, sendWallet.value]);
4843
4944 useFadeIn();
5045
src/views/Activate/useActivateFlowState.js+25−3
@@ -4,13 +4,30 @@ import { Nothing } from 'folktale/maybe';
44export default function useActivateFlowState() {
55 const [derivedPatp, setDerivedPatp] = useState(Nothing());
66 const [derivedPoint, setDerivedPoint] = useState(Nothing());
7− const [derivedPointDominion, setDerivedPointDominion] = useState(Nothing());
8− const [derivedWallet, setDerivedWallet] = useState(Nothing());
97 const [generated, setGenerated] = useState(false);
108 const [incomingPoints, setIncomingPoints] = useState(Nothing());
11− const [inviteWallet, setInviteWallet] = useState(Nothing());
9+ const [derivedPointDominion, setDerivedPointDominion] = useState(Nothing());
1210 const [isIn, setIsIn] = useState(false);
1311
12+ // A new wallet generated after confirming that the invite ticket is valid
13+ // and the point is available for activation.
14+ // At the end of the Activate flow, the point will be transferred
15+ // from the invite wallet to the derived wallet. When the user confirms
16+ // the Master Key (ticket) and downloads the passport / mnemonic,
17+ // it is for the derived wallet
18+ // type UrbitWallet
19+ const [derivedWallet, setDerivedWallet] = useState(Nothing());
20+ // The wallet generated deterministically during the invite flow;
21+ // it is re-generated when the user starts the Activate flow. It is used
22+ // to derive and confirm a shareable ticket that a user can activate a point with.
23+ // type UrbitWallet
24+ const [inviteWallet, setInviteWallet] = useState(Nothing());
25+ // This wallet is generated from the invite wallet's seed phrase.
26+ // It is used during the transfer phase of the invite flow to send transactions.
27+ // useMultiKeyFileGenerator.
28+ // type bip32.BIP32Interface
29+ const [sendWallet, setSendWallet] = useState(Nothing());
30+
1431 const reset = useCallback(() => {
1532 setDerivedPatp(Nothing());
1633 setDerivedPoint(Nothing());
@@ -19,13 +36,16 @@ export default function useActivateFlowState() {
1936 setGenerated(false);
2037 setIncomingPoints(Nothing());
2138 setInviteWallet(Nothing());
39+ setSendWallet(Nothing());
2240 }, [
41+ setDerivedPatp,
2342 setDerivedPoint,
2443 setDerivedPointDominion,
2544 setDerivedWallet,
2645 setGenerated,
2746 setIncomingPoints,
2847 setInviteWallet,
48+ setSendWallet,
2949 ]);
3050
3151 return {
@@ -38,6 +58,7 @@ export default function useActivateFlowState() {
3858 inviteWallet,
3959 isIn,
4060 reset,
61+ sendWallet,
4162 setDerivedPatp,
4263 setDerivedPoint,
4364 setDerivedPointDominion,
@@ -46,5 +67,6 @@ export default function useActivateFlowState() {
4667 setIncomingPoints,
4768 setInviteWallet,
4869 setIsIn,
70+ setSendWallet,
4971 };
5072}
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 useMultikeyFileGenerator from 'lib/useMultikeyFileGenerator';
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 } = useMultikeyFileGenerator({});
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 useMultikeyFileGenerator from 'lib/useMultikeyFileGenerator';
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 } = useMultikeyFileGenerator({});
4747 const [paper, setPaper] = useState(Nothing());
4848
4949 const downloadKeys = useCallback(() => {
src/views/UrbitOS/AccessCode.test.tsx+2−2
@@ -4,7 +4,7 @@ import AccessCode from './AccessCode';
44
55describe('AccessCode', () => {
66 describe('when code is not available', () => {
7− // Value is initialized as `false` in `useKeyfileGenerator`
7+ // Value is initialized as `false` in `useMultikeyFileGenerator`
88 const testCode = false;
99
1010 it('does not render the component', () => {
@@ -15,7 +15,7 @@ describe('AccessCode', () => {
1515 });
1616
1717 describe('when code is available', () => {
18− // Value has been loaded from `useKeyfileGenerator`
18+ // Value has been loaded from `useMultikeyFileGenerator`
1919 const testCode = 'foo-bar';
2020
2121 it('renders the component', () => {
src/views/UrbitOS/Home.tsx+3−3
@@ -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 useMultikeyFileGenerator from 'lib/useMultikeyFileGenerator';
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 { bind: keyBind, code } = useKeyfileGenerator();
45+ const { code, download } = useMultikeyFileGenerator({});
4646
4747 return (
4848 <Window className="os-home">
@@ -53,7 +53,7 @@ export default function UrbitOSHome() {
5353 <Button
5454 className="header-button keyfile"
5555 disabled={!hasSetNetworkKeys}
56− onClick={keyBind.download}>
56+ onClick={download}>
5757 <KeyfileIcon />
5858 Download Keyfile
5959 </Button>
src/views/UrbitOS/NetworkKeys.tsx+2−2
@@ -28,7 +28,7 @@ import {
2828import useEthereumTransaction from 'lib/useEthereumTransaction';
2929import { GAS_LIMITS } from 'lib/constants';
3030import { addHexPrefix } from 'lib/utils/address';
31−import useKeyfileGenerator from 'lib/useKeyfileGenerator';
31+import useMultikeyFileGenerator from 'lib/useMultikeyFileGenerator';
3232
3333import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
3434import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
@@ -72,7 +72,7 @@ function useSetKeys(
7272 generating: keyfileGenerating,
7373 filename,
7474 bind: keyfileBind,
75− } = useKeyfileGenerator(manualNetworkSeed);
75+ } = useMultikeyFileGenerator({ seed: manualNetworkSeed });
7676
7777 const buildNetworkSeed = useCallback(
7878 async manualSeed => {
src/worker/worker.ts+1−1
@@ -1,6 +1,6 @@
11import kg from 'urbit-key-generation';
22
3−export async function generateWallet(data: string): Promise<string> {
3+export async function generateWallet(data: string): Promise<UrbitWallet> {
44 // Process the data without stalling the UI
55 const config = JSON.parse(data);
66 const wallet = await kg.generateWallet(config);