1import React, { useMemo, useCallback, useState } from 'react';
2import cn from 'classnames';
13import { toBN } from 'web3-utils';
15import { ReactComponent as InfoIcon } from 'assets/info.svg';
17import { useExploreTxUrls } from 'lib/explorer';
18import { hexify } from 'lib/txn';
19import pluralize from 'lib/pluralize';
20import { safeFromWei, safeToWei } from 'lib/lib';
22import { composeValidator, buildCheckboxValidator } from 'form/validators';
23import BridgeForm from 'form/BridgeForm';
24import Condition from 'form/Condition';
26import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
27import CopyButton from './CopyButton';
28import ProgressButton from './ProgressButton';
29import convertToInt from 'lib/convertToInt';
30import NeedFundsNotice from './NeedFundsNotice';
32export default function InlineEthereumTransaction({
33 // from useEthereumTransaction.bind
56 // additional from parent
57 label = 'Generate & Sign Transaction',
61 // show receipt after successful broadcast
62 const [showReceipt, setShowReceipt] = useState(false);
63 const toggleShowReceipt = useCallback(() => setShowReceipt(!showReceipt), [
67 // show configure controls pre-broadcast
68 const showConfigureInput = !(signed || broadcasted || confirmed || completed);
69 // show the send/loading button while signed, broadcasting, or confirme
70 const showBroadcastButton = signed;
71 const showLoadingButton = broadcasted || confirmed;
72 const canBroadcast = signed && !needFunds;
73 // show signed tx only when signing (for offline usage)
74 const showSignedTx = signed;
76 const [showGasDetails, _setShowGasDetails] = useState(false);
77 const toggleGasDetails = useCallback(
78 () => _setShowGasDetails(!showGasDetails),
79 [_setShowGasDetails, showGasDetails]
82 const validate = useMemo(
85 useAdvanced: buildCheckboxValidator(),
86 viewSigned: buildCheckboxValidator(),
91 const onValues = useCallback(
92 ({ valid, values, form }) => {
93 if (!values.useAdvanced) {
100 const renderPrimarySection = () => {
103 <Grid.Item full as={RestartButton} solid onClick={() => reset()}>
107 } else if (completed) {
109 } else if (showBroadcastButton) {
116 disabled={!canBroadcast}
117 onClick={() => broadcast()}>
121 } else if (showLoadingButton) {
128 progress={confirmationProgress}>
137 onClick={generateAndSign}
139 loading={!canSign && initializing}>
146 const serializedTxsHex = useMemo(
148 signedTransactions &&
149 signedTransactions.map(stx => hexify(stx.serialize())),
153 const numTxs = useMemo(() => (unsignedTransactions || []).length || 1, [
154 unsignedTransactions,
156 const maxCost = useMemo(
166 [gasLimit, gasPrice, numTxs]
169 const gasInfo = useMemo(() => {
170 const extra = numTxs === 1 ? '' : `* ${numTxs} TXN`;
171 return showGasDetails
172 ? `${gasPrice} Gwei * ${gasLimit} ${extra} = ${maxCost} ETH`
174 }, [showGasDetails, maxCost, gasPrice, gasLimit, numTxs]);
177 <Grid className={cn(className, 'mt1')}>
178 <BridgeForm validate={validate} onValues={onValues}>
181 {renderPrimarySection()}
184 <Grid.Item full as={ErrorText} className="mv1">
198 {showConfigureInput && (
205 inverseLabel="Back to Defaults"
207 disabled={!showConfigureInput || initializing}
210 <Condition when="useAdvanced" is={true}>
211 <Grid.Item full className="mb2"></Grid.Item>
219 <Flex.Item as={H5}>Gas Price</Flex.Item>
225 onClick={toggleGasDetails}
230 {/* TODO(shrugs): move to indigo/RangeInput */}
239 setGasPrice(convertToInt(e.target.value, 10))
248 <Flex.Item as={Text}>Cheap</Flex.Item>
249 <Flex.Item as={Text}>Fast</Flex.Item>
251 <Grid.Divider className="mt4" />
262 label="Signed Transaction"
264 disabled={!showSignedTx}
266 <Condition when="viewSigned" is={true}>
267 <SignedTransactionList
268 serializedTxsHex={serializedTxsHex}
278 <Grid.Item full as={RestartButton} onClick={onReturn}>
286 onClose={toggleShowReceipt}
292 className="underline mv2 pointer"
294 onClick={toggleShowReceipt}>
307function SignedTransactionList({ serializedTxsHex, nonce, gasPrice }) {
308 return serializedTxsHex.map((serializedTxHex, i) => (
309 <React.Fragment key="i">
311 <Grid.Item full as={Flex} justify="between" className="pv4 black f5">
312 <Flex.Item>Nonce</Flex.Item>
313 <Flex.Item>{nonce + i}</Flex.Item>
316 <Grid.Item full as={Flex} justify="between" className="pv4 black f5">
317 <Flex.Item>Gas Price</Flex.Item>
318 <Flex.Item>{gasPrice.toFixed()} Gwei</Flex.Item>
321 <Grid.Item full as={Flex} justify="between" className="mt3 mb2">
322 <Flex.Item as={H5}>Signed Transaction Hex</Flex.Item>
323 <Flex.Item as={CopyButton} text={serializedTxHex} />
325 <Grid.Item full as="code" className="mb4 f6 mono gray4 wrap">
333function TransactionReceipt({ txHashes, maxCost, onClose }) {
334 const txUrls = useExploreTxUrls(txHashes);
337 <Grid.Item full as={Flex} justify="between" className="pv2 black f5">
338 <Flex.Item>Receipt</Flex.Item>
339 <Flex.Item onClick={onClose} className="underline pointer">
343 <Grid.Item full as={Flex} justify="between" className="pv2 black f5">
344 <Flex.Item>Gas Price</Flex.Item>
345 <Flex.Item className="mono">{maxCost} ETH</Flex.Item>
348 <Grid.Item full as={Flex} col className="pv4">
349 <Flex.Item as={H5}>Receipt</Flex.Item>
352 txHashes.map((txHash, i) => (
353 <Flex.Item as={Flex} className="mv3">
359 className="f6 mono gray4 wrap ">
362 <Flex.Item className="ml8" as={LinkButton} href={txUrls[i]}>
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list