on master help sign in
activate: generate invite wallet deterministically
a2920a4tomholford
src/lib/keys.js−27
@@ -246,30 +246,3 @@ export const segmentNetworkKey = hex => {
246
246
247 return [rowFrom(2), rowFrom(18), rowFrom(34), rowFrom(50)];
247 return [rowFrom(2), rowFrom(18), rowFrom(34), rowFrom(50)];
248};
248};
249−
250−// ctsy @yosoyubik
251−/**
252− * @param {object} pair
253− * @param {number} point
254− * @param {number} revision
255− * @return {string}
256− */
257−export const compileMultikey = (point, pair1, pair2, revision1, revision2) => {
258− const bnsec1 = new BN(createRing(pair1), 'hex');
259− const bnsec2 = new BN(createRing(pair2), 'hex');
260−
261− const tag = noun.dwim(noun.Atom.fromInt(1), noun.Atom.yes);
262− const ship = noun.Atom.fromInt(point);
263− const key1 = noun.dwim(
264− noun.Atom.fromInt(revision1),
265− noun.Atom.fromString(bnsec1.toString())
266− );
267− const key2 = noun.dwim(
268− noun.Atom.fromInt(revision2),
269− noun.Atom.fromString(bnsec2.toString())
270− );
271−
272− const sed = noun.dwim(tag, ship, key1, key2, noun.Atom.yes);
273−
274− return b64(jam(sed));
275−};
src/lib/types/BridgeWallet.ts+1
@@ -2,4 +2,5 @@ import { BIP32Interface } from 'bitcoinjs-lib';
2
2
3export default interface BridgeWallet extends BIP32Interface {
3export default interface BridgeWallet extends BIP32Interface {
4 address: string;
4 address: string;
5+ passphrase?: string;
5}
6}
src/lib/types/L2Transaction.ts+1−1
@@ -43,6 +43,6 @@ export interface ReticketParams {
43 point: Ship;
43 point: Ship;
44 to: EthAddress;
44 to: EthAddress;
45 manager: EthAddress;
45 manager: EthAddress;
46− fromWallet: any; // TODO: wallet type
46+ fromWallet: UrbitWallet;
47 toWallet: any; // TODO: wallet type
47 toWallet: any; // TODO: wallet type
48}
48}
src/lib/useMultikeyFileGenerator.ts+28−26
@@ -11,7 +11,7 @@ import { deriveNetworkKeys } from 'urbit-key-generation';
11import { convertToInt } from './convertToInt';
11import { convertToInt } from './convertToInt';
12import {
12import {
13 attemptNetworkSeedDerivation,
13 attemptNetworkSeedDerivation,
14− compileMultikey,
14+ compileMultiKey,
15 keysMatchChain,
15 keysMatchChain,
16} from './keys';
16} from './keys';
17import { generateCode } from './networkCode';
17import { generateCode } from './networkCode';
@@ -80,7 +80,7 @@ export default function useMultikeyFileGenerator({
80 ? Just(seed)
80 ? Just(seed)
81 : await attemptNetworkSeedDerivation({
81 : await attemptNetworkSeedDerivation({
82 urbitWallet: seedWallet || urbitWallet,
82 urbitWallet: seedWallet || urbitWallet,
83− wallet,
83+ wallet: wallet,
84 authMnemonic,
84 authMnemonic,
85 details: _details,
85 details: _details,
86 authToken,
86 authToken,
@@ -127,38 +127,40 @@ export default function useMultikeyFileGenerator({
127 return;
127 return;
128 }
128 }
129
129
130− // TODO: Do we still need this? The legacy implementation in useKeyfileGenerator
130+ const currentPair = await pairFromRevision(currentRevision);
131− // performed this guard statement
132
131
133− // const currentPair = await pairFromRevision(currentRevision);
134−
135− // if (!currentPair || !keysMatchChain(currentPair, _details)) {
132+ if (!currentPair || !keysMatchChain(currentPair, _details || {})) {
136− // setGenerating(false);
133+ setGenerating(false);
137− // setNotice('Derived networking keys do not match on-chain details.');
134+ setNotice('Derived networking keys do not match on-chain details.');
138− // console.log(`keys do not match details for revision ${currentRevision}`);
135+ console.log(`keys do not match details for revision ${currentRevision}`);
139− // return;
136+ return;
140− // }
137+ }
141−
142− // const nextPair = await pairFromRevision(nextRevision);
143
138
144− const [currentPair, nextPair] = await Promise.all([
145− pairFromRevision(currentRevision),
146− pairFromRevision(nextRevision),
139+ const nextPair = await pairFromRevision(nextRevision);
147− ]);
148
140
149 setNotice('');
141 setNotice('');
150 setCode(generateCode(currentPair));
142 setCode(generateCode(currentPair));
151 setKeyfile(
143 setKeyfile(
152− compileMultikey(
153− _point,
144+ compileMultiKey(_point, [
145+ {
146+ revision: currentRevision,
154− currentPair,
147+ pair: currentPair,
148+ },
149+ {
150+ revision: nextRevision,
155− nextPair,
151+ pair: nextPair,
156− currentRevision,
152+ },
157− nextRevision
158− )
153+ ])
159 );
154 );
160 setGenerating(false);
155 setGenerating(false);
156+ }, [
157+ _details,
158+ _point,
159+ currentRevision,
160+ hasNetworkKeys,
161+ nextRevision,
161− }, [_point, currentRevision, hasNetworkKeys, nextRevision, pairFromRevision]);
162+ pairFromRevision,
163+ ]);
162
164
163 const filename = useMemo(() => {
165 const filename = useMemo(() => {
164 return `${stripSigPrefix(ob.patp(_point))}-${currentRevision}.key`;
166 return `${stripSigPrefix(ob.patp(_point))}-${currentRevision}.key`;
src/lib/useRoller.ts+7−7
@@ -22,7 +22,7 @@ import { usePointCache } from 'store/pointCache';
22
22
23import { getUpdatedPointMessage, isPlanet, toL1Details } from './utils/point';
23import { getUpdatedPointMessage, isPlanet, toL1Details } from './utils/point';
24import { convertToInt } from './convertToInt';
24import { convertToInt } from './convertToInt';
25−import { isDevelopment, isRopsten } from './flags';
25+import { isDevelopment, isMainnet, isRopsten } from './flags';
26import {
26import {
27 generateInviteWallet,
27 generateInviteWallet,
28 getPendingSpawns,
28 getPendingSpawns,
@@ -113,13 +113,13 @@ export default function useRoller() {
113 const [config, setConfig] = useState<Config | null>(null);
113 const [config, setConfig] = useState<Config | null>(null);
114
114
115 const options: Options = useMemo(() => {
115 const options: Options = useMemo(() => {
116− const type = isRopsten || !isDevelopment ? 'https' : 'http';
116+ const type = isMainnet || isRopsten ? 'https' : 'http';
117+ const host = isMainnet
118+ ? ROLLER_HOSTS.MAINNET
117− const host = isRopsten
119+ : isRopsten
118 ? ROLLER_HOSTS.ROPSTEN
120 ? ROLLER_HOSTS.ROPSTEN
119− : isDevelopment
120− ? ROLLER_HOSTS.LOCAL
121+ : ROLLER_HOSTS.LOCAL;
121− : ROLLER_HOSTS.MAINNET;
122− const port = isDevelopment && !isRopsten ? 8080 : 443;
122+ const port = isMainnet || isRopsten ? 443 : 8080;
123 const path = '/v1/roller';
123 const path = '/v1/roller';
124
124
125 return {
125 return {
src/lib/wallet.ts+5−1
@@ -12,7 +12,11 @@ export function EthereumWallet(privateKey) {
12 this.address = publicToAddress(this.publicKey);
12 this.address = publicToAddress(this.publicKey);
13}
13}
14
14
15−export const urbitWalletFromTicket = async (ticket, point, passphrase) => {
15+export const urbitWalletFromTicket = async (
16+ ticket: string,
17+ point: number,
18+ passphrase?: string
19+) => {
16 return await kg.generateWallet({
20 return await kg.generateWallet({
17 ticket: ticket,
21 ticket: ticket,
18 ship: point,
22 ship: point,
src/urbit-key-generation.d.ts+54
@@ -9,6 +9,60 @@ interface NetworkKeys {
9 };
9 };
10}
10}
11
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+
12declare module 'urbit-key-generation' {
60declare module 'urbit-key-generation' {
13 function deriveNetworkKeys(hex: string): NetworkKeys;
61 function deriveNetworkKeys(hex: string): NetworkKeys;
62+ function generateWallet({
63+ ticket,
64+ ship,
65+ passphrase,
66+ boot,
67+ }: WalletConfig): UrbitWallet;
14}
68}
src/views/Activate/ActivateCodeForm.tsx+8−9
@@ -18,10 +18,9 @@ import { useActivateFlow } from './ActivateFlow';
18import WarningBox from 'components/WarningBox';
18import WarningBox from 'components/WarningBox';
19import useRoller from 'lib/useRoller';
19import useRoller from 'lib/useRoller';
20import useImpliedTicket from 'lib/useImpliedTicket';
20import useImpliedTicket from 'lib/useImpliedTicket';
21−import { generateOwnershipWallet } from 'lib/walletgen';
21+import { generateWallet } from 'lib/walletgen';
22−import { generateWallet } from 'lib/invite';
22+import { urbitWalletFromTicket } from 'lib/wallet';
23−import { walletFromMnemonic } from 'lib/wallet';
24−import { DEFAULT_HD_PATH, POINT_PROXIES } from 'lib/constants';
23+import { POINT_PROXIES } from 'lib/constants';
25import useBreakpoints from 'lib/useBreakpoints';
24import useBreakpoints from 'lib/useBreakpoints';
26import { Ship } from '@urbit/roller-api';
25import { Ship } from '@urbit/roller-api';
27import { convertToInt } from 'lib/convertToInt';
26import { convertToInt } from 'lib/convertToInt';
@@ -109,11 +108,11 @@ const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
109 const { ticket, point } = getTicketAndPoint(
108 const { ticket, point } = getTicketAndPoint(
110 impliedTicket || values.ticket
109 impliedTicket || values.ticket
111 );
110 );
112− const { seed } = await generateOwnershipWallet(point, ticket);
111+
113− const inviteWallet = walletFromMnemonic(seed, DEFAULT_HD_PATH);
112+ const inviteWallet = Just(await urbitWalletFromTicket(ticket, point));
114 setInviteWallet(inviteWallet);
113 setInviteWallet(inviteWallet);
115− const _inviteWallet = need.wallet(inviteWallet);
114+ const _inviteWallet: UrbitWallet = need.wallet(inviteWallet);
116− const inviteAddress = _inviteWallet.address;
115+ const inviteAddress = _inviteWallet.ownership.keys.address;
117
116
118 let incoming = await loadPoints(inviteAddress);
117 let incoming = await loadPoints(inviteAddress);
119
118
@@ -136,7 +135,7 @@ const ActivateCodeForm = ({ afterSubmit }: ActivateCodeFormProps) => {
136 setDerivedPatp(Just(ob.patp(point)));
135 setDerivedPatp(Just(ob.patp(point)));
137 setDerivedPoint(Just(point));
136 setDerivedPoint(Just(point));
138 setDerivedPointDominion(Just(rollerPoint.dominion));
137 setDerivedPointDominion(Just(rollerPoint.dominion));
139− setDerivedWallet(Just(await generateWallet(point, true)));
138+ setDerivedWallet(Just(await generateWallet(point, ticket, true)));
140 setIsIn(false);
139 setIsIn(false);
141 await timeout(100);
140 await timeout(100);
142 } else {
141 } else {
src/views/Activate/MasterKeyDownload.tsx+2−2
@@ -1,7 +1,6 @@
1import React, { useCallback, useEffect, useMemo, useState } from 'react';
1import React, { useCallback, useEffect, useMemo, useState } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
2import { Just, Nothing } from 'folktale/maybe';
3import * as need from 'lib/need';
3import * as need from 'lib/need';
4−import * as ob from 'urbit-ob';
5
4
6import { ActivateSteps } from './ActivateSteps';
5import { ActivateSteps } from './ActivateSteps';
7import { Box } from '@tlon/indigo-react';
6import { Box } from '@tlon/indigo-react';
@@ -24,6 +23,7 @@ const MasterKeyDownload = () => {
24 const {
23 const {
25 derivedPoint,
24 derivedPoint,
26 derivedWallet,
25 derivedWallet,
26+ inviteWallet,
27 isIn,
27 isIn,
28 setGenerated,
28 setGenerated,
29 setIsIn,
29 setIsIn,
@@ -47,7 +47,7 @@ const MasterKeyDownload = () => {
47
47
48 const { download } = useMultikeyFileGenerator({
48 const { download } = useMultikeyFileGenerator({
49 point,
49 point,
50− seedWallet: derivedWallet,
50+ seedWallet: inviteWallet,
51 });
51 });
52
52
53 // sync paper value to activation state
53 // sync paper value to activation state
src/worker/worker.ts+1−1
@@ -1,6 +1,6 @@
1import kg from 'urbit-key-generation';
1import kg from 'urbit-key-generation';
2
2
3−export async function generateWallet(data: string): Promise<string> {
3+export async function generateWallet(data: string): Promise<UrbitWallet> {
4 // Process the data without stalling the UI
4 // Process the data without stalling the UI
5 const config = JSON.parse(data);
5 const config = JSON.parse(data);
6 const wallet = await kg.generateWallet(config);
6 const wallet = await kg.generateWallet(config);