on master help sign in
refactor: minor changes from self-code-review
60ad7acMatt Condon (shrugs)
src/components/InlineEthereumTransaction.js+1−1
@@ -87,7 +87,7 @@ export default function InlineEthereumTransaction({
87 as={ForwardButton}
87 as={ForwardButton}
88 solid
88 solid
89 success
89 success
90− disable={broadcasted}
90+ disabled={broadcasted}
91 loading={broadcasted}
91 loading={broadcasted}
92 onClick={() => broadcast()}>
92 onClick={() => broadcast()}>
93 Send Transaction
93 Send Transaction
src/lib/constants.js+8
@@ -18,9 +18,13 @@ const GALAXY_ENTROPY_BITS = 384;
18
18
19const SEED_ENTROPY_BITS = 128;
19const SEED_ENTROPY_BITS = 128;
20
20
21+// the curve param for the network keys
22+const NETWORK_KEY_CURVE_PARAMETER = '42';
21// the null result if a key is unset within azimuth
23// the null result if a key is unset within azimuth
22const ZERO_KEY =
24const ZERO_KEY =
23 '0x0000000000000000000000000000000000000000000000000000000000000000';
25 '0x0000000000000000000000000000000000000000000000000000000000000000';
26+// the current crypto suite version
27+const CRYPTO_SUITE_VERSION = 1;
24
28
25//TODO move into azimuth-js
29//TODO move into azimuth-js
26const GAS_LIMITS = {
30const GAS_LIMITS = {
@@ -37,6 +41,8 @@ const GAS_LIMITS = {
37 //
41 //
38 GIFT_PLANET: 400000, //NOTE low sample size
42 GIFT_PLANET: 400000, //NOTE low sample size
39 //
43 //
44+ SEND_ETH: 21000,
45+ //
40 DEFAULT: 550000,
46 DEFAULT: 550000,
41};
47};
42
48
@@ -89,5 +95,7 @@ export {
89 GALAXY_ENTROPY_BITS,
95 GALAXY_ENTROPY_BITS,
90 SEED_ENTROPY_BITS,
96 SEED_ENTROPY_BITS,
91 ZOD,
97 ZOD,
98+ NETWORK_KEY_CURVE_PARAMETER,
92 ZERO_KEY,
99 ZERO_KEY,
100+ CRYPTO_SUITE_VERSION,
93};
101};
src/lib/error.js+2
@@ -7,6 +7,8 @@ const BRIDGE_ERROR = {
7 MISSING_MNEMONIC: 'no authentication mnemonic found',
7 MISSING_MNEMONIC: 'no authentication mnemonic found',
8 MISSING_URBIT_WALLET: 'no urbit wallet found',
8 MISSING_URBIT_WALLET: 'no urbit wallet found',
9 MISSING_POINT: 'no point found',
9 MISSING_POINT: 'no point found',
10+ MISSING_AUTH_MNEMONIC: 'no mnemonic found',
11+ MISSING_POINT_DETAILS: 'no details of point found',
10 INVALID_ROUTE: 'invalid route',
12 INVALID_ROUTE: 'invalid route',
11 INVALID_NETWORK_TYPE: 'invalid network type',
13 INVALID_NETWORK_TYPE: 'invalid network type',
12 INVALID_WALLET_TYPE: 'invalid wallet type',
14 INVALID_WALLET_TYPE: 'invalid wallet type',
src/lib/invite.js+11−6
@@ -10,7 +10,12 @@ import { hexify } from './txn';
10import { deriveNetworkSeedFromUrbitWallet, deriveNetworkKeys } from './keys';
10import { deriveNetworkSeedFromUrbitWallet, deriveNetworkKeys } from './keys';
11import { addHexPrefix } from './wallet';
11import { addHexPrefix } from './wallet';
12import { sendAndAwaitAll } from './txn';
12import { sendAndAwaitAll } from './txn';
13+import {
14+ GAS_LIMITS,
15+ DEFAULT_GAS_PRICE_GWEI,
16+ CRYPTO_SUITE_VERSION,
13−import { GAS_LIMITS } from './constants';
17+} from './constants';
18+import { toWei } from 'web3-utils';
14
19
15// the initial network key revision is always 1
20// the initial network key revision is always 1
16const INITIAL_NETWORK_KEY_REVISION = 1;
21const INITIAL_NETWORK_KEY_REVISION = 1;
@@ -138,8 +143,8 @@ export async function reticketPointBetweenWallets({
138 point,
143 point,
139 addHexPrefix(networkKeys.crypt.public),
144 addHexPrefix(networkKeys.crypt.public),
140 addHexPrefix(networkKeys.auth.public),
145 addHexPrefix(networkKeys.auth.public),
141− 1,
146+ CRYPTO_SUITE_VERSION,
142− false
147+ /* discontinuous */ false
143 );
148 );
144 keysTx.gas = GAS_LIMITS.CONFIGURE_KEYS;
149 keysTx.gas = GAS_LIMITS.CONFIGURE_KEYS;
145
150
@@ -201,7 +206,7 @@ export async function reticketPointBetweenWallets({
201 txs = txs.map(tx => {
206 txs = txs.map(tx => {
202 tx.from = fromWallet.address;
207 tx.from = fromWallet.address;
203 tx.nonce = inviteNonce++;
208 tx.nonce = inviteNonce++;
204− tx.gasPrice = 20000000000; //NOTE we pay the premium for faster ux
209+ tx.gasPrice = parseInt(toWei(DEFAULT_GAS_PRICE_GWEI.toFixed(), 'gwei'), 10);
205 totalCost = totalCost + tx.gasPrice * tx.gas;
210 totalCost = totalCost + tx.gasPrice * tx.gas;
206 return tx;
211 return tx;
207 });
212 });
@@ -247,8 +252,8 @@ export async function reticketPointBetweenWallets({
247
252
248 // if non-trivial eth left in invite wallet, transfer to new ownership
253 // if non-trivial eth left in invite wallet, transfer to new ownership
249 let balance = await web3.eth.getBalance(fromWallet.address);
254 let balance = await web3.eth.getBalance(fromWallet.address);
250− const gasPrice = 20000000000;
255+ const gasPrice = parseInt(toWei(DEFAULT_GAS_PRICE_GWEI.toFixed(), 'gwei'));
251− const gasLimit = 21000;
256+ const gasLimit = GAS_LIMITS.SEND_ETH;
252 const sendEthCost = gasPrice * gasLimit;
257 const sendEthCost = gasPrice * gasLimit;
253 if (transferEth && balance > sendEthCost) {
258 if (transferEth && balance > sendEthCost) {
254 const value = balance - sendEthCost;
259 const value = balance - sendEthCost;
src/lib/keys.js+4−4
@@ -6,8 +6,7 @@ import * as serial from '../nockjs/serial';
6import * as kg from 'urbit-key-generation/dist';
6import * as kg from 'urbit-key-generation/dist';
7
7
8import { eqAddr, addHexPrefix, CURVE_ZERO_ADDR } from './wallet';
8import { eqAddr, addHexPrefix, CURVE_ZERO_ADDR } from './wallet';
9−
10−const NETWORK_KEY_CURVE_PARAMETER = '42';
9+import { NETWORK_KEY_CURVE_PARAMETER } from './constants';
11
10
12// ctsy joemfb
11// ctsy joemfb
13const b64 = buf => {
12const b64 = buf => {
@@ -164,11 +163,12 @@ export const keysMatchChain = (pair, details) => {
164};
163};
165
164
166export const segmentNetworkKey = hex => {
165export const segmentNetworkKey = hex => {
167− const sl = i => hex.slice(i, i + 4);
168− const rowFrom = i => `${sl(i)}.${sl(i + 4)}.${sl(i + 8)}.${sl(i + 12)}`;
169 if (hex === CURVE_ZERO_ADDR) {
166 if (hex === CURVE_ZERO_ADDR) {
170 return null;
167 return null;
171 }
168 }
172
169
170+ const sl = i => hex.slice(i, i + 4);
171+ const rowFrom = i => `${sl(i)}.${sl(i + 4)}.${sl(i + 8)}.${sl(i + 12)}`;
172+
173 return [rowFrom(2), rowFrom(18), rowFrom(34), rowFrom(50)];
173 return [rowFrom(2), rowFrom(18), rowFrom(34), rowFrom(50)];
174};
174};
src/lib/need.js+3−3
@@ -18,15 +18,15 @@ const needBuilder = fn => obj => {
18export const value = (obj, fn) => needBuilder(fn)(obj);
18export const value = (obj, fn) => needBuilder(fn)(obj);
19
19
20export const details = needBuilder(() => {
20export const details = needBuilder(() => {
21− throw new Error('need details of point');
21+ throw new Error(BRIDGE_ERROR.MISSING_POINT_DETAILS);
22});
22});
23
23
24export const authMnemonic = needBuilder(() => {
24export const authMnemonic = needBuilder(() => {
25− throw new Error('need auth mnemonic');
25+ throw new Error(BRIDGE_ERROR.MISSING_AUTH_MNEMONIC);
26});
26});
27
27
28export const web3 = needBuilder(() => {
28export const web3 = needBuilder(() => {
29− throw new Error(BRIDGE_ERROR.MISSING_WEB3.message);
29+ throw new Error(BRIDGE_ERROR.MISSING_WEB3);
30});
30});
31
31
32export const contracts = needBuilder(() => {
32export const contracts = needBuilder(() => {
src/lib/proxy.js+2−3
@@ -23,10 +23,9 @@ export const proxyTypeToHuman = proxyType => {
23export const proxyTypeToHumanDescription = proxyType => {
23export const proxyTypeToHumanDescription = proxyType => {
24 switch (proxyType) {
24 switch (proxyType) {
25 case PROXY_TYPE.MANAGEMENT:
25 case PROXY_TYPE.MANAGEMENT:
26− // TODO: is the below copy actually true?
26+ return 'The management proxy is allowed to manage networking keys.';
27− return "The management address proves your point's identity to Arvo.";
28 case PROXY_TYPE.SPAWN:
27 case PROXY_TYPE.SPAWN:
29− return 'The spawn proxy is allowed to spawn points from this point.';
28+ return 'The spawn proxy is allowed to spawn points.';
30 case PROXY_TYPE.TRANSFER:
29 case PROXY_TYPE.TRANSFER:
31 return 'The transfer proxy is allowed to transfer this point.';
30 return 'The transfer proxy is allowed to transfer this point.';
32 case PROXY_TYPE.VOTING:
31 case PROXY_TYPE.VOTING:
src/lib/useEthereumTransaction.js+29−27
@@ -1,4 +1,5 @@
1−import { useCallback, useEffect, useState } from 'react';
1+import { useCallback, useState } from 'react';
2+import { fromWei } from 'web3-utils';
2
3
3import { useNetwork } from 'store/network';
4import { useNetwork } from 'store/network';
4import { useWallet } from 'store/wallet';
5import { useWallet } from 'store/wallet';
@@ -9,7 +10,8 @@ import {
9 waitForTransactionConfirm,
10 waitForTransactionConfirm,
10} from './txn';
11} from './txn';
11import * as need from './need';
12import * as need from './need';
12−import { fromWei } from 'web3-utils';
13+import { GAS_LIMITS } from './constants';
14+import useLifecycle from './useLifecycle';
13
15
14const STATE = {
16const STATE = {
15 NONE: 'NONE',
17 NONE: 'NONE',
@@ -22,7 +24,10 @@ const STATE = {
22 * manage the state around sending and confirming an ethereum transaction
24 * manage the state around sending and confirming an ethereum transaction
23 * @param {number} initialGasLimit
25 * @param {number} initialGasLimit
24 */
26 */
25−export default function useEthereumTransaction(initialGasLimit = 0) {
27+export default function useEthereumTransaction(
28+ initialGasLimit = GAS_LIMITS.DEFAULT,
29+ initialGasPrice = 20
30+) {
26 const { wallet, walletType, walletHdPath } = useWallet();
31 const { wallet, walletType, walletHdPath } = useWallet();
27 const { web3, networkType } = useNetwork();
32 const { web3, networkType } = useNetwork();
28 const _web3 = need.web3(web3);
33 const _web3 = need.web3(web3);
@@ -41,7 +46,7 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
41 const [state, setState] = useState(STATE.NONE);
46 const [state, setState] = useState(STATE.NONE);
42 const [chainId, setChainId] = useState();
47 const [chainId, setChainId] = useState();
43 const [nonce, setNonce] = useState();
48 const [nonce, setNonce] = useState();
44− const [gasPrice, setGasPrice] = useState(20); // gwei
49+ const [gasPrice, setGasPrice] = useState(initialGasPrice); // gwei
45 const [gasLimit] = useState(initialGasLimit);
50 const [gasLimit] = useState(initialGasLimit);
46 const [unsignedTransaction, setUnsignedTransaction] = useState();
51 const [unsignedTransaction, setUnsignedTransaction] = useState();
47 const [signedTransaction, setSignedTransaction] = useState();
52 const [signedTransaction, setSignedTransaction] = useState();
@@ -53,8 +58,10 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
53 const broadcasted = state === STATE.BROADCASTED;
58 const broadcasted = state === STATE.BROADCASTED;
54 const confirmed = state === STATE.CONFIRMED;
59 const confirmed = state === STATE.CONFIRMED;
55
60
61+ // disable the inputs when:
56 const inputsLocked = signed || broadcasted || confirmed;
62 const inputsLocked = signed || broadcasted || confirmed;
57
63
64+ // we can sign when:
58 const canSign = !initializing && constructed;
65 const canSign = !initializing && constructed;
59
66
60 const construct = useCallback(txn => setUnsignedTransaction(txn), [
67 const construct = useCallback(txn => setUnsignedTransaction(txn), [
@@ -116,13 +123,15 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
116 }, [_web3, setError, signedTransaction]);
123 }, [_web3, setError, signedTransaction]);
117
124
118 const reset = useCallback(() => {
125 const reset = useCallback(() => {
126+ setUnsignedTransaction(undefined);
127+ setTxHash(undefined);
128+ setSignedTransaction(undefined);
129+ setGasPrice(initialGasPrice);
119 setState(STATE.NONE);
130 setState(STATE.NONE);
120 setError(undefined);
131 setError(undefined);
121− setGasPrice(0);
122− setSignedTransaction(undefined);
123− }, [setError]);
132+ }, [initialGasPrice, setError]);
124
133
125− useEffect(() => {
134+ useLifecycle(() => {
126 (async () => {
135 (async () => {
127 try {
136 try {
128 setError(undefined);
137 setError(undefined);
@@ -139,9 +148,9 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
139 setError(error);
148 setError(error);
140 }
149 }
141 })();
150 })();
142− }, [_wallet.address, _web3.eth, setError]);
151+ });
143
152
144− return {
153+ const values = {
145 initializing,
154 initializing,
146 construct,
155 construct,
147 constructed,
156 constructed,
@@ -154,24 +163,17 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
154 reset,
163 reset,
155 error,
164 error,
156 inputsLocked,
165 inputsLocked,
166+ //
157 txHash,
167 txHash,
158 signedTransaction,
168 signedTransaction,
159− bind: {
160− constructed,
161− canSign,
162− generateAndSign,
163− signed,
164− broadcast,
165− broadcasted,
166− confirmed,
167− reset,
168− error,
169− gasPrice,
169+ gasPrice,
170− setGasPrice,
170+ setGasPrice,
171− txHash,
172− nonce,
171+ nonce,
173− chainId,
172+ chainId,
174− signedTransaction,
175− },
173+ };
174+
175+ return {
176+ ...values,
177+ bind: values,
176 };
178 };
177}
179}
src/lib/useKeyfileGenerator.js+3−2
@@ -52,7 +52,7 @@ export default function useKeyfileGenerator(point, manualNetworkSeed) {
52
52
53 if (Nothing.hasInstance(networkSeed)) {
53 if (Nothing.hasInstance(networkSeed)) {
54 setGenerating(false);
54 setGenerating(false);
55− console.log('nondeterministic seed!');
55+ console.log('The network seed is nondeterministic — unable to derive.');
56 // TODO: tell user their seed is nondeterministic
56 // TODO: tell user their seed is nondeterministic
57 return;
57 return;
58 }
58 }
@@ -64,7 +64,8 @@ export default function useKeyfileGenerator(point, manualNetworkSeed) {
64 if (!keysMatchChain(pair, _details)) {
64 if (!keysMatchChain(pair, _details)) {
65 setGenerating(false);
65 setGenerating(false);
66 console.log('Derived networking keys do not match public keys on chain.');
66 console.log('Derived networking keys do not match public keys on chain.');
67− // TODO: tell usrs their seed is nondeterministic
67+ // TODO: tell users their seed is nondeterministic
68+ return;
68 }
69 }
69
70
70 setKeyfile(compileNetworkingKey(pair, point, networkRevision));
71 setKeyfile(compileNetworkingKey(pair, point, networkRevision));
src/lib/validators.js+5−5
@@ -204,7 +204,7 @@ export const validateExactly = (value, error) => m =>
204 error,
204 error,
205 });
205 });
206
206
207−export const validateNotEqual = (values = []) => m =>
207+export const validateNotAny = (values = []) => m =>
208 simpleValidatorWrapper({
208 simpleValidatorWrapper({
209 prevMessage: m,
209 prevMessage: m,
210 validator: d => !values.includes(d),
210 validator: d => !values.includes(d),
@@ -245,7 +245,7 @@ export const validateMaximumPatpByteLength = byteLength => {
245 return validateMaximumLength(patpStringLength(byteLength));
245 return validateMaximumLength(patpStringLength(byteLength));
246};
246};
247
247
248−export const validateNotNullAddress = validateNotEqual(
248+export const validateNotNullAddress = validateNotAny([
249+ ETH_ZERO_ADDR,
249− [ETH_ZERO_ADDR, ETH_ZERO_ADDR_SHORT],
250+ ETH_ZERO_ADDR_SHORT,
250− 'Cannot be 0x0'
251−);
251+]);
src/views/Admin/AdminNetworkingKeys.js+1−3
@@ -18,7 +18,7 @@ import {
18} from 'lib/keys';
18} from 'lib/keys';
19import { formatDotsWithTime } from 'lib/dateFormat';
19import { formatDotsWithTime } from 'lib/dateFormat';
20import useEthereumTransaction from 'lib/useEthereumTransaction';
20import useEthereumTransaction from 'lib/useEthereumTransaction';
21−import { GAS_LIMITS, ZERO_KEY } from 'lib/constants';
21+import { GAS_LIMITS, ZERO_KEY, CRYPTO_SUITE_VERSION } from 'lib/constants';
22import { addHexPrefix } from 'lib/wallet';
22import { addHexPrefix } from 'lib/wallet';
23
23
24import ViewHeader from 'components/ViewHeader';
24import ViewHeader from 'components/ViewHeader';
@@ -29,8 +29,6 @@ import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
29import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
30import NoticeBox from 'components/NoticeBox';
30import NoticeBox from 'components/NoticeBox';
31
31
32−const CRYPTO_SUITE_VERSION = 1;
33−
34const chainKeyProp = name => d =>
32const chainKeyProp = name => d =>
35 d[name] === ZERO_KEY ? Nothing() : Just(d[name]);
33 d[name] === ZERO_KEY ? Nothing() : Just(d[name]);
36
34
src/views/Login/Keystore.js+1−1
@@ -23,7 +23,7 @@ export default function Keystore({ className }) {
23 // inputs
23 // inputs
24 // keystore: Maybe<String>
24 // keystore: Maybe<String>
25 const [keystore, setKeystore] = useState(Nothing());
25 const [keystore, setKeystore] = useState(Nothing());
26− const [passphraseInput, { value: passphrase }] = usePassphraseInput({
26+ const [passphraseInput, { data: passphrase }] = usePassphraseInput({
27 name: 'password',
27 name: 'password',
28 label: 'Keystore password',
28 label: 'Keystore password',
29 autoFocus: true,
29 autoFocus: true,