on 8ff3bf1 help sign in
bridge/src/components/InlineEthereumTransaction.js
240 lines 7.0 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 HelpText,
12} from 'indigo-react';
13import { fromWei } from 'web3-utils';
15import { useExploreTxUrl } from 'lib/explorer';
16import { hexify } from 'lib/txn';
18import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
19import WarningBox from './WarningBox';
20import { composeValidator, buildCheckboxValidator } from 'form/validators';
21import BridgeForm from 'form/BridgeForm';
22import Condition from 'form/Condition';
24export default function InlineEthereumTransaction({
25 // from useEthereumTransaction.bind
26 initializing,
27 canSign,
28 generateAndSign,
29 signed,
30 broadcast,
31 broadcasted,
32 confirmed,
33 completed,
34 reset,
35 error,
36 gasPrice,
37 setGasPrice,
38 resetGasPrice,
39 txHash,
40 nonce,
41 chainId,
42 needFunds,
43 signedTransaction,
45 // additional from parent
46 label = 'Generate & Sign Transaction',
47 className,
48 onReturn,
49}) {
50 // show receipt after successful broadcast
51 const showReceipt = broadcasted || confirmed || completed;
52 // show configure controls pre-broadcast
53 const showConfigureInput = !(signed || broadcasted || confirmed || completed);
54 // show the send/loading button while signed, broadcasting, or confirme
55 const showBroadcastButton = signed || broadcasted || confirmed;
56 const canBroadcast = signed && !needFunds;
57 const isLoading = broadcasted || confirmed;
58 // show signed tx only when signing (for offline usage)
59 const showSignedTx = signed;
61 const exploreTxUrl = useExploreTxUrl(txHash);
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 renderPrimaryButton = () => {
82 if (error) {
83 return (
84 <Grid.Item full as={RestartButton} solid onClick={() => reset()}>
85 Reset Transaction
86 </Grid.Item>
87 );
88 } else if (completed) {
89 return (
90 <>
91 <Grid.Divider />
92 <Grid.Item full as={RestartButton} onClick={onReturn}>
93 Return
94 </Grid.Item>
95 </>
96 );
97 } else if (showBroadcastButton) {
98 return (
99 <Grid.Item
100 full
101 as={ForwardButton}
102 solid
103 success
104 disabled={!canBroadcast}
105 loading={isLoading}
106 onClick={() => broadcast()}>
107 Send Transaction
108 </Grid.Item>
109 );
110 } else {
111 return (
112 <Grid.Item
113 full
114 as={GenerateButton}
115 onClick={generateAndSign}
116 disabled={!canSign}
117 loading={!canSign && initializing}>
118 {label}
119 </Grid.Item>
120 );
121 }
122 };
124 return (
125 <Grid className={cn(className, 'mt1')}>
126 <BridgeForm validate={validate} onValues={onValues}>
127 {({ handleSubmit }) => (
128 <>
129 {renderPrimaryButton()}
131 {error && (
132 <Grid.Item full as={ErrorText} className="mt1">
133 {error.message}
134 </Grid.Item>
135 )}
137 {needFunds && (
138 <Grid.Item full as={WarningBox} className="mt3">
139 The address {needFunds.address} needs at least{' '}
140 {fromWei(needFunds.minBalance)} ETH and currently has{' '}
141 {fromWei(needFunds.balance)} ETH. Waiting until the account has
142 enough funds.
143 </Grid.Item>
144 )}
146 {showConfigureInput && (
147 <>
148 <Grid.Item
149 full
150 as={ToggleInput}
151 name="useAdvanced"
152 label="Advanced Configuration"
153 inverseLabel="Cancel Advanced Configuration"
154 disabled={!showConfigureInput || initializing}
155 />
157 <Condition when="useAdvanced" is={true}>
158 <Grid.Item
159 full
160 as={Flex}
161 row
162 justify="between"
163 className="mt2">
164 <Flex.Item as={H5}>Gas Price</Flex.Item>
165 <Flex.Item as={H5}>{gasPrice} Gwei</Flex.Item>
166 </Grid.Item>
167 {/* TODO(shrugs): move to indigo/RangeInput */}
168 <Grid.Item
169 full
170 as="input"
171 type="range"
172 min="1"
173 max="100"
174 value={gasPrice}
175 onChange={e => setGasPrice(parseInt(e.target.value, 10))}
176 />
177 <Grid.Item
178 full
179 as={Flex}
180 row
181 justify="between"
182 className="f6 mt1">
183 <Flex.Item as={Text}>Cheap</Flex.Item>
184 <Flex.Item as={Text}>Fast</Flex.Item>
185 </Grid.Item>
186 <Grid.Item full as={HelpText} className="mt3">
187 Nonce: {nonce}
188 </Grid.Item>
189 <Grid.Item full as={HelpText} className="mt1">
190 Chain ID: {chainId}
191 </Grid.Item>
192 <Grid.Divider className="mt3" />
193 </Condition>
194 </>
195 )}
197 {showSignedTx && (
198 <>
199 <Grid.Item
200 full
201 as={ToggleInput}
202 name="viewSigned"
203 label="View Signed Transaction"
204 inverseLabel="Hide Signed Transaction"
205 disabled={!showSignedTx}
206 />
207 <Condition when="viewSigned" is={true}>
208 <Grid.Item full as="code" className="f6 mono gray4 wrap">
209 {hexify(signedTransaction.serialize())}
210 </Grid.Item>
211 </Condition>
212 </>
213 )}
215 {showReceipt && (
216 <>
217 <Grid.Divider />
218 <Grid.Item full as={Flex} col className="pv4">
219 <Flex.Item as={Flex} row justify="between">
220 <Flex.Item as={H5}>Transaction Hash</Flex.Item>
221 <Flex.Item as={LinkButton} href={exploreTxUrl}>
222 Etherscan↗
223 </Flex.Item>
224 </Flex.Item>
225 <Flex.Item as={Flex}>
226 <Flex.Item flex as="code" className="f6 mono gray4 wrap">
227 {txHash}
228 </Flex.Item>
229 <Flex.Item flex />
230 </Flex.Item>
231 </Grid.Item>
232 <Grid.Divider />
233 </>
234 )}
235 </>
236 )}
237 </BridgeForm>
238 </Grid>
239 );