import React, { useMemo, useCallback, useState } from 'react'; import cn from 'classnames'; import { Grid, ToggleInput, ErrorText, Flex, LinkButton, H5, Button, } from 'indigo-react'; import { toBN } from 'web3-utils'; 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 ProgressButton from './ProgressButton'; import NeedFundsNotice from './NeedFundsNotice'; import NoticeBox from './NoticeBox'; import FeeDropdown from './L2/Dropdowns/FeeDropdown'; import CopyButton from './copiable/CopyButton'; import './InlineEthereumTransaction.scss'; import { useRollerStore } from 'store/rollerStore'; export default function InlineEthereumTransaction({ // from useEthereumTransaction.bind initializing, canSign, generateAndSign, signed, fakeSigned, 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, }) { const { ethBalance } = useRollerStore(); // 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 validate = useMemo( () => composeValidator({ useAdvanced: buildCheckboxValidator(), viewSigned: buildCheckboxValidator(), }), [] ); const onValues = useCallback( ({ valid, values, form }) => { if (!values.useAdvanced) { resetGasPrice(); } }, [resetGasPrice] ); 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 insufficientEth = useMemo( () => Number(maxCost) > Number(ethBalance.toString()), [maxCost, ethBalance] ); const renderPrimarySection = () => { if (error) { return ( reset()}> Reset Transaction ); } else if (completed) { return ( <> Return {showReceipt && ( )} {!showReceipt && ( View Receipt )} ); } else if (insufficientEth) { return ( Insufficient ETH ); } else if (showBroadcastButton) { return ( broadcast()}> Send Transaction ); } else if (showLoadingButton) { return ( Sending Transaction ); } else { return ( {label} ); } }; return ( {() => ( <> {showConfigureInput && ( <> Gas Fee Max Transaction Cost {maxCost} ETH )} {renderPrimarySection()} {error && ( {error.message} )} {needFunds && ( )} {showSignedTx && fakeSigned && ( <> Your wallet will sign the transaction upon sending it. )} {showSignedTx && !fakeSigned && ( <> )} )} ); } 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↗ ))} ); }