import React, { useMemo, useCallback, useState } from 'react'; import cn from 'classnames'; import { Grid, ToggleInput, ErrorText, Flex, LinkButton, H5, Text, } from 'indigo-react'; import { toBN } from 'web3-utils'; import { ReactComponent as InfoIcon } from 'assets/info.svg'; import { useExploreTxUrls } from 'lib/explorer'; import { hexify } from 'lib/txn'; import { safeFromWei, safeToWei } from 'lib/lib'; import { composeValidator, buildCheckboxValidator } from 'form/validators'; import BridgeForm from 'form/BridgeForm'; import Condition from 'form/Condition'; import { GenerateButton, ForwardButton, RestartButton } from './Buttons'; import CopyButton from './CopyButton'; import ProgressButton from './ProgressButton'; import { convertToInt } from 'lib/convertToInt'; import NeedFundsNotice from './NeedFundsNotice'; export default function InlineEthereumTransaction({ // from useEthereumTransaction.bind initializing, canSign, generateAndSign, signed, broadcast, broadcasted, confirmed, completed, reset, error, gasPrice, setGasPrice, resetGasPrice, txHashes, nonce, chainId, needFunds, signedTransactions, confirmationProgress, gasLimit, unsignedTransactions, finalCost, // additional from parent label = 'Generate & Sign Transaction', className, onReturn, }) { // show receipt after successful broadcast const [showReceipt, setShowReceipt] = useState(false); const toggleShowReceipt = useCallback(() => setShowReceipt(!showReceipt), [ setShowReceipt, showReceipt, ]); // show configure controls pre-broadcast const showConfigureInput = !(signed || broadcasted || confirmed || completed); // show the send/loading button while signed, broadcasting, or confirme const showBroadcastButton = signed; const showLoadingButton = broadcasted || confirmed; const canBroadcast = signed && !needFunds; // show signed tx only when signing (for offline usage) const showSignedTx = signed; const [showGasDetails, _setShowGasDetails] = useState(false); const toggleGasDetails = useCallback( () => _setShowGasDetails(!showGasDetails), [_setShowGasDetails, showGasDetails] ); const validate = useMemo( () => composeValidator({ useAdvanced: buildCheckboxValidator(), viewSigned: buildCheckboxValidator(), }), [] ); const onValues = useCallback( ({ valid, values, form }) => { if (!values.useAdvanced) { resetGasPrice(); } }, [resetGasPrice] ); const renderPrimarySection = () => { if (error) { return ( reset()}> Reset Transaction ); } else if (completed) { return ( <> Return {showReceipt && ( )} {!showReceipt && ( View Receipt )} ); } else if (showBroadcastButton) { return ( broadcast()}> Send Transaction ); } else if (showLoadingButton) { return ( Sending Transaction ); } else { return ( {label} ); } }; const serializedTxsHex = useMemo( () => signedTransactions && signedTransactions.map(stx => hexify(stx.serialize())), [signedTransactions] ); const numTxs = useMemo(() => (unsignedTransactions || []).length || 1, [ unsignedTransactions, ]); const maxCost = useMemo( () => safeFromWei( safeToWei( toBN(gasLimit) .mul(toBN(gasPrice)) .mul(toBN(numTxs)), 'gwei' ), 'ether' ), [gasLimit, gasPrice, numTxs] ); const gasInfo = useMemo(() => { const extra = numTxs === 1 ? '' : `* ${numTxs} txs`; return showGasDetails ? `${gasPrice} Gwei * ${gasLimit} ${extra} = ${maxCost} ETH` : `${maxCost} ETH`; }, [showGasDetails, maxCost, gasPrice, gasLimit, numTxs]); return ( {() => ( <> {renderPrimarySection()} {error && ( {error.message} )} {needFunds && ( )} {showConfigureInput && ( <> Transaction Fee {gasInfo}{' '} {/* TODO(shrugs): move to indigo/RangeInput */} setGasPrice(convertToInt(e.target.value, 10)) } /> Cheap Fast )} {showSignedTx && ( <> )} )} ); } function SignedTransactionList({ serializedTxsHex, nonce, maxCost }) { return serializedTxsHex.map((serializedTxHex, i) => ( Nonce {nonce + i} Transaction Cost {maxCost} ETH Signed Transaction Hex {serializedTxHex} )); } function TransactionReceipt({ txHashes, finalCost, onClose }) { const txUrls = useExploreTxUrls(txHashes); return ( <> Receipt Close Transaction Cost {finalCost} ETH Receipt {txHashes && txHashes.map((txHash, i) => ( <> {txHash} Etherscan↗ ))} ); }