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/roller';
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 ViewHeader from 'components/ViewHeader';
27import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
28import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29import NoticeBox from 'components/NoticeBox';
30import AlertBox from 'components/AlertBox';
32import { HexInput } from 'form/Inputs';
35 buildCheckboxValidator,
37} from 'form/validators';
38import BridgeForm from 'form/BridgeForm';
39import Condition from 'form/Condition';
40import FormError from 'form/FormError';
41import { convertToInt } from 'lib/convertToInt';
43function useSetKeys(manualNetworkSeed, setManualNetworkSeed) {
44 const { urbitWallet, wallet, authMnemonic, authToken } = useWallet();
45 const { pointCursor } = usePointCursor();
46 const { syncDetails, syncRekeyDate, getDetails } = usePointCache();
47 const { contracts } = useNetwork();
49 const _point = need.point(pointCursor);
50 const _contracts = need.contracts(contracts);
51 const _details = need.details(getDetails(_point));
53 const networkRevision = convertToInt(_details.keyRevisionNumber, 10);
54 const randomSeed = useRef();
57 available: keyfileAvailable,
58 generating: keyfileGenerating,
61 } = useKeyfileGenerator(manualNetworkSeed);
63 const buildNetworkSeed = useCallback(
65 if (manualSeed !== undefined) {
66 setManualNetworkSeed(manualSeed);
69 const newNetworkRevision = networkRevision + 1;
70 console.log(`deriving seed with revision ${newNetworkRevision}`);
72 const networkSeed = await attemptNetworkSeedDerivation({
79 revision: newNetworkRevision,
82 if (Just.hasInstance(networkSeed)) {
83 return networkSeed.value;
86 randomSeed.current = randomSeed.current || randomHex(32); // 32 bytes
87 setManualNetworkSeed(randomSeed.current);
89 return randomSeed.current;
104 const { completed: _completed, ...rest } = useEthereumTransaction(
106 async (manualSeed, isDiscontinuity) => {
107 const seed = await buildNetworkSeed(manualSeed);
108 const pair = deriveNetworkKeys(seed);
110 return azimuth.ecliptic.configureKeys(
113 addHexPrefix(pair.crypt.public),
114 addHexPrefix(pair.auth.public),
115 CRYPTO_SUITE_VERSION,
119 [_contracts, _point, buildNetworkSeed]
122 () => Promise.all([syncDetails(_point), syncRekeyDate(_point)]),
123 [_point, syncDetails, syncRekeyDate]
125 GAS_LIMITS.CONFIGURE_KEYS
128 // only treat the transaction as completed once we also have keys to download
129 const completed = _completed && keyfileAvailable && !keyfileGenerating;
139export default function UrbitOSNetworkingKeys({
141 setManualNetworkSeed,
143 const { pop } = useLocalRouter();
144 const { pointCursor } = usePointCursor();
145 const { getDetails } = usePointCache();
146 const { currentL2, currentL2Spawn } = useRollerStore();
147 const { configureNetworkingKeys, getPendingTransactions } = useRoller();
148 const [breach, setBreach] = useState(false);
150 const point = need.point(pointCursor);
151 const details = getDetails(point);
153 const hasKeys = details.matchWith({
154 Nothing: () => false,
155 Just: ({ value: details }) => parseInt(details.keyRevisionNumber, 10) > 0,
156 // we actually don't mind the default NaN behavior of parseInt here,
157 // since NaN > 0 === false and that's a reasonable result
167 } = useSetKeys(manualNetworkSeed, setManualNetworkSeed);
169 const validateForm = useCallback((values, errors) => {
170 if (values.useNetworkSeed && errors.networkSeed) {
175 const validate = useMemo(
179 useNetworkSeed: buildCheckboxValidator(),
180 networkSeed: buildHexValidator(64), // 64 chars
181 useDiscontinuity: buildCheckboxValidator(),
188 const onValues = useCallback(
189 ({ valid, values, form }) => {
192 values.useNetworkSeed ? values.networkSeed : undefined,
193 values.useDiscontinuity
195 setBreach(values.useDiscontinuity);
196 setManualNetworkSeed(values.useNetworkSeed);
201 if (!values.useNetworkSeed && values.networkSeed) {
202 form.change('networkSeed', '');
204 setManualNetworkSeed('');
207 [construct, unconstruct, setManualNetworkSeed, setBreach]
210 const setNetworkingKeys = useCallback(async () => {
212 console.log(breach, manualNetworkSeed);
214 const txHash = await configureNetworkingKeys({
218 // TODO: just use the tx hash instead?
219 getPendingTransactions(point);
220 // TODO: this is just so we get visual feedback that the tx has gone through
221 // but this should be addressed with the new UI flow (-> download keyfile)
223 // A question here is how to deal with the modals/messages about the keys not being
224 // set since they are in pending in the Roller...
225 // we could inspect if there's a changeKeys in the local list of pending txs,...
231 // setLoading(false);
236 getPendingTransactions,
239 configureNetworkingKeys,
242 const initialValues = useMemo(
244 useNetworkSeed: false,
245 useDiscontinuity: false,
250 const viewTitle = completed
251 ? 'Network Keys are now set'
252 : 'Set Networking Keys';
255 'You need this keyfile to authenticate with your OS. Please Download.';
260 <Grid.Item full as={ViewHeader}>
264 <Grid.Item className="gray4 f5" full>
265 Network Keys authenticate Urbit ID with Urbit OS.
273 as={DownloadKeyfileButton}
277 <Grid.Item full as={AlertBox} className="mb8">
285 initialValues={initialValues}>
293 name="useNetworkSeed"
294 label="Use Custom Network Seed"
295 inverseLabel="Back to Derived Network Seed"
296 disabled={inputsLocked}
298 <Condition when="useNetworkSeed" is={true}>
299 <Grid.Item full as={NoticeBox} className="mb2">
300 When using a custom network seed, you'll need to download
301 your Arvo keyfile immediately after this transaction as
302 Bridge does not store your seed.
308 label="Network Seed (32 bytes)"
309 disabled={inputsLocked}
315 name="useDiscontinuity"
316 label="Breach Continuity"
317 disabled={inputsLocked}
320 <Grid.Item full as={FormError} />
324 {currentL2 && !currentL2Spawn ? (
331 onClick={setNetworkingKeys}>
337 as={InlineEthereumTransaction}
339 label={`${hasKeys ? 'Reset' : 'Set'} Networking Keys`}
340 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