on 01a3773 help sign in
bridge/src/components/InlineEthereumTransaction.js
287 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 disabled={true}
115 progress={confirmationProgress}>
116 Sending Transaction
117 </Grid.Item>
118 );
119 } else {
120 return (
121 <Grid.Item
122 full
123 as={GenerateButton}
124 onClick={generateAndSign}
125 disabled={!canSign}
126 loading={!canSign && initializing}>
127 {label}
128 </Grid.Item>
129 );
130 }
131 };
133 const serializedTxHex = useMemo(
134 () => signedTransaction && hexify(signedTransaction.serialize()),
135 [signedTransaction]
136 );
138 return (
139 <Grid className={cn(className, 'mt1')}>
140 <BridgeForm validate={validate} onValues={onValues}>
141 {({ handleSubmit }) => (
142 <>
143 {renderPrimarySection()}
145 {error && (
146 <Grid.Item full as={ErrorText} className="mt1">
147 {error.message}
148 </Grid.Item>
149 )}
151 {needFunds && (
152 <Grid.Item full as={WarningBox} className="mt3">
153 The address {needFunds.address} needs at least{' '}
154 {fromWei(needFunds.minBalance)} ETH and currently has{' '}
155 {fromWei(needFunds.balance)} ETH. Waiting until the account has
156 enough funds.
157 </Grid.Item>
158 )}
160 {showConfigureInput && (
161 <>
162 <Grid.Item
163 full
164 as={ToggleInput}
165 name="useAdvanced"
166 label="Advanced"
167 inverseLabel="Back to Defaults"
168 inverseColor="red3"
169 disabled={!showConfigureInput || initializing}
170 />
172 <Condition when="useAdvanced" is={true}>
173 <Grid.Divider />
174 <Grid.Item
175 full
176 as={Flex}
177 row
178 justify="between"
179 className="mt2">
180 <Flex.Item as={H5}>Gas Price</Flex.Item>
181 <Flex.Item as={H5}>{gasPrice} Gwei</Flex.Item>
182 </Grid.Item>
183 {/* TODO(shrugs): move to indigo/RangeInput */}
184 <Grid.Item
185 full
186 as="input"
187 type="range"
188 min="1"
189 max="100"
190 value={gasPrice}
191 onChange={e => setGasPrice(parseInt(e.target.value, 10))}
192 />
193 <Grid.Item
194 full
195 as={Flex}
196 row
197 justify="between"
198 className="f6 mt1">
199 <Flex.Item as={Text}>Cheap</Flex.Item>
200 <Flex.Item as={Text}>Fast</Flex.Item>
201 </Grid.Item>
202 <Grid.Divider className="mt4" />
203 </Condition>
204 </>
205 )}
207 {showSignedTx && (
208 <>
209 <Grid.Item
210 full
211 as={ToggleInput}
212 name="viewSigned"
213 label="Signed Transaction"
214 inverseLabel="Hide"
215 disabled={!showSignedTx}
216 />
217 <Condition when="viewSigned" is={true}>
218 <Grid.Divider />
219 <Grid.Item
220 full
221 as={Flex}
222 justify="between"
223 className="pv4 black f5">
224 <Flex.Item>Nonce</Flex.Item>
225 <Flex.Item>{nonce}</Flex.Item>
226 </Grid.Item>
227 <Grid.Divider />
228 <Grid.Item
229 full
230 as={Flex}
231 justify="between"
232 className="pv4 black f5">
233 <Flex.Item>Gas Price</Flex.Item>
234 <Flex.Item>{gasPrice.toFixed()} Gwei</Flex.Item>
235 </Grid.Item>
236 <Grid.Divider />
237 <Grid.Item
238 full
239 as={Flex}
240 justify="between"
241 className="mt3 mb2">
242 <Flex.Item as={H5}>Signed Transaction Hex</Flex.Item>
243 <Flex.Item as={CopyButton} text={serializedTxHex} />
244 </Grid.Item>
245 <Grid.Item full as="code" className="mb4 f6 mono gray4 wrap">
246 {serializedTxHex}
247 </Grid.Item>
248 <Grid.Divider />
249 </Condition>
250 </>
251 )}
253 {showReceipt && (
254 <>
255 <Grid.Divider />
256 <Grid.Item full as={Flex} col className="pv4">
257 <Flex.Item as={Flex} row justify="between">
258 <Flex.Item as={H5}>Transaction Hash</Flex.Item>
259 <Flex.Item as={LinkButton} href={exploreTxUrl}>
260 Etherscan↗
261 </Flex.Item>
262 </Flex.Item>
263 <Flex.Item as={Flex}>
264 <Flex.Item flex as="code" className="f6 mono gray4 wrap">
265 {txHash}
266 </Flex.Item>
267 <Flex.Item flex />
268 </Flex.Item>
269 </Grid.Item>
270 <Grid.Divider />
271 </>
272 )}
274 {completed && (
275 <>
276 <Grid.Item full as={RestartButton} onClick={onReturn}>
277 Return
278 </Grid.Item>
279 <Grid.Divider />
280 </>
281 )}
282 </>
283 )}
284 </BridgeForm>
285 </Grid>
286 );