import {TransactionResponse} from '@ethersproject/providers'; import {useCallback, useMemo} from 'react'; import {useDispatch, useSelector} from 'react-redux'; import {useWallet} from 'use-wallet'; import {AppDispatch, AppState} from '../index'; import {addTransaction, clearAllTransactions} from './actions'; import {TransactionDetails} from './reducer'; // helper that can take a ethers library transaction response and add it to the list of transactions export function useTransactionAdder(): ( response: TransactionResponse, customData?: {summary?: string; approval?: {tokenAddress: string; spender: string}}, ) => void { const {chainId, account} = useWallet(); const dispatch = useDispatch(); return useCallback( ( response: TransactionResponse, {summary, approval}: {summary?: string; approval?: {tokenAddress: string; spender: string}} = {}, ) => { if (!account) return; if (!chainId) return; const {hash} = response; if (!hash) { throw Error('No transaction hash found.'); } dispatch(addTransaction({hash, from: account, chainId, approval, summary})); }, [dispatch, chainId, account], ); } // returns all the transactions for the current chain export function useAllTransactions(): {[txHash: string]: TransactionDetails} { const {chainId} = useWallet(); const state = useSelector((state) => state.transactions); return chainId ? state[chainId] ?? {} : {}; } export function useIsTransactionPending(transactionHash?: string): boolean { const transactions = useAllTransactions(); if (!transactionHash || !transactions[transactionHash]) { return false; } return !transactions[transactionHash].receipt; } /** * Returns whether a transaction happened in the last day (86400 seconds * 1000 milliseconds / second) * @param tx to check for recency */ export function isTransactionRecent(tx: TransactionDetails): boolean { return new Date().getTime() - tx.addedTime < 86_400_000; } // returns whether a token has a pending approval transaction export function useHasPendingApproval(tokenAddress: string | undefined, spender: string | undefined): boolean { const allTransactions = useAllTransactions(); return useMemo( () => typeof tokenAddress === 'string' && typeof spender === 'string' && Object.keys(allTransactions).some((hash) => { const tx = allTransactions[hash]; if (!tx) return false; if (tx.receipt) { return false; } else { const approval = tx.approval; if (!approval) return false; return approval.spender === spender && approval.tokenAddress === tokenAddress && isTransactionRecent(tx); } }), [allTransactions, spender, tokenAddress], ); } export function useClearAllTransactions(): {clearAllTransactions: () => void} { const {chainId} = useWallet(); const dispatch = useDispatch(); return { clearAllTransactions: useCallback(() => dispatch(clearAllTransactions({chainId})), [dispatch, chainId]), }; }