@@ -1,6 +1,14 @@
1import React, { useCallback, useEffect, useState } from 'react';
1import React, { useCallback, useEffect, useState } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
2import { Just, Nothing } from 'folktale/maybe';
3−import { Grid, Text, H5, Flex } from 'indigo-react';
11+} from 'indigo-react';
4import * as azimuth from 'azimuth-js';
12import * as azimuth from 'azimuth-js';
5import { randomHex } from 'web3-utils';
13import { randomHex } from 'web3-utils';
@@ -23,11 +31,12 @@ import { addHexPrefix } from 'lib/wallet';
24import ViewHeader from 'components/ViewHeader';
32import ViewHeader from 'components/ViewHeader';
25import MiniBackButton from 'components/MiniBackButton';
33import MiniBackButton from 'components/MiniBackButton';
26−import { BootArvoButton, ForwardButton } from 'components/Buttons';
34+import { BootArvoButton } from 'components/Buttons';
27import FooterButton from 'components/FooterButton';
35import FooterButton from 'components/FooterButton';
28import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
36import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
29import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
37import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
30import NoticeBox from 'components/NoticeBox';
38import NoticeBox from 'components/NoticeBox';
39+import { useHexInput, useCheckboxInput } from 'lib/useInputs';
32const chainKeyProp = name => d =>
41const chainKeyProp = name => d =>
33 d[name] === ZERO_KEY ? Nothing() : Just(d[name]);
42 d[name] === ZERO_KEY ? Nothing() : Just(d[name]);
@@ -50,13 +59,15 @@ function useSetKeys() {
50 const _point = need.point(pointCursor);
59 const _point = need.point(pointCursor);
51 const _contracts = need.contracts(contracts);
60 const _contracts = need.contracts(contracts);
53− const [isDiscontinuity] = useState(false);
54− // TODO: set discontinuity with radio check?
55 const [ndNetworkSeed, setNdNetworkSeed] = useState();
62 const [ndNetworkSeed, setNdNetworkSeed] = useState();
57− const { construct, broadcasting, confirmed, bind } = useEthereumTransaction(
64+ const {
66+ construct: _construct,
58− GAS_LIMITS.CONFIGURE_KEYS
70+ } = useEthereumTransaction(GAS_LIMITS.CONFIGURE_KEYS);
61 // sync point details after success
72 // sync point details after success
62 useEffect(() => {
73 useEffect(() => {
@@ -65,54 +76,56 @@ function useSetKeys() {
66 }, [_point, confirmed, syncOwnedPoint]);
77 }, [_point, confirmed, syncOwnedPoint]);
68− const setKeys = useCallback(async () => {
79+ const construct = useCallback(
80+ async (manualSeed, isDiscontinuity) => {
69− const details = need.details(getDetails(_point));
81+ const details = need.details(getDetails(_point));
70− const networkRevision = parseInt(details.keyRevisionNumber, 10);
82+ const networkRevision = parseInt(details.keyRevisionNumber, 10);
84+ let _seed = manualSeed;
86+ const networkSeed = await attemptNetworkSeedDerivation({
72− console.log('setting revision to ', networkRevision + 1);
91+ revision: networkRevision + 1,
94+ _seed = networkSeed.matchWith({
96+ const ndSeed = randomHex(64);
97+ setNdNetworkSeed(ndSeed);
103+ const pair = deriveNetworkKeys(_seed);
105+ const txn = azimuth.ecliptic.configureKeys(
108+ addHexPrefix(pair.crypt.public),
109+ addHexPrefix(pair.auth.public),
110+ CRYPTO_SUITE_VERSION,
111+ isDiscontinuity ? 1 : 0
74− const seed = await attemptNetworkSeedDerivation({
114+ _construct(txn);
77− authMnemonic,
117+ _construct,
79− revision: networkRevision + 1,
82− const _networkSeed = seed.matchWith({
84− const ndSeed = randomHex(64);
85− setNdNetworkSeed(ndSeed);
91− const pair = deriveNetworkKeys(_networkSeed);
93− const txn = azimuth.ecliptic.configureKeys(
94 _contracts,
118 _contracts,
96− addHexPrefix(pair.crypt.public),
97− addHexPrefix(pair.auth.public),
98− CRYPTO_SUITE_VERSION,
106− authMnemonic,
120+ authMnemonic,
108− getDetails,
121+ getDetails,
110− urbitWallet,
122+ urbitWallet,
115− setKeys,
128+ isDefaultState,
116 construct,
129 construct,
117 broadcasting,
130 broadcasting,
118 confirmed,
131 confirmed,
@@ -134,19 +147,62 @@ export default function AdminNetworkingKeys() {
134 Just: ({ value: details }) => parseInt(details.keyRevisionNumber, 10) > 0,
147 Just: ({ value: details }) => parseInt(details.keyRevisionNumber, 10) > 0,
137− const [didRequestSetKeys, _setDidRequestSetKeys] = useState(false);
150+ const [showNetworkSeedInput, { data: showNetworkSeed }] = useCheckboxInput({
151+ name: 'shownetworkseed',
152+ label: 'Use Custom Network Seed',
153+ inverseLabel: 'Back to Derived Network Seed',
154+ initialValue: false,
158+ { pass: validNetworkSeed, data: networkSeed },
159+ { setValue: setNetworkSeed },
161+ name: 'networkseed',
162+ label: 'Network Seed (64 bytes)',
163+ length: 32, // 64 bytes
168+ { pass: validDiscontinuity, data: isDiscontinuity },
169+ ] = useCheckboxInput({
170+ name: 'discontinuity',
171+ label: 'Trigger New Continuity Era',
173+ initialValue: false,
139− setKeys,
177+ isDefaultState,
140 broadcasting,
179 broadcasting,
141 confirmed,
180 confirmed,
142 ndNetworkSeed,
181 ndNetworkSeed,
144 } = useSetKeys();
183 } = useSetKeys();
146− const setDidRequestSetKeys = useCallback(() => {
185+ useEffect(() => {
148− _setDidRequestSetKeys(true);
187+ (!showNetworkSeed || (showNetworkSeed && validNetworkSeed)) &&
149− }, [setKeys, _setDidRequestSetKeys]);
188+ validDiscontinuity
190+ construct(networkSeed, isDiscontinuity);
202+ if (!showNetworkSeed) {
205+ }, [setNetworkSeed, showNetworkSeed]);
151 const goRelocate = useCallback(() => push(names.RELOCATE), [push, names]);
207 const goRelocate = useCallback(() => push(names.RELOCATE), [push, names]);
@@ -166,33 +222,6 @@ export default function AdminNetworkingKeys() {
166 return 'Networking';
222 return 'Networking';
169− const renderButton = () => {
170− if (!didRequestSetKeys) {
176− onClick={() => setDidRequestSetKeys(true)}>
177− {hasKeys ? 'Reset' : 'Set'} Networking Keys
186− as={DownloadKeyfileButton}
188− networkSeed={ndNetworkSeed}
196 const renderNetworkKeySection = (title, key) => (
225 const renderNetworkKeySection = (title, key) => (
198 <Grid.Item full as={H5} className="mt3 gray4">
227 <Grid.Item full as={H5} className="mt3 gray4">
@@ -279,32 +308,52 @@ export default function AdminNetworkingKeys() {
279 {renderTitle()}
308 {renderTitle()}
280 </Grid.Item>
309 </Grid.Item>
282− {!didRequestSetKeys && (
283− <Grid.Item full as={Text} className="mb3">
311+ <Grid.Item full as={Text} className="mb3">
284− {hasKeys
312+ {hasKeys
285− ? 'Here are your public keys that authenticate your Arvo.'
313+ ? 'Here are your public keys that authenticate your Arvo.'
286− : 'Set your networking keys to authenticate with Arvo.'}
314+ : 'Set your networking keys to authenticate with Arvo.'}
287− </Grid.Item>
315+ </Grid.Item>
290 {confirmed && (
317 {confirmed && (
291− <Grid.Item full as={NoticeBox} className="mb3">
319+ <Grid.Item full as={NoticeBox} className="mb3">
292− You need this keyfile to authenticate with Arvo.
320+ You need this keyfile to authenticate with Arvo.
293− </Grid.Item>
321+ </Grid.Item>
324+ as={DownloadKeyfileButton}
326+ networkSeed={ndNetworkSeed}
296− {renderButton()}
331+ {!confirmed && (
298− {didRequestSetKeys && (
333+ <Grid.Item full as={ToggleInput} {...showNetworkSeedInput} />
299− <Grid.Item
334+ {showNetworkSeed && (
301− as={InlineEthereumTransaction}
336+ <Grid.Item full as={NoticeBox} className="mb2">
302− {...bind}
337+ When using a custom network seed, you'll need to download your
303− onReturn={() => pop()}
338+ Arvo keyfile immediately after this transaction is
304− />
339+ confirmed—Multipass does not store your seed.
341+ <Grid.Item full as={Input} {...networkSeedInput} />
344+ <Grid.Item full as={CheckboxInput} {...discontinuityInput} />
350+ as={InlineEthereumTransaction}
352+ label={`${hasKeys ? 'Reset' : 'Set'} Networking Keys`}
353+ onReturn={() => pop()}
307− {!didRequestSetKeys && renderDetails()}
356+ {isDefaultState && renderDetails()}
309 {confirmed && (
358 {confirmed && (
@@ -314,7 +363,7 @@ export default function AdminNetworkingKeys() {
317− {!didRequestSetKeys && (
366+ {isDefaultState && (
318 <FooterButton onClick={goRelocate} disabled>
367 <FooterButton onClick={goRelocate} disabled>
320 </FooterButton>
369 </FooterButton>