on 79bacf2 help sign in
bridge/src/components/InlineEthereumTransaction.js
288 lines 8.5 kB history raw
1import React, { useMemo, useCallback } from 'react';
2import cn from 'classnames';
3import {
4 Grid,
5 ToggleInput,
6 ErrorText,
7 Flex,
8 LinkButton,
9 H5,
10 Text,
11} from 'indigo-react';
12import { fromWei } from 'web3-utils';
14import { useExploreTxUrl } from 'lib/explorer';
15import { hexify } from 'lib/txn';
17import { composeValidator, buildCheckboxValidator } from 'form/validators';
18import BridgeForm from 'form/BridgeForm';
19import Condition from 'form/Condition';
21import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
22import WarningBox from './WarningBox';
23import CopyButton from './CopyButton';
24import ProgressButton from './ProgressButton';
26export default function InlineEthereumTransaction({
27 // from useEthereumTransaction.bind
28 initializing,
29 canSign,
30 generateAndSign,
31 signed,
32 broadcast,
33 broadcasted,
34 confirmed,
35 completed,
36 reset,
37 error,
38 gasPrice,
39 setGasPrice,
40 resetGasPrice,
41 txHash,
42 nonce,
43 chainId,
44 needFunds,
45 signedTransaction,
46 confirmationProgress,
48 // additional from parent
49 label = 'Generate & Sign Transaction',
50 className,
51 onReturn,
52}) {
53 // show receipt after successful broadcast
54 const showReceipt = broadcasted || confirmed || completed;
55 // show configure controls pre-broadcast
56 const showConfigureInput = !(signed || broadcasted || confirmed || completed);
57 // show the send/loading button while signed, broadcasting, or confirme
58 const showBroadcastButton = signed;
59 const showLoadingButton = broadcasted || confirmed;
60 const canBroadcast = signed && !needFunds;
61 // show signed tx only when signing (for offline usage)
62 const showSignedTx = signed;
64 const exploreTxUrl = useExploreTxUrl(txHash);
66 const validate = useMemo(
67 () =>
68 composeValidator({
69 useAdvanced: buildCheckboxValidator(),
70 viewSigned: buildCheckboxValidator(),
71 }),
72 []
73 );
75 const onValues = useCallback(
76 ({ valid, values, form }) => {
77 if (!values.useAdvanced) {
78 resetGasPrice();
79 }
80 },
81 [resetGasPrice]
82 );
84 const renderPrimarySection = () => {
85 if (error) {
86 return (
87 <Grid.Item full as={RestartButton} solid onClick={() => reset()}>
88 Reset Transaction
89 </Grid.Item>
90 );
91 } else if (completed) {
92 return (
93 <Grid.Item full className="pv4 black f5">
94 Transaction Complete
95 </Grid.Item>
96 );
97 } else if (showBroadcastButton) {
98 return (
99 <Grid.Item
100 full
101 as={ForwardButton}
102 solid
103 success
104 disabled={!canBroadcast}
105 onClick={() => broadcast()}>
106 Send Transaction
107 </Grid.Item>
108 );
109 } else if (showLoadingButton) {
110 return (
111 <Grid.Item
112 full
113 as={ProgressButton}
114 success
115 disabled
116 progress={confirmationProgress}>
117 Sending Transaction
118 </Grid.Item>
119 );
120 } else {
121 return (
122 <Grid.Item
123 full
124 as={GenerateButton}
125 onClick={generateAndSign}
126 disabled={!canSign}
127 loading={!canSign && initializing}>
128 {label}
129 </Grid.Item>
130 );
131 }
132 };
134 const serializedTxHex = useMemo(
135 () => signedTransaction && hexify(signedTransaction.serialize()),
136 [signedTransaction]
137 );
139 return (
140 <Grid className={cn(className, 'mt1')}>
141 <BridgeForm validate={validate} onValues={onValues}>
142 {({ handleSubmit }) => (
143 <>
144 {renderPrimarySection()}
146 {error && (
147 <Grid.Item full as={ErrorText} className="mt1">
148 {error.message}
149 </Grid.Item>
150 )}
152 {needFunds && (
153 <Grid.Item full as={WarningBox} className="mt3">
154 The address {needFunds.address} needs at least{' '}
155 {fromWei(needFunds.minBalance)} ETH and currently has{' '}
156 {fromWei(needFunds.balance)} ETH. Waiting until the account has
157 enough funds.
158 </Grid.Item>
159 )}
161 {showConfigureInput && (
162 <>
163 <Grid.Item
164 full
165 as={ToggleInput}
166 name="useAdvanced"
167 label="Advanced"
168 inverseLabel="Back to Defaults"
169 inverseColor="red3"
170 disabled={!showConfigureInput || initializing}
171 />
173 <Condition when="useAdvanced" is={true}>
174 <Grid.Divider />
175 <Grid.Item
176 full
177 as={Flex}
178 row
179 justify="between"
180 className="mt2">
181 <Flex.Item as={H5}>Gas Price</Flex.Item>
182 <Flex.Item as={H5}>{gasPrice} Gwei</Flex.Item>
183 </Grid.Item>
184 {/* TODO(shrugs): move to indigo/RangeInput */}
185 <Grid.Item
186 full
187 as="input"
188 type="range"
189 min="1"
190 max="100"
191 value={gasPrice}
192 onChange={e => setGasPrice(parseInt(e.target.value, 10))}
193 />
194 <Grid.Item
195 full
196 as={Flex}
197 row
198 justify="between"
199 className="f6 mt1">
200 <Flex.Item as={Text}>Cheap</Flex.Item>
201 <Flex.Item as={Text}>Fast</Flex.Item>
202 </Grid.Item>
203 <Grid.Divider className="mt4" />
204 </Condition>
205 </>
206 )}
208 {showSignedTx && (
209 <>
210 <Grid.Item
211 full
212 as={ToggleInput}
213 name="viewSigned"
214 label="Signed Transaction"
215 inverseLabel="Hide"
216 disabled={!showSignedTx}
217 />
218 <Condition when="viewSigned" is={true}>
219 <Grid.Divider />
220 <Grid.Item
221 full
222 as={Flex}
223 justify="between"
224 className="pv4 black f5">
225 <Flex.Item>Nonce</Flex.Item>
226 <Flex.Item>{nonce}</Flex.Item>
227 </Grid.Item>
228 <Grid.Divider />
229 <Grid.Item
230 full
231 as={Flex}
232 justify="between"
233 className="pv4 black f5">
234 <Flex.Item>Gas Price</Flex.Item>
235 <Flex.Item>{gasPrice.toFixed()} Gwei</Flex.Item>
236 </Grid.Item>
237 <Grid.Divider />
238 <Grid.Item
239 full
240 as={Flex}
241 justify="between"
242 className="mt3 mb2">
243 <Flex.Item as={H5}>Signed Transaction Hex</Flex.Item>
244 <Flex.Item as={CopyButton} text={serializedTxHex} />
245 </Grid.Item>
246 <Grid.Item full as="code" className="mb4 f6 mono gray4 wrap">
247 {serializedTxHex}
248 </Grid.Item>
249 <Grid.Divider />
250 </Condition>
251 </>
252 )}
254 {showReceipt && (
255 <>
256 <Grid.Divider />
257 <Grid.Item full as={Flex} col className="pv4">
258 <Flex.Item as={Flex} row justify="between">
259 <Flex.Item as={H5}>Transaction Hash</Flex.Item>
260 <Flex.Item as={LinkButton} href={exploreTxUrl}>
261 Etherscan↗
262 </Flex.Item>
263 </Flex.Item>
264 <Flex.Item as={Flex}>
265 <Flex.Item flex as="code" className="f6 mono gray4 wrap">
266 {txHash}
267 </Flex.Item>
268 <Flex.Item flex />
269 </Flex.Item>
270 </Grid.Item>
271 <Grid.Divider />
272 </>
273 )}
275 {completed && (
276 <>
277 <Grid.Item full as={RestartButton} onClick={onReturn}>
278 Return
279 </Grid.Item>
280 <Grid.Divider />
281 </>
282 )}
283 </>
284 )}
285 </BridgeForm>
286 </Grid>
287 );