on 685bb75 help sign in
bridge/src/components/InlineEthereumTransaction.js
277 lines 7.2 kB history raw
1import React, { useMemo, useCallback, useState } from 'react';
2import cn from 'classnames';
3import { Grid, ErrorText, Flex, LinkButton, H5 } from 'indigo-react';
4import { toBN } from 'web3-utils';
6import { useExploreTxUrls } from 'lib/explorer';
7import { safeFromWei, safeToWei } from 'lib/lib';
9import { composeValidator, buildCheckboxValidator } from 'form/validators';
10import BridgeForm from 'form/BridgeForm';
12import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
13import ProgressButton from './ProgressButton';
14import NeedFundsNotice from './NeedFundsNotice';
16import './InlineEthereumTransaction.scss';
17import FeeDropdown from './L2/Dropdowns/FeeDropdown';
19export default function InlineEthereumTransaction({
20 // from useEthereumTransaction.bind
21 initializing,
22 canSign,
23 generateAndSign,
24 signed,
25 fakeSigned,
26 broadcast,
27 broadcasted,
28 confirmed,
29 completed,
30 reset,
31 error,
32 gasPrice,
33 setGasPrice,
34 resetGasPrice,
35 txHashes,
36 needFunds,
37 confirmationProgress,
38 gasLimit,
39 unsignedTransactions,
40 finalCost,
42 // additional from parent
43 label = 'Generate & Sign Transaction',
44 className,
45 onReturn,
46}) {
47 // show receipt after successful broadcast
48 const [showReceipt, setShowReceipt] = useState(false);
49 const toggleShowReceipt = useCallback(() => setShowReceipt(!showReceipt), [
50 setShowReceipt,
51 showReceipt,
52 ]);
53 // show configure controls pre-broadcast
54 const showConfigureInput = !(signed || broadcasted || confirmed || completed);
55 // show the send/loading button while signed, broadcasting, or confirme
56 const showBroadcastButton = signed;
57 const showLoadingButton = broadcasted || confirmed;
58 const canBroadcast = signed && !needFunds;
59 // show signed tx only when signing (for offline usage)
61 const validate = useMemo(
62 () =>
63 composeValidator({
64 useAdvanced: buildCheckboxValidator(),
65 viewSigned: buildCheckboxValidator(),
66 }),
67 []
68 );
70 const onValues = useCallback(
71 ({ valid, values, form }) => {
72 if (!values.useAdvanced) {
73 resetGasPrice();
74 }
75 },
76 [resetGasPrice]
77 );
79 const renderPrimarySection = () => {
80 if (error) {
81 return (
82 <Grid.Item
83 className="eth-tx-button"
84 full
85 as={RestartButton}
86 solid
87 onClick={() => reset()}>
88 Reset Transaction
89 </Grid.Item>
90 );
91 } else if (completed) {
92 return (
93 <>
94 <Grid.Divider />
95 <Grid.Item
96 className="eth-tx-button"
97 full
98 as={RestartButton}
99 onClick={onReturn}>
100 Return
101 </Grid.Item>
102 <Grid.Divider />
103 {showReceipt && (
104 <TransactionReceipt
105 txHashes={txHashes}
106 finalCost={finalCost}
107 onClose={toggleShowReceipt}
108 />
109 )}
111 {!showReceipt && (
112 <Grid.Item
113 className="underline mv2 pointer"
114 full
115 onClick={toggleShowReceipt}>
116 View Receipt
117 </Grid.Item>
118 )}
119 </>
120 );
121 } else if (showBroadcastButton) {
122 return (
123 <Grid.Item
124 className="eth-tx-button"
125 full
126 as={ForwardButton}
127 solid
128 success
129 disabled={!canBroadcast}
130 onClick={() => broadcast()}>
131 Send Transaction
132 </Grid.Item>
133 );
134 } else if (showLoadingButton) {
135 return (
136 <Grid.Item
137 className="eth-tx-button"
138 full
139 as={ProgressButton}
140 success
141 disabled
142 progress={confirmationProgress}>
143 Sending Transaction
144 </Grid.Item>
145 );
146 } else {
147 return (
148 <Grid.Item
149 className="eth-tx-button"
150 full
151 as={GenerateButton}
152 onClick={generateAndSign}
153 disabled={!canSign}
154 loading={!canSign && initializing}>
155 {label}
156 </Grid.Item>
157 );
158 }
159 };
161 const numTxs = useMemo(() => (unsignedTransactions || []).length || 1, [
162 unsignedTransactions,
163 ]);
164 const maxCost = useMemo(
165 () =>
166 safeFromWei(
167 safeToWei(
168 toBN(gasLimit)
169 .mul(toBN(gasPrice))
170 .mul(toBN(numTxs)),
171 'gwei'
172 ),
173 'ether'
174 ),
175 [gasLimit, gasPrice, numTxs]
176 );
178 return (
179 <Grid className={cn(className, 'mt1')}>
180 <BridgeForm validate={validate} onValues={onValues}>
181 {() => (
182 <>
183 {showConfigureInput && (
184 <>
185 <Grid.Item
186 className="mt2 text eth-tx-button"
187 full
188 as={Flex}
189 row
190 justify="between">
191 <Flex.Item as={H5}>Gas Fee</Flex.Item>
192 <FeeDropdown setGasPrice={setGasPrice} />
193 </Grid.Item>
195 <Grid.Item
196 className="mt2 text eth-tx-button"
197 full
198 as={Flex}
199 row
200 justify="between">
201 <Flex.Item as={H5}>Max Transaction Cost</Flex.Item>
202 <Flex.Item as={H5}>{maxCost} ETH</Flex.Item>
203 </Grid.Item>
204 <Grid.Divider className="mt4" />
205 </>
206 )}
208 {renderPrimarySection()}
210 {error && (
211 <Grid.Item className="mv1 eth-tx-button" full as={ErrorText}>
212 {error.message}
213 </Grid.Item>
214 )}
216 {needFunds && (
217 <Grid.Item
218 className="mt3 eth-tx-button"
219 full
220 as={NeedFundsNotice}
221 {...needFunds}
222 />
223 )}
224 </>
225 )}
226 </BridgeForm>
227 </Grid>
228 );
231function TransactionReceipt({ txHashes, finalCost, onClose }) {
232 const txUrls = useExploreTxUrls(txHashes);
233 return (
234 <>
235 <Grid.Item
236 className="pv2 black f5 eth-tx-button"
237 full
238 as={Flex}
239 justify="between">
240 <Flex.Item>Receipt</Flex.Item>
241 <Flex.Item onClick={onClose} className="underline pointer">
242 Close
243 </Flex.Item>
244 </Grid.Item>
245 <Grid.Item
246 className="pv2 black f5 eth-tx-button"
247 full
248 as={Flex}
249 justify="between">
250 <Flex.Item>Transaction Cost</Flex.Item>
251 <Flex.Item className="mono">{finalCost} ETH</Flex.Item>
252 </Grid.Item>
253 <Grid.Divider />
254 <Grid.Item className="pv4 eth-tx-button" full as={Flex} col>
255 <Flex.Item as={H5}>Receipt</Flex.Item>
257 {txHashes &&
258 txHashes.map((txHash, i) => (
259 <Flex.Item as={Flex} className="mv3">
260 <>
261 <Flex.Item
262 key={i}
263 flex
264 as="code"
265 className="f6 mono gray4 wrap ">
266 {txHash}
267 </Flex.Item>
268 <Flex.Item className="ml8" as={LinkButton} href={txUrls[i]}>
269 Etherscan↗
270 </Flex.Item>
271 </>
272 </Flex.Item>
273 ))}
274 </Grid.Item>
275 </>
276 );