UNPKG

viem

Version:

TypeScript Interface for Ethereum

114 lines 4.99 kB
import { getAction } from '../../utils/getAction.js'; import { observe } from '../../utils/observe.js'; import { poll } from '../../utils/poll.js'; import { stringify } from '../../utils/stringify.js'; import { createPendingTransactionFilter } from './createPendingTransactionFilter.js'; import { getFilterChanges } from './getFilterChanges.js'; import { uninstallFilter } from './uninstallFilter.js'; /** * Watches and returns pending transaction hashes. * * - Docs: https://viem.sh/docs/actions/public/watchPendingTransactions * - JSON-RPC Methods: * - When `poll: true` * - Calls [`eth_newPendingTransactionFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter) to initialize the filter. * - Calls [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getFilterChanges) on a polling interval. * - When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newPendingTransactions"` event. * * This Action will batch up all the pending transactions found within the [`pollingInterval`](https://viem.sh/docs/actions/public/watchPendingTransactions#pollinginterval-optional), and invoke them via [`onTransactions`](https://viem.sh/docs/actions/public/watchPendingTransactions#ontransactions). * * @param client - Client to use * @param parameters - {@link WatchPendingTransactionsParameters} * @returns A function that can be invoked to stop watching for new pending transaction hashes. {@link WatchPendingTransactionsReturnType} * * @example * import { createPublicClient, http } from 'viem' * import { mainnet } from 'viem/chains' * import { watchPendingTransactions } from 'viem/public' * * const client = createPublicClient({ * chain: mainnet, * transport: http(), * }) * const unwatch = await watchPendingTransactions(client, { * onTransactions: (hashes) => console.log(hashes), * }) */ export function watchPendingTransactions(client, { batch = true, onError, onTransactions, poll: poll_, pollingInterval = client.pollingInterval, }) { const enablePolling = typeof poll_ !== 'undefined' ? poll_ : client.transport.type !== 'webSocket'; const pollPendingTransactions = () => { const observerId = stringify([ 'watchPendingTransactions', client.uid, batch, pollingInterval, ]); return observe(observerId, { onTransactions, onError }, (emit) => { let filter; const unwatch = poll(async () => { try { if (!filter) { try { filter = await getAction(client, createPendingTransactionFilter, 'createPendingTransactionFilter')({}); return; } catch (err) { unwatch(); throw err; } } const hashes = await getAction(client, getFilterChanges, 'getFilterChanges')({ filter }); if (hashes.length === 0) return; if (batch) emit.onTransactions(hashes); else for (const hash of hashes) emit.onTransactions([hash]); } catch (err) { emit.onError?.(err); } }, { emitOnBegin: true, interval: pollingInterval, }); return async () => { if (filter) await getAction(client, uninstallFilter, 'uninstallFilter')({ filter }); unwatch(); }; }); }; const subscribePendingTransactions = () => { let active = true; let unsubscribe = () => (active = false); (async () => { try { const { unsubscribe: unsubscribe_ } = await client.transport.subscribe({ params: ['newPendingTransactions'], onData(data) { if (!active) return; const transaction = data.result; onTransactions([transaction]); }, onError(error) { onError?.(error); }, }); unsubscribe = unsubscribe_; if (!active) unsubscribe(); } catch (err) { onError?.(err); } })(); return () => unsubscribe(); }; return enablePolling ? pollPendingTransactions() : subscribePendingTransactions(); } //# sourceMappingURL=watchPendingTransactions.js.map