on master help sign in
wip: configure keys + transfer point
ea93e0ctomholford
src/lib/useRoller.ts+73−17
@@ -43,6 +43,12 @@ import {
43import { usePointCache } from 'store/pointCache';
43import { usePointCache } from 'store/pointCache';
44import { getOutgoingPoints, maybeGetResult } from 'views/Points';
44import { getOutgoingPoints, maybeGetResult } from 'views/Points';
45import { isPlanet } from './utils/point';
45import { isPlanet } from './utils/point';
46+import {
47+ CRYPTO_SUITE_VERSION,
48+ deriveNetworkKeys,
49+ deriveNetworkSeedFromUrbitWallet,
50+} from './keys';
51+import { convertToInt } from './convertToInt';
46
52
47const spawn = async (
53const spawn = async (
48 api: any,
54 api: any,
@@ -140,8 +146,8 @@ const hasPoint = (point: number) => (invite: Invite) => invite.planet === point;
140const getProxyAndNonce = (
146const getProxyAndNonce = (
141 point: L2Point,
147 point: L2Point,
142 address: string
148 address: string
143−): { proxy?: string; nonce?: number } =>
149+): { proxy?: string; nonce?: number } => {
144− point.ownership?.managementProxy?.address === address
150+ return point.ownership?.managementProxy?.address === address
145 ? { proxy: 'manage', nonce: point.ownership?.managementProxy.nonce }
151 ? { proxy: 'manage', nonce: point.ownership?.managementProxy.nonce }
146 : point.ownership?.owner?.address === address
152 : point.ownership?.owner?.address === address
147 ? { proxy: 'own', nonce: point.ownership?.owner.nonce }
153 ? { proxy: 'own', nonce: point.ownership?.owner.nonce }
@@ -155,6 +161,7 @@ const getProxyAndNonce = (
155 nonce: point.transferProxy?.votingProxy?.owner.nonce,
161 nonce: point.transferProxy?.votingProxy?.owner.nonce,
156 }
162 }
157 : { proxy: undefined, nonce: undefined };
163 : { proxy: undefined, nonce: undefined };
164+};
158
165
159export default function useRoller() {
166export default function useRoller() {
160 const { wallet, authToken, authMnemonic, urbitWallet }: any = useWallet();
167 const { wallet, authToken, authMnemonic, urbitWallet }: any = useWallet();
@@ -466,40 +473,89 @@ export default function useRoller() {
466 ]
473 ]
467 );
474 );
468
475
476+ // TODO: extract from #transferPoint
477+ // interface ConfigureKeysParams {
478+
479+ // }
480+
481+ // const configureKeys = async () => {
482+
483+ // }
484+
469 interface TransferPointParams {
485 interface TransferPointParams {
470 point: Ship;
486 point: Ship;
471− from: From;
472 to: EthAddress;
487 to: EthAddress;
473− fromAddress: EthAddress;
488+ ownerAddress: EthAddress;
474− signingKey: string;
489+ wallet: any; // TODO: wallet type
475 }
490 }
476
491
477 const transferPoint = async ({
492 const transferPoint = async ({
478 point,
493 point,
479− from,
480 to,
494 to,
481− fromAddress,
495+ ownerAddress,
482− signingKey,
496+ wallet,
483 }: TransferPointParams) => {
497 }: TransferPointParams) => {
498+ const patp = ob.patp(point);
499+ const signingKey = wallet.ownership.keys.private;
484− const pointInfo = await api.getPoint(point);
500+ const azimuthPoint = await api.getPoint(point);
485
501
486− const { nonce } = getProxyAndNonce(pointInfo, fromAddress);
502+ const { nonce } = getProxyAndNonce(azimuthPoint, ownerAddress);
487 if (nonce === undefined) {
503 if (nonce === undefined) {
488 throw new Error('Nonce unavailable');
504 throw new Error('Nonce unavailable');
489 }
505 }
490− const transferData = { address: fromAddress, reset: true };
506+
507+ // update networking keys
508+ // TODO: extract this to a useRoller#configureKeys function?
509+ const networkRevision = convertToInt(azimuthPoint.network.keys.life, 10);
510+ const nextRevision = networkRevision + 1;
511+ const seed = await deriveNetworkSeedFromUrbitWallet(wallet, nextRevision);
512+ const keys = deriveNetworkKeys(seed.value);
513+ const keysData = {
514+ address: ownerAddress,
515+ encrypt: keys.crypt.public,
516+ breach: false,
517+ auth: keys.auth.public,
518+ cryptoSuite: CRYPTO_SUITE_VERSION,
519+ };
520+ const keysFrom: From = {
521+ ship: patp,
522+ proxy: 'own',
523+ };
524+
491− const transferHash: Hash = await api.hashTransaction(
525+ const keysHash: Hash = await api.hashTransaction(
492 nonce,
526 nonce,
493− from,
527+ keysFrom,
528+ 'configureKeys',
529+ keysData
530+ );
531+
532+ await api.configureKeys(
533+ signTransactionHash(keysHash, Buffer.from(signingKey, 'hex')),
534+ keysFrom,
535+ ownerAddress,
536+ keysData
537+ );
538+
539+ // transfer point
540+ const transferFrom: From = {
541+ ship: patp,
542+ proxy: 'transfer',
543+ };
544+
545+ const transferData = { address: ownerAddress, reset: false };
546+ const transferHash: Hash = await api.hashTransaction(
547+ nonce + 1,
548+ transferFrom,
494 'transferPoint',
549 'transferPoint',
495 transferData
550 transferData
496 );
551 );
497
552
498− const sig = signTransactionHash(
553+ const transferTxHash = await api.transferPoint(
499− transferHash,
500− Buffer.from(signingKey, 'hex')
554+ signTransactionHash(transferHash, Buffer.from(signingKey, 'hex')),
555+ transferFrom,
556+ to,
557+ transferData
501 );
558 );
502− const transferTxHash = await api.transferPoint(sig, from, to, transferData);
503
559
504 return transferTxHash;
560 return transferTxHash;
505 };
561 };
src/views/Activate/ActivateButton.tsx+1
@@ -28,6 +28,7 @@ const ActivateButton = ({
28 height={'50px'}
28 height={'50px'}
29 fontWeight={'400'}
29 fontWeight={'400'}
30 fontSize={'18px'}
30 fontSize={'18px'}
31+ disabled={disabled}
31 opacity={disabled ? 0.2 : 1.0}
32 opacity={disabled ? 0.2 : 1.0}
32 {...rest}>
33 {...rest}>
33 {children}
34 {children}
src/views/Activate/MasterKeyTransfer.tsx+19−119
@@ -1,141 +1,39 @@
1−import React, { useState, useCallback, useMemo, useEffect } from 'react';
1+import React, { useState, useCallback, useMemo } from 'react';
2
2
3−import { useNetwork } from 'store/network';
4−import { useWallet } from 'store/wallet';
5−import { useHistory } from 'store/history';
6−import { usePointCursor } from 'store/pointCursor';
7−
8−import * as need from 'lib/need';
9import useLifecycle from 'lib/useLifecycle';
3import useLifecycle from 'lib/useLifecycle';
10−import useBlockWindowClose from 'lib/useBlockWindowClose';
11−import { reticketPointBetweenWallets } from 'lib/reticket';
12
4
13import { Anchor, Box, Text } from '@tlon/indigo-react';
5import { Anchor, Box, Text } from '@tlon/indigo-react';
14import { useActivateFlow } from './ActivateFlow';
6import { useActivateFlow } from './ActivateFlow';
15import ActivateView from './ActivateView';
7import ActivateView from './ActivateView';
16−import { POINT_DOMINIONS } from 'lib/constants';
17−import { From } from '@urbit/roller-api';
18import useRoller from 'lib/useRoller';
8import useRoller from 'lib/useRoller';
19import { FadeableActivateHeader as ActivateHeader } from './ActivateHeader';
9import { FadeableActivateHeader as ActivateHeader } from './ActivateHeader';
20import { FadeableActivateButton as ActivateButton } from './ActivateButton';
10import { FadeableActivateButton as ActivateButton } from './ActivateButton';
21import useFadeIn from './useFadeIn';
11import useFadeIn from './useFadeIn';
22import PointPresenter from './PointPresenter';
12import PointPresenter from './PointPresenter';
13+import DangerBox from './DangerBox';
23
14
24−const MasterKeyTransfer = ({ className, resetActivateRouter }) => {
15+const MasterKeyTransfer = () => {
25− const { replaceWith, names } = useHistory();
26− const { setUrbitWallet } = useWallet();
27− const { setPointCursor } = usePointCursor();
28− const { web3, contracts, networkType } = useNetwork();
29 const { api, transferPoint } = useRoller();
16 const { api, transferPoint } = useRoller();
30− const {
31− derivedPatp,
32− derivedPoint,
33− derivedPointDominion,
34− derivedWallet,
35− inviteWallet,
36− reset: resetActivateFlow,
37− } = useActivateFlow();
17+ const { derivedPatp, derivedPoint, derivedWallet } = useActivateFlow();
38− const [generalError, setGeneralError] = useState();
18+ const [error, setError] = useState();
39− const [progress, setProcesss] = useState(0);
40− const [needFunds, setNeedFunds] = useState();
41−
42− // const [transferTxHash, setTransferTxHash] = useState<string | null>(null);
43−
44− const _inviteWallet = need.wallet(inviteWallet);
45− const _wallet = need.wallet(derivedWallet);
46− const _point = need.point(derivedPoint);
47− const _web3 = need.web3(web3);
48− const _contracts = need.contracts(contracts);
49−
50− const goToLogin = useCallback(
51− () => replaceWith([{ key: names.LOGIN }, { key: names.POINT }]),
52− [replaceWith, names]
53− );
54−
55− const goToRestart = useCallback(() => {
56− // NOTE: because we're already on the ACTIVATE view in the history,
57− // react (intelligently) doesn't trigger a re-render and that means the
58− // current state of the two nested routers (activate & passport) stick
59− // around unless we manually clear them.
60− // we only need to clear activate because that will unmount the passport
61− // router (which will be set to initialRoutes when mounted again)
62−
63− // 2) reset local router
64− resetActivateRouter();
65− // 3) clear the state
66− resetActivateFlow();
67− }, [resetActivateRouter, resetActivateFlow]);
68−
69− const claimL2Point = useCallback(async () => {
70− console.log('claiming l2 point:');
71− const transferFrom: From = {
72− ship: derivedPatp.value,
73− proxy: 'transfer',
74− };
75−
76− const l2point = await api.getPoint(derivedPoint.value);
77− const fromAddress = l2point.ownership?.owner?.address!;
78− const txHash = await transferPoint({
79− point: derivedPoint.value,
80− from: transferFrom,
81− to: _inviteWallet.address,
82− fromAddress: fromAddress,
83− signingKey: derivedWallet.value.ownership.keys.private,
84− });
85−
86− // setTransferTxHash(txHash);
87− }, [
88− _inviteWallet.address,
89− api,
90− derivedPatp.value,
91− derivedPoint.value,
92− derivedWallet.value,
93− transferPoint,
94− ]);
95−
96− // const claimL1Point = useCallback(async () => {
97− // await reticketPointBetweenWallets({
98− // fromWallet: _inviteWallet,
99− // toWallet: _wallet,
100− // point: _point,
101− // web3: _web3,
102− // contracts: _contracts,
103− // networkType,
104− // onUpdate: handleUpdate,
105− // transferEth: true,
106− // //NOTE not passing wc function, we always have invite ticket wallet
107− // });
108− // }, [_contracts, _inviteWallet, _point, _wallet, _web3, networkType]);
109
19
110 const claimPoint = useCallback(async () => {
20 const claimPoint = useCallback(async () => {
111− setGeneralError(false);
21+ setError(undefined);
112
22
113 try {
23 try {
114− // If L2
24+ const l2point = await api.getPoint(derivedPoint.value);
115− if (derivedPointDominion.value === POINT_DOMINIONS.L2) {
25+ await transferPoint({
116− await claimL2Point();
117− } else {
118− // await claimL1Point();
119− console.log('do nothing for now');
120− }
121−
122− // If L1
123−
124− // set the global wallet
125− // setUrbitWallet(derivedWallet);
126− // setPointCursor(derivedPoint);
26+ point: derivedPoint.value,
127−
27+ to: derivedWallet.value.ownership.address,
128− // and redirect to login
28+ ownerAddress: l2point.ownership?.owner?.address!,
129− // await timeout(3000);
29+ wallet: derivedWallet.value,
130− // goToLogin();
30+ });
131 } catch (error) {
31 } catch (error) {
132 console.error(error);
32 console.error(error);
133− // some generic error
33+ setError(error);
134− setGeneralError(error);
135 }
34 }
136− }, [derivedPointDominion, claimL2Point]);
35+ }, [api, derivedPoint.value, derivedWallet.value, transferPoint]);
137
36
138− // useBlockWindowClose();
139 useFadeIn();
37 useFadeIn();
140
38
141 useLifecycle(() => {
39 useLifecycle(() => {
@@ -165,13 +63,15 @@ const MasterKeyTransfer = ({ className, resetActivateRouter }) => {
165 flexDirection={'column'}
63 flexDirection={'column'}
166 flexWrap={'nowrap'}
64 flexWrap={'nowrap'}
167 justifyContent={'space-between'}>
65 justifyContent={'space-between'}>
66+ {error && <DangerBox>{error.toString()}</DangerBox>}
168 <ActivateButton
67 <ActivateButton
169 onClick={() =>
68 onClick={() =>
170 window.open(
69 window.open(
171 'https://github.com/urbit/port/releases/latest/download/Port.dmg'
70 'https://github.com/urbit/port/releases/latest/download/Port.dmg'
172 )
71 )
173 }
72 }
174− success={true}>
73+ success={true}
74+ disabled={error}>
175 Download the Client for Mac
75 Download the Client for Mac
176 </ActivateButton>
76 </ActivateButton>
177 <Anchor
77 <Anchor
@@ -188,7 +88,7 @@ const MasterKeyTransfer = ({ className, resetActivateRouter }) => {
188 </Anchor>
88 </Anchor>
189 </Box>
89 </Box>
190 );
90 );
191− }, []);
91+ }, [error]);
192
92
193 return (
93 return (
194 <ActivateView header={header} footer={footer}>
94 <ActivateView header={header} footer={footer}>