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