1import React, { useCallback, useMemo, useRef, useState } from 'react';
2import { Just } from 'folktale/maybe';
3import { Grid, ToggleInput, CheckboxInput, Button } from 'indigo-react';
4import * as azimuth from 'azimuth-js';
5import { randomHex } from 'web3-utils';
7import { usePointCursor } from 'store/pointCursor';
8import { usePointCache } from 'store/pointCache';
9import { useNetwork } from 'store/network';
10import { useWallet } from 'store/wallet';
11import { useRollerStore } from 'store/rollerStore';
13import useRoller from 'lib/useRoller';
14import { useLocalRouter } from 'lib/LocalRouter';
15import * as need from 'lib/need';
17 attemptNetworkSeedDerivation,
21import useEthereumTransaction from 'lib/useEthereumTransaction';
22import { GAS_LIMITS } from 'lib/constants';
23import { addHexPrefix } from 'lib/utils/address';
24import useKeyfileGenerator from 'lib/useKeyfileGenerator';
26import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
27import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
28import NoticeBox from 'components/NoticeBox';
29import AlertBox from 'components/AlertBox';
31import { HexInput } from 'form/Inputs';
34 buildCheckboxValidator,
36} from 'form/validators';
37import BridgeForm from 'form/BridgeForm';
38import Condition from 'form/Condition';
39import FormError from 'form/FormError';
40import { convertToInt } from 'lib/convertToInt';
41import Window from 'components/L2/Window/Window';
42import HeaderPane from 'components/L2/Window/HeaderPane';
43import BodyPane from 'components/L2/Window/BodyPane';
44import { Box, Row } from '@tlon/indigo-react';
46function useSetKeys(manualNetworkSeed, setManualNetworkSeed) {
47 const { urbitWallet, wallet, authMnemonic, authToken } = useWallet();
48 const { pointCursor } = usePointCursor();
49 const { syncDetails, syncRekeyDate, getDetails } = usePointCache();
50 const { contracts } = useNetwork();
52 const _point = need.point(pointCursor);
53 const _contracts = need.contracts(contracts);
54 const _details = need.details(getDetails(_point));
56 const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
57 const randomSeed = useRef();
60 available: keyfileAvailable,
61 generating: keyfileGenerating,
64 } = useKeyfileGenerator(manualNetworkSeed);
66 const buildNetworkSeed = useCallback(
68 if (manualSeed !== undefined) {
69 setManualNetworkSeed(manualSeed);
72 const newNetworkRevision = networkRevision + 1;
73 console.log(`deriving seed with revision ${newNetworkRevision}`);
75 const networkSeed = await attemptNetworkSeedDerivation({
82 revision: newNetworkRevision,
85 if (Just.hasInstance(networkSeed)) {
86 return networkSeed.value;
89 randomSeed.current = randomSeed.current || randomHex(32); // 32 bytes
90 setManualNetworkSeed(randomSeed.current);
92 return randomSeed.current;
107 const { completed: _completed, ...rest } = useEthereumTransaction(
109 async (manualSeed, isDiscontinuity) => {
110 const seed = await buildNetworkSeed(manualSeed);
111 const pair = deriveNetworkKeys(seed);
113 return azimuth.ecliptic.configureKeys(
116 addHexPrefix(pair.crypt.public),
117 addHexPrefix(pair.auth.public),
118 CRYPTO_SUITE_VERSION,
122 [_contracts, _point, buildNetworkSeed]
125 () => Promise.all([syncDetails(_point), syncRekeyDate(_point)]),
126 [_point, syncDetails, syncRekeyDate]
128 GAS_LIMITS.CONFIGURE_KEYS
131 // only treat the transaction as completed once we also have keys to download
132 const completed = _completed && keyfileAvailable && !keyfileGenerating;
142export default function UrbitOSNetworkingKeys({
144 setManualNetworkSeed,
146 const { pop } = useLocalRouter();
147 const { pointCursor } = usePointCursor();
148 const { getDetails } = usePointCache();
151 } = useRollerStore();
152 const { configureNetworkingKeys, getPendingTransactions } = useRoller();
153 const [breach, setBreach] = useState(false);
155 const point = need.point(pointCursor);
156 const details = getDetails(point);
158 const hasKeys = details.matchWith({
159 Nothing: () => false,
160 Just: ({ value: details }) => parseInt(details.keyRevisionNumber, 10) > 0,
161 // we actually don't mind the default NaN behavior of parseInt here,
162 // since NaN > 0 === false and that's a reasonable result
172 } = useSetKeys(manualNetworkSeed, setManualNetworkSeed);
174 const validateForm = useCallback((values, errors) => {
175 if (values.useNetworkSeed && errors.networkSeed) {
180 const validate = useMemo(
184 useNetworkSeed: buildCheckboxValidator(),
185 networkSeed: buildHexValidator(64), // 64 chars
186 useDiscontinuity: buildCheckboxValidator(),
193 const onValues = useCallback(
194 ({ valid, values, form }) => {
197 values.useNetworkSeed ? values.networkSeed : undefined,
198 values.useDiscontinuity
200 setBreach(values.useDiscontinuity);
201 setManualNetworkSeed(values.useNetworkSeed);
206 if (!values.useNetworkSeed && values.networkSeed) {
207 form.change('networkSeed', '');
209 setManualNetworkSeed('');
212 [construct, unconstruct, setManualNetworkSeed, setBreach]
215 const setNetworkingKeys = useCallback(async () => {
218 await configureNetworkingKeys({
222 // TODO: just use the tx hash instead?
223 getPendingTransactions(point);
224 // TODO: this is just so we get visual feedback that the tx has gone through
225 // but this should be addressed with the new UI flow (-> download keyfile)
227 // A question here is how to deal with the modals/messages about the keys not being
228 // set since they are in pending in the Roller...
229 // we could inspect if there's a changeKeys in the local list of pending txs,...
235 // setLoading(false);
240 getPendingTransactions,
243 configureNetworkingKeys,
246 const initialValues = useMemo(
248 useNetworkSeed: false,
249 useDiscontinuity: false,
254 const viewTitle = completed
255 ? 'Network Keys are now set'
256 : 'Set Networking Keys';
259 'You need this keyfile to authenticate with your OS. Please Download.';
264 <Row className="header-row">
270 <Grid.Item className="gray4 f5 mv2 align-self-start" full>
271 Network Keys authenticate Urbit ID with Urbit OS.
279 as={DownloadKeyfileButton}
284 <Grid.Item full as={AlertBox} className="mb8">
292 initialValues={initialValues}>
300 name="useNetworkSeed"
301 label="Use Custom Network Seed"
302 inverseLabel="Back to Derived Network Seed"
303 disabled={inputsLocked}
305 <Condition when="useNetworkSeed" is={true}>
306 <Grid.Item full as={NoticeBox} className="mb2">
307 When using a custom network seed, you'll need to download
308 your Arvo keyfile immediately after this transaction as
309 Bridge does not store your seed.
315 label="Network Seed (32 bytes)"
316 disabled={inputsLocked}
323 name="useDiscontinuity"
324 label="Breach Continuity"
325 disabled={inputsLocked}
329 <Grid.Item full as={FormError} />
340 onClick={setNetworkingKeys}>
341 {'Reset Networking Keys'}
346 as={InlineEthereumTransaction}
348 label={`${hasKeys ? 'Reset' : 'Set'} Networking Keys`}
349 onReturn={() => pop()}
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list