on 555fac9 help sign in
bridge/src/components/InlineEthereumTransaction.js
290 lines 8.4 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';
13import { useExploreTxUrl } from 'lib/explorer';
14import { hexify } from 'lib/txn';
16import { composeValidator, buildCheckboxValidator } from 'form/validators';
17import BridgeForm from 'form/BridgeForm';
18import Condition from 'form/Condition';
20import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
21import CopyButton from './CopyButton';
22import ProgressButton from './ProgressButton';
23import convertToInt from 'lib/convertToInt';
24import NeedFundsNotice from './NeedFundsNotice';
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 {() => (
143 <>
144 {renderPrimarySection()}
146 {error && (
147 <Grid.Item full as={ErrorText} className="mv1">
148 {error.message}
149 </Grid.Item>
150 )}
152 {needFunds && (
153 <Grid.Item
154 full
155 as={NeedFundsNotice}
156 className="mt3"
157 {...needFunds}
158 />
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 =>
193 setGasPrice(convertToInt(e.target.value, 10))
194 }
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 );