Skip to Content
Pulsar EVM Standalone

Using EVM Trackers Standalone

While the Pulsar suite offers a full stack solution with a UI (@tuwaio/nova-transactions) and a Zustand-based state store (@tuwaio/pulsar-core), its architecture remains modular and flexible. This allows utilizing the low-level trackers (evmTracker, gelatoFetcher, safeFetcher) from @tuwaio/pulsar-evm directly, bypassing the complete state management store.

This flexibility is ideal if:

  • Integrating transaction tracking logic into your own state management solution (Zustand, Redux, MobX, etc.).
  • Requiring tracking on the server-side, where client-centric store persistence is unnecessary.
  • Granular control over each stage of a transaction’s lifecycle is required for custom workflows.

[!WARNING] Use of legacy web3.js and ethers.js libraries is strictly prohibited. All tracking pipelines are built strictly upon viem and wagmi primitives to ensure deterministic transaction status reconciliation and application sovereignty.


Why Use evmTracker?

Using evmTracker provides client-side state persistence, mempool retry logic, and multi-chain indexing helpers that standard RPC calls lack.

FeaturewaitForTransactionReceipt (viem)evmTracker (Pulsar)
Handles RPC Lags❌ No. If called immediately after submission, the RPC node might not have indexed the transaction yet, causing errors.Yes. Built-in retry mechanism to wait for the transaction to appear in the mempool, mitigating RPC delays.
Full Lifecycle Support🤷‍♂️ Limited. Mainly reacts once the transaction is confirmed or replaced.Yes. Provides callbacks for each stage: initialization, details fetched, mined, replaced, failed, etc.
Fetches Full Tx Details❌ No. Doesn’t return complete info such as nonce, value, etc.Yes. Calls getTransaction internally, passing all transaction details to callbacks.
Abstraction LevelLow. You must manage the tracking states manually.High. Encapsulates the entire process into a single, convenient async function, simplifying implementation.

In essence, evmTracker is a reliable tracking pipeline wrapper around viem functions, addressing common edge cases and ensuring robust transaction lifecycle tracking.


Trackers Overview

1. EVM Tracker

This is the primary tracker for monitoring standard transactions on EVM-compatible chains, identified via transaction hash.

How It Works

evmTracker initially fetches transaction details using getTransaction. If unavailable (due to RPC indexing delay), it retries. Once details are resolved, it actively waits for the transaction receipt using waitForTransactionReceipt.

Example Usage

import { evmTracker } from '@tuwaio/pulsar-evm'; import { config } from './wagmi'; // Your wagmi config async function trackMyTransaction(txHash: string, chainId: number) { console.log(`Starting to track transaction: ${txHash}`); await evmTracker({ config, // Wagmi config for internal client creation tx: { txKey: txHash, // Transaction hash chainId, // Chain ID (e.g., 1 for Ethereum Mainnet) }, onTxDetailsFetched: (txDetails) => { console.log('Transaction details received:', txDetails); // Update your UI/state with nonce, gas, etc. }, onSuccess: async (txDetails, receipt, client) => { console.log('Transaction mined!', receipt); if (receipt.status === 'success') { // Update status as successful } else { // Update status as failed } }, onReplaced: (replacement) => { console.log('Transaction was replaced:', replacement); // Handle replacement logic }, onFailure: (error) => { console.error('Tracking failed:', error); // Handle errors }, }); }

2. Gelato & Safe Fetchers

For polling-based tracking, especially for Gelato and Safe multisig transactions, we expose fetcher functions. You can integrate these directly with Pulsar’s initializePollingTracker or your custom polling setup.

Example for Handling Gelato & Safe Transactions

import { initializePollingTracker } from '@tuwaio/pulsar-core'; import { gelatoFetcher, safeFetcher, createGelatoClient } from '@tuwaio/pulsar-evm'; // Initialize Gelato HTTP transport client const gelatoClient = createGelatoClient({ apiKey: 'YOUR_GELATO_API_KEY' }); // Tracking a Gelato relay task async function trackGelatoTask(taskId: string) { await initializePollingTracker({ tx: { txKey: taskId, pending: true, // Crucial: must be true to start polling loop }, fetcher: gelatoFetcher(gelatoClient), onSuccess: (status) => { console.log('Gelato task succeeded:', status); }, onFailure: (status) => { console.error('Gelato task failed:', status); }, }); } // Tracking a Safe multisig transaction async function trackSafeTx(safeTxHash: string, chainId: number, fromAddress: string) { await initializePollingTracker({ tx: { txKey: safeTxHash, chainId, from: fromAddress, pending: true, // Crucial: must be true to start polling loop }, fetcher: safeFetcher, onSuccess: (status) => { console.log('Safe transaction succeeded:', status); }, onFailure: (status) => { console.error('Safe transaction failed:', status); }, onReplaced: (replacement) => { console.warn('Transaction was replaced:', replacement); }, }); }

Helper Functions

Additionally, the package provides several utilities for managing transaction states and chain interactions:

checkTransactionsTracker

Determines which tracker is suitable based on a transaction key.

import { checkTransactionsTracker } from '@tuwaio/pulsar-evm'; const { tracker, txKey } = checkTransactionsTracker('0xabc...', 'injected'); // tracker -> 'ethereum' or relevant tracker type // txKey -> same as input or derived key
Last updated on