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