on master help sign in
feat: implement transaction configuration
764521dMatt Condon (shrugs)
src/components/InlineEthereumTransaction.js+54−14
@@ -7,6 +7,8 @@ import {
7 Flex,
7 Flex,
8 LinkButton,
8 LinkButton,
9 H5,
9 H5,
10+ Text,
11+ HelpText,
10} from 'indigo-react';
12} from 'indigo-react';
11import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
13import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
12import { useCheckboxInput } from 'lib/useInputs';
14import { useCheckboxInput } from 'lib/useInputs';
@@ -25,20 +27,30 @@ export default function InlineEthereumTransaction({
25 confirmed,
27 confirmed,
26 reset,
28 reset,
27 error,
29 error,
30+ gasPrice,
28 setGasPrice,
31 setGasPrice,
29 txHash,
32 txHash,
33+ nonce,
34+ chainId,
30 signedTransaction,
35 signedTransaction,
31
36
32 // additional from parent
37 // additional from parent
33 className,
38 className,
34 onReturn,
39 onReturn,
35}) {
40}) {
41+ // show receipt after successful broadcast
42+ const showReceipt = broadcasted || confirmed;
43+ // show configure controls pre-broadcast
44+ const showConfigureInput = !(signed || broadcasted || confirmed);
45+ // show signed tx after signing
46+ const showSignedTx = signed;
47+
36 const exploreHashUrl = useExploreTxUrl(txHash);
48 const exploreHashUrl = useExploreTxUrl(txHash);
37− const [configureInput, { data: configurationOpen }] = useCheckboxInput({
49+ const [advancedInput, { data: advancedOpen }] = useCheckboxInput({
38− name: 'configure',
50+ name: 'advanced',
39− label: 'Configure Transaction',
51+ label: 'Advanced Configuration',
40− inverseLabel: 'Cancel Configure Transaction',
52+ inverseLabel: 'Hide Advanced Configuration',
41− disabled: signed || broadcasted || confirmed,
53+ disabled: !showConfigureInput,
42 });
54 });
43
55
44 const [
56 const [
@@ -48,16 +60,9 @@ export default function InlineEthereumTransaction({
48 name: 'viewsigned',
60 name: 'viewsigned',
49 label: 'View Signed Transaction',
61 label: 'View Signed Transaction',
50 inverseLabel: 'Hide Signed Transaction',
62 inverseLabel: 'Hide Signed Transaction',
51− disabled: !signed,
63+ disabled: !showSignedTx,
52 });
64 });
53
65
54− // show receipt after successful broadcast
55− const showReceipt = broadcasted || confirmed;
56− // show configure controls pre-broadcast
57− const showConfigureInput = !(broadcasted || confirmed);
58− // show signed tx after signing
59− const showSignedTx = signed;
60−
61 const renderButton = () => {
66 const renderButton = () => {
62 if (error) {
67 if (error) {
63 return (
68 return (
@@ -122,7 +127,42 @@ export default function InlineEthereumTransaction({
122 )}
127 )}
123
128
124 {showConfigureInput && (
129 {showConfigureInput && (
130+ <>
131+ {!advancedOpen ? (
125− <Grid.Item full as={ToggleInput} {...configureInput} />
132+ <Grid.Item full as={ToggleInput} {...advancedInput} />
133+ ) : (
134+ <>
135+ <Grid.Item full as={Flex} row justify="between" className="mt2">
136+ <Flex.Item as={H5}>Gas Price</Flex.Item>
137+ <Flex.Item as={H5}>{gasPrice} Gwei</Flex.Item>
138+ </Grid.Item>
139+ <Grid.Item
140+ full
141+ as="input"
142+ type="range"
143+ min="1"
144+ max="100"
145+ value={gasPrice}
146+ onChange={e => setGasPrice(parseInt(e.target.value, 10))}
147+ />
148+ <Grid.Item
149+ full
150+ as={Flex}
151+ row
152+ justify="between"
153+ className="f6 mt1">
154+ <Flex.Item as={Text}>Cheap</Flex.Item>
155+ <Flex.Item as={Text}>Fast</Flex.Item>
156+ </Grid.Item>
157+ <Grid.Item full as={HelpText} className="mt3">
158+ Nonce: {nonce}
159+ </Grid.Item>
160+ <Grid.Item full as={HelpText} className="mt1">
161+ Chain ID: {chainId}
162+ </Grid.Item>
163+ </>
164+ )}
165+ </>
126 )}
166 )}
127
167
128 {showSignedTx && (
168 {showSignedTx && (
src/components/NoticeBox.jsnew file+11
@@ -0,0 +1,11 @@
1+import React from 'react';
2+import cn from 'classnames';
3+import { Flex, Text } from 'indigo-react';
4+
5+export default function NoticeBox({ className, children }) {
6+ return (
7+ <Flex className={cn('bg-gray2 pv3 ph4', className)} align="center">
8+ <Text className="f6 fw-bold gray4">{children}</Text>
9+ </Flex>
10+ );
11+}
src/lib/constants.js+2
@@ -1,6 +1,7 @@
1import { isDevelopment } from './flags';
1import { isDevelopment } from './flags';
2
2
3const CHECK_BLOCK_EVERY_MS = isDevelopment ? 1000 : 5000;
3const CHECK_BLOCK_EVERY_MS = isDevelopment ? 1000 : 5000;
4+const DEFAULT_GAS_PRICE_GWEI = 20;
4
5
5const MIN_GALAXY = 0;
6const MIN_GALAXY = 0;
6const MAX_GALAXY = 255;
7const MAX_GALAXY = 255;
@@ -72,6 +73,7 @@ const PROFILE_STATES = {
72
73
73export {
74export {
74 CHECK_BLOCK_EVERY_MS,
75 CHECK_BLOCK_EVERY_MS,
76+ DEFAULT_GAS_PRICE_GWEI,
75 GAS_LIMITS,
77 GAS_LIMITS,
76 GEN_STATES,
78 GEN_STATES,
77 BUTTON_STATES,
79 BUTTON_STATES,
src/lib/txn.js+12−14
@@ -16,20 +16,18 @@ const RETRY_OPTIONS = {
16 randomize: false,
16 randomize: false,
17};
17};
18
18
19−const signTransaction = async config => {
19+const signTransaction = async ({
20− let {
21− wallet,
20+ wallet,
22− walletType,
21+ walletType,
23− walletHdPath,
22+ walletHdPath,
24− networkType,
23+ networkType,
25− txn,
24+ txn,
26− nonce,
25+ nonce, // number
27− chainId,
26+ chainId, // number
28− gasPrice,
27+ gasPrice, // string
29− gasLimit,
28+ gasLimit, // string | number
30− } = config;
29+}) => {
31−
32− //TODO require these in txn object
30+ // TODO: require these in txn object
33 nonce = toHex(nonce);
31 nonce = toHex(nonce);
34 chainId = toHex(chainId);
32 chainId = toHex(chainId);
35 gasPrice = toHex(toWei(gasPrice, 'gwei'));
33 gasPrice = toHex(toWei(gasPrice, 'gwei'));
src/lib/useEthereumTransaction.js+5−2
@@ -73,7 +73,7 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
73 txn: unsignedTransaction,
73 txn: unsignedTransaction,
74 nonce,
74 nonce,
75 chainId,
75 chainId,
76− gasPrice,
76+ gasPrice: gasPrice.toFixed(0),
77 gasLimit,
77 gasLimit,
78 });
78 });
79
79
@@ -134,7 +134,7 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
134
134
135 setNonce(nonce);
135 setNonce(nonce);
136 setChainId(chainId);
136 setChainId(chainId);
137− setGasPrice(fromWei(estimatedGasPrice, 'gwei'));
137+ setGasPrice(parseInt(fromWei(estimatedGasPrice, 'gwei'), 10));
138 } catch (error) {
138 } catch (error) {
139 setError(error);
139 setError(error);
140 }
140 }
@@ -166,8 +166,11 @@ export default function useEthereumTransaction(initialGasLimit = 0) {
166 confirmed,
166 confirmed,
167 reset,
167 reset,
168 error,
168 error,
169+ gasPrice,
169 setGasPrice,
170 setGasPrice,
170 txHash,
171 txHash,
172+ nonce,
173+ chainId,
171 signedTransaction,
174 signedTransaction,
172 },
175 },
173 };
176 };
src/style/bridge.scss+54
@@ -26,3 +26,57 @@ body {
26#root {
26#root {
27 min-height: 100vh;
27 min-height: 100vh;
28}
28}
29+
30+// range slider
31+
32+input[type='range'] {
33+ overflow: hidden;
34+ -webkit-appearance: none;
35+ background-color: #e6e6e6;
36+
37+ /* Chrome */
38+ &::-webkit-slider-runnable-track {
39+ height: 24px;
40+ -webkit-appearance: none;
41+ background-color: #e6e6e6;
42+ margin-top: -1px;
43+ }
44+
45+ &::-webkit-slider-thumb {
46+ -webkit-appearance: none;
47+ width: 24px;
48+ height: 100%;
49+ background-color: #000;
50+ border: none;
51+ border-radius: 0;
52+ cursor: ew-resize;
53+ }
54+
55+ /* FF */
56+ &::-moz-range-progress {
57+ height: 100%;
58+ background-color: #000;
59+ }
60+
61+ &::-moz-range-track {
62+ background-color: #e6e6e6;
63+ }
64+
65+ &::-moz-range-thumb {
66+ width: 24px;
67+ height: 100%;
68+ background-color: #000;
69+ border: none;
70+ border-radius: 0;
71+ cursor: ew-resize;
72+ }
73+
74+ /* IE */
75+ &::-ms-fill-lower {
76+ background-color: #000;
77+ }
78+
79+ &::-ms-fill-upper {
80+ background-color: #e6e6e6;
81+ }
82+}
src/views/Admin/AdminNetworkingKeys.js+7−7
@@ -6,6 +6,8 @@ import { randomHex } from 'web3-utils';
6
6
7import { usePointCursor } from 'store/pointCursor';
7import { usePointCursor } from 'store/pointCursor';
8import { usePointCache } from 'store/pointCache';
8import { usePointCache } from 'store/pointCache';
9+import { useNetwork } from 'store/network';
10+import { useWallet } from 'store/wallet';
9
11
10import { useLocalRouter } from 'lib/LocalRouter';
12import { useLocalRouter } from 'lib/LocalRouter';
11import * as need from 'lib/need';
13import * as need from 'lib/need';
@@ -15,19 +17,17 @@ import {
15 deriveNetworkKeys,
17 deriveNetworkKeys,
16} from 'lib/keys';
18} from 'lib/keys';
17import { formatDotsWithTime } from 'lib/dateFormat';
19import { formatDotsWithTime } from 'lib/dateFormat';
20+import useEthereumTransaction from 'lib/useEthereumTransaction';
21+import { GAS_LIMITS, ZERO_KEY } from 'lib/constants';
22+import { addHexPrefix } from 'lib/wallet';
18
23
19import ViewHeader from 'components/ViewHeader';
24import ViewHeader from 'components/ViewHeader';
20import MiniBackButton from 'components/MiniBackButton';
25import MiniBackButton from 'components/MiniBackButton';
21import { BootArvoButton, ForwardButton } from 'components/Buttons';
26import { BootArvoButton, ForwardButton } from 'components/Buttons';
22import FooterButton from 'components/FooterButton';
27import FooterButton from 'components/FooterButton';
23−import WarningBox from 'components/WarningBox';
24import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
28import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
25−import useEthereumTransaction from 'lib/useEthereumTransaction';
26−import { GAS_LIMITS, ZERO_KEY } from 'lib/constants';
27import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
28−import { addHexPrefix } from 'lib/wallet';
30+import NoticeBox from 'components/NoticeBox';
29−import { useNetwork } from 'store/network';
30−import { useWallet } from 'store/wallet';
31
31
32const CRYPTO_SUITE_VERSION = 1;
32const CRYPTO_SUITE_VERSION = 1;
33
33
@@ -290,7 +290,7 @@ export default function AdminNetworkingKeys() {
290 )}
290 )}
291
291
292 {confirmed && (
292 {confirmed && (
293− <Grid.Item full as={WarningBox} className="mb3">
293+ <Grid.Item full as={NoticeBox} className="mb3">
294 You need this keyfile to authenticate with Arvo.
294 You need this keyfile to authenticate with Arvo.
295 </Grid.Item>
295 </Grid.Item>
296 )}
296 )}
src/views/Invite/InviteEmail.js+6−4
@@ -32,7 +32,7 @@ import * as tank from 'lib/tank';
32import { useLocalRouter } from 'lib/LocalRouter';
32import { useLocalRouter } from 'lib/LocalRouter';
33import useArray from 'lib/useArray';
33import useArray from 'lib/useArray';
34import { buildEmailInputConfig } from 'lib/useInputs';
34import { buildEmailInputConfig } from 'lib/useInputs';
35−import { MIN_PLANET, GAS_LIMITS } from 'lib/constants';
35+import { MIN_PLANET, GAS_LIMITS, DEFAULT_GAS_PRICE_GWEI } from 'lib/constants';
36import * as need from 'lib/need';
36import * as need from 'lib/need';
37import * as wg from 'lib/walletgen';
37import * as wg from 'lib/walletgen';
38import useSetState from 'lib/useSetState';
38import useSetState from 'lib/useSetState';
@@ -43,9 +43,11 @@ import MiniBackButton from 'components/MiniBackButton';
43import LoadableButton from 'components/LoadableButton';
43import LoadableButton from 'components/LoadableButton';
44import Highlighted from 'components/Highlighted';
44import Highlighted from 'components/Highlighted';
45
45
46−const GAS_PRICE_GWEI = 20; // we pay the premium for faster ux
47const GAS_LIMIT = GAS_LIMITS.GIFT_PLANET;
46const GAS_LIMIT = GAS_LIMITS.GIFT_PLANET;
48−const INVITE_COST = toWei((GAS_PRICE_GWEI * GAS_LIMIT).toString(), 'gwei');
47+const INVITE_COST = toWei(
48+ (DEFAULT_GAS_PRICE_GWEI * GAS_LIMIT).toString(),
49+ 'gwei'
50+);
49const HAS_RECEIVED_TEXT = 'This email has already received an invite.';
51const HAS_RECEIVED_TEXT = 'This email has already received an invite.';
50
52
51const STATUS = {
53const STATUS = {
@@ -252,7 +254,7 @@ export default function InviteEmail() {
252 networkType,
254 networkType,
253 // TODO: ^ make a useTransactionSigner to encapsulate this logic
255 // TODO: ^ make a useTransactionSigner to encapsulate this logic
254 txn: inviteTx,
256 txn: inviteTx,
255− gasPrice: GAS_PRICE_GWEI.toString(),
257+ gasPrice: DEFAULT_GAS_PRICE_GWEI.toString(),
256 gasLimit: GAS_LIMIT.toString(),
258 gasLimit: GAS_LIMIT.toString(),
257 nonce: nonce + i,
259 nonce: nonce + i,
258 chainId,
260 chainId,