1import React, { useMemo, useCallback, useState } from 'react';
2import cn from 'classnames';
12import { toBN } from 'web3-utils';
14import { useExploreTxUrls } from 'lib/explorer';
15import { hexify } from 'lib/txn';
16import { safeFromWei, safeToWei } from 'lib/lib';
18import { composeValidator, buildCheckboxValidator } from 'form/validators';
19import BridgeForm from 'form/BridgeForm';
20import Condition from 'form/Condition';
22import { GenerateButton, ForwardButton, RestartButton } from './Buttons';
23import ProgressButton from './ProgressButton';
24import NeedFundsNotice from './NeedFundsNotice';
25import NoticeBox from './NoticeBox';
26import FeeDropdown from './L2/Dropdowns/FeeDropdown';
27import CopyButton from './copiable/CopyButton';
29import './InlineEthereumTransaction.scss';
30import { useRollerStore } from 'store/rollerStore';
32export default function InlineEthereumTransaction({
33 // from useEthereumTransaction.bind
58 // additional from parent
59 label = 'Generate & Sign Transaction',
63 const { ethBalance } = useRollerStore();
64 // show receipt after successful broadcast
65 const [showReceipt, setShowReceipt] = useState(false);
66 const toggleShowReceipt = useCallback(() => setShowReceipt(!showReceipt), [
70 // show configure controls pre-broadcast
71 const showConfigureInput = !(signed || broadcasted || confirmed || completed);
72 // show the send/loading button while signed, broadcasting, or confirme
73 const showBroadcastButton = signed;
74 const showLoadingButton = broadcasted || confirmed;
75 const canBroadcast = signed && !needFunds;
76 // show signed tx only when signing (for offline usage)
77 const showSignedTx = signed;
79 const validate = useMemo(
82 useAdvanced: buildCheckboxValidator(),
83 viewSigned: buildCheckboxValidator(),
88 const onValues = useCallback(
89 ({ valid, values, form }) => {
90 if (!values.useAdvanced) {
97 const serializedTxsHex = useMemo(
100 signedTransactions.map(stx => hexify(stx.serialize())),
104 const numTxs = useMemo(() => (unsignedTransactions || []).length || 1, [
105 unsignedTransactions,
107 const maxCost = useMemo(
118 [gasLimit, gasPrice, numTxs]
121 const insufficientEth = useMemo(
122 () => Number(maxCost) > Number(ethBalance.toString()),
123 [maxCost, ethBalance]
126 const renderPrimarySection = () => {
130 className="eth-tx-button"
135 onClick={() => reset()}>
139 } else if (completed) {
144 className="eth-tx-button"
155 finalCost={finalCost}
156 onClose={toggleShowReceipt}
162 className="underline mv2 pointer"
164 onClick={toggleShowReceipt}>
170 } else if (insufficientEth) {
173 className="ph4 eth-tx-button insufficient-eth"
182 } else if (showBroadcastButton) {
185 className="ph4 eth-tx-button"
191 disabled={!canBroadcast}
192 onClick={() => broadcast()}>
196 } else if (showLoadingButton) {
199 className="ph4 eth-tx-button"
205 progress={confirmationProgress}>
212 className="ph4 eth-tx-button"
216 onClick={generateAndSign}
218 loading={!canSign && initializing}>
226 <Grid className={cn(className, 'mt1', 'inline-ethereum-tx')}>
227 <BridgeForm validate={validate} onValues={onValues}>
230 {showConfigureInput && (
233 className="mt2 text eth-tx-button"
238 <Flex.Item as={H5}>Gas Fee</Flex.Item>
239 <FeeDropdown setGasPrice={setGasPrice} />
243 className="mt2 text eth-tx-button"
248 <Flex.Item as={H5}>Max Transaction Cost</Flex.Item>
249 <Flex.Item as={H5}>{maxCost} ETH</Flex.Item>
251 <Grid.Divider className="mt4" />
255 {renderPrimarySection()}
258 <Grid.Item full as={ErrorText} className="mv1">
272 {showSignedTx && fakeSigned && (
274 <Grid.Item full as={NoticeBox} className="mt2">
275 Your wallet will sign the transaction upon sending it.
280 {showSignedTx && !fakeSigned && (
283 className="eth-tx-button text"
287 label="Signed Transaction"
289 disabled={!showSignedTx}
291 <Condition when="viewSigned" is={true}>
292 <SignedTransactionList
293 serializedTxsHex={serializedTxsHex}
307function SignedTransactionList({ serializedTxsHex, nonce, maxCost }) {
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>Transaction Cost</Flex.Item>
318 <Flex.Item>{maxCost} ETH</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, finalCost, onClose }) {
334 const txUrls = useExploreTxUrls(txHashes);
338 className="pv2 black f5 eth-tx-button"
342 <Flex.Item>Receipt</Flex.Item>
343 <Flex.Item onClick={onClose} className="underline pointer">
348 className="pv2 black f5 eth-tx-button"
352 <Flex.Item>Transaction Cost</Flex.Item>
353 <Flex.Item className="mono">{finalCost} ETH</Flex.Item>
356 <Grid.Item className="pv4 eth-tx-button" full as={Flex} col>
357 <Flex.Item as={H5}>Receipt</Flex.Item>
360 txHashes.map((txHash, i) => (
361 <Flex.Item as={Flex} className="mv3">
367 className="f6 mono gray4 wrap ">
370 <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