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