viem
Version:
114 lines • 4.99 kB
JavaScript
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