import {useEffect} from 'react'; import {useDispatch, useSelector} from 'react-redux'; import {useWallet} from 'use-wallet'; import {useAddPopup, useBlockNumber} from '../application/hooks'; import {AppDispatch, AppState} from '../index'; import {checkedTransaction, finalizeTransaction} from './actions'; import {getDefaultProvider} from '../../utils/provider'; export function shouldCheck( lastBlockNumber: number, tx: {addedTime: number; receipt?: {}; lastCheckedBlockNumber?: number}, ): boolean { if (tx.receipt) return false; if (!tx.lastCheckedBlockNumber) return true; const blocksSinceCheck = lastBlockNumber - tx.lastCheckedBlockNumber; if (blocksSinceCheck < 1) return false; const minutesPending = (new Date().getTime() - tx.addedTime) / 1000 / 60; if (minutesPending > 60) { // every 10 blocks if pending for longer than an hour return blocksSinceCheck > 9; } else if (minutesPending > 5) { // every 3 blocks if pending more than 5 minutes return blocksSinceCheck > 2; } else { // otherwise every block return true; } } export default function Updater(): null { const {chainId, ethereum} = useWallet(); const lastBlockNumber = useBlockNumber(); const dispatch = useDispatch(); const state = useSelector((state) => state.transactions); const transactions = chainId ? state[chainId] ?? {} : {}; // show popup on confirm const addPopup = useAddPopup(); useEffect(() => { if (!chainId || !ethereum || !lastBlockNumber) { return; } const provider = getDefaultProvider(); Object.keys(transactions) .filter((hash) => shouldCheck(lastBlockNumber, transactions[hash])) .forEach((hash) => { provider .getTransactionReceipt(hash) .then((receipt) => { if (receipt) { dispatch( finalizeTransaction({ chainId, hash, receipt: { blockHash: receipt.blockHash, blockNumber: receipt.blockNumber, contractAddress: receipt.contractAddress, from: receipt.from, status: receipt.status, to: receipt.to, transactionHash: receipt.transactionHash, transactionIndex: receipt.transactionIndex, }, }), ); addPopup( { txn: { hash, success: receipt.status === 1, summary: transactions[hash]?.summary, }, }, hash, ); } else { dispatch(checkedTransaction({chainId, hash, blockNumber: lastBlockNumber})); } }) .catch((error) => { console.error(`failed to check transaction hash: ${hash}`, error); }); }); }, [chainId, ethereum, transactions, lastBlockNumber, dispatch, addPopup]); return null; }