CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-wagmi

React Hooks for Ethereum providing reactive primitives for wallet connections, smart contract interactions, and blockchain data

Pending
Overview
Eval results
Files

watch.mddocs/

Real-time Data Watching

Event listeners and watchers for real-time blockchain data updates and contract events. This module provides comprehensive real-time data subscription functionality for monitoring blockchain state changes and contract events.

Capabilities

useWatchBlockNumber

Hook to watch for new block numbers in real-time with automatic updates.

/**
 * Hook to watch for new blocks
 * @param parameters - Block number watching parameters
 * @returns Real-time block number updates
 */
function useWatchBlockNumber<config = Config>(
  parameters?: UseWatchBlockNumberParameters<config>
): UseWatchBlockNumberReturnType;

interface UseWatchBlockNumberParameters<config = Config> {
  /** Chain to watch */
  chainId?: config['chains'][number]['id'];
  config?: Config | config;
  /** Whether to watch block numbers */
  enabled?: boolean;
  /** Callback when block number changes */
  onBlockNumber?: (blockNumber: bigint, prevBlockNumber?: bigint) => void;
  /** Callback on error */
  onError?: (error: Error) => void;
  /** Polling interval in milliseconds (default: 4000) */
  pollingInterval?: number;
  /** Whether to sync connected chain */
  syncConnectedChain?: boolean;
}

type UseWatchBlockNumberReturnType = void;

Usage Example:

import { useWatchBlockNumber, useBlockNumber } from "wagmi";
import { useState } from "react";

function BlockNumberWatcher() {
  const [latestBlock, setLatestBlock] = useState<bigint>();
  const { data: currentBlock } = useBlockNumber();

  useWatchBlockNumber({
    onBlockNumber(blockNumber, prevBlockNumber) {
      console.log('New block:', blockNumber.toString());
      setLatestBlock(blockNumber);
    },
    onError(error) {
      console.error('Block watch error:', error);
    },
  });

  return (
    <div>
      <h3>Block Number Watcher</h3>
      <p>Current Block: {currentBlock?.toString()}</p>
      <p>Latest Watched Block: {latestBlock?.toString()}</p>
    </div>
  );
}

useWatchBlocks

Hook to watch for new blocks with full block data in real-time.

/**
 * Hook to watch for new blocks
 * @param parameters - Block watching parameters
 * @returns Real-time block data updates
 */
function useWatchBlocks<config = Config>(
  parameters?: UseWatchBlocksParameters<config>
): UseWatchBlocksReturnType;

interface UseWatchBlocksParameters<config = Config> {
  /** Chain to watch */
  chainId?: config['chains'][number]['id'];
  config?: Config | config;
  /** Block tag to watch */
  blockTag?: 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized';
  /** Whether to watch blocks */
  enabled?: boolean;
  /** Whether to emit missed blocks on reconnect */
  emitMissed?: boolean;
  /** Whether to emit on begin */
  emitOnBegin?: boolean;
  /** Include full transaction data */
  includeTransactions?: boolean;
  /** Callback when new block arrives */
  onBlock?: (block: Block, prevBlock?: Block) => void;
  /** Callback on error */
  onError?: (error: Error) => void;
  /** Polling interval in milliseconds */
  pollingInterval?: number;
  /** Whether to sync connected chain */
  syncConnectedChain?: boolean;
}

type UseWatchBlocksReturnType = void;

interface Block {
  /** Block hash */
  hash: Hash;
  /** Block number */
  number: bigint;
  /** Parent block hash */
  parentHash: Hash;
  /** Timestamp */
  timestamp: bigint;
  /** Gas limit */
  gasLimit: bigint;
  /** Gas used */
  gasUsed: bigint;
  /** Miner/validator address */
  miner: Address;
  /** Transaction hashes or full transactions */
  transactions: Hash[] | Transaction[];
  /** Additional block properties */
  difficulty?: bigint;
  totalDifficulty?: bigint;
  size?: bigint;
  nonce?: Hex;
  baseFeePerGas?: bigint;
}

useWatchContractEvent

Hook to watch for specific contract events in real-time.

/**
 * Hook to watch contract events
 * @param parameters - Event watching parameters
 * @returns Event watcher that triggers on new events
 */
function useWatchContractEvent<config = Config>(
  parameters: UseWatchContractEventParameters<config>
): UseWatchContractEventReturnType;

interface UseWatchContractEventParameters<config = Config> {
  /** Contract ABI */
  abi: Abi;
  /** Contract address */
  address?: Address | Address[];
  /** Event name to watch */
  eventName?: string;
  /** Event parameter filters */
  args?: Record<string, unknown> | readonly unknown[];
  /** Batch event handling */
  batch?: boolean;
  /** Chain to watch */
  chainId?: config['chains'][number]['id'];
  config?: Config | config;
  /** Whether to watch events */
  enabled?: boolean;
  /** From block */
  fromBlock?: bigint;
  /** Event handler callback */
  onLogs: (logs: Log[]) => void;
  /** Error handler callback */
  onError?: (error: Error) => void;
  /** Polling interval in milliseconds */
  pollingInterval?: number;
  /** Whether to fetch past events on mount */
  strict?: boolean;
  /** Whether to sync connected chain */
  syncConnectedChain?: boolean;
}

type UseWatchContractEventReturnType = void;

interface Log {
  /** Event address */
  address: Address;
  /** Topics (indexed parameters) */
  topics: readonly Hash[];
  /** Event data */
  data: Hex;
  /** Block hash */
  blockHash?: Hash;
  /** Block number */
  blockNumber?: bigint;
  /** Transaction hash */
  transactionHash?: Hash;
  /** Transaction index */
  transactionIndex?: number;
  /** Log index */
  logIndex?: number;
  /** Whether log was removed */
  removed?: boolean;
}

Usage Example:

import { useWatchContractEvent } from "wagmi";
import { erc20Abi } from "viem";
import { useState } from "react";

function TokenTransferWatcher() {
  const [transfers, setTransfers] = useState<Log[]>([]);

  useWatchContractEvent({
    abi: erc20Abi,
    address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    eventName: 'Transfer',
    args: {
      // Watch transfers from specific address
      from: '0x742d35Cc6634C0532925a3b8D',
    },
    onLogs(logs) {
      console.log('New transfer events:', logs);
      setTransfers(prev => [...prev, ...logs]);
    },
    onError(error) {
      console.error('Event watch error:', error);
    },
  });

  return (
    <div>
      <h3>Token Transfer Monitor</h3>
      <p>Watching {transfers.length} transfers</p>
      {transfers.slice(-5).map((transfer, i) => (
        <div key={i}>
          <p>Block: {transfer.blockNumber?.toString()}</p>
          <p>Hash: {transfer.transactionHash}</p>
        </div>
      ))}
    </div>
  );
}

useWatchPendingTransactions

Hook to watch for pending transactions in the mempool.

/**
 * Hook to watch pending transactions
 * @param parameters - Pending transaction watching parameters
 * @returns Real-time pending transaction updates
 */
function useWatchPendingTransactions<config = Config>(
  parameters?: UseWatchPendingTransactionsParameters<config>
): UseWatchPendingTransactionsReturnType;

interface UseWatchPendingTransactionsParameters<config = Config> {
  /** Chain to watch */
  chainId?: config['chains'][number]['id'];
  config?: Config | config;
  /** Whether to watch pending transactions */
  enabled?: boolean;
  /** Callback when new pending transaction */
  onTransactions?: (hashes: Hash[]) => void;
  /** Error handler callback */
  onError?: (error: Error) => void;
  /** Polling interval in milliseconds */
  pollingInterval?: number;
  /** Whether to sync connected chain */
  syncConnectedChain?: boolean;
}

type UseWatchPendingTransactionsReturnType = void;

useWatchAsset

Hook to request adding an asset (token) to the user's wallet.

/**
 * Hook to request adding asset to wallet
 * @param parameters - Watch asset configuration with mutation callbacks
 * @returns Watch asset mutation
 */
function useWatchAsset<config = Config, context = unknown>(
  parameters?: UseWatchAssetParameters<config, context>
): UseWatchAssetReturnType<config, context>;

interface UseWatchAssetParameters<config = Config, context = unknown> {
  config?: Config | config;
  mutation?: {
    onMutate?: (variables: WatchAssetVariables) => Promise<context> | context;
    onError?: (error: WatchAssetErrorType, variables: WatchAssetVariables, context?: context) => Promise<void> | void;
    onSuccess?: (data: WatchAssetData, variables: WatchAssetVariables, context?: context) => Promise<void> | void;
    onSettled?: (data?: WatchAssetData, error?: WatchAssetErrorType, variables?: WatchAssetVariables, context?: context) => Promise<void> | void;
  };
}

interface UseWatchAssetReturnType<config = Config, context = unknown> {
  /** Request to add asset to wallet */
  watchAsset: (variables: WatchAssetVariables, options?: WatchAssetMutateOptions) => void;
  /** Async version of watchAsset */
  watchAssetAsync: (variables: WatchAssetVariables, options?: WatchAssetMutateAsyncOptions) => Promise<WatchAssetData>;
  /** Watch asset data */
  data?: WatchAssetData;
  /** Watch asset error */
  error: WatchAssetErrorType | null;
  /** Watch asset status flags */
  isError: boolean;
  isIdle: boolean;
  isPending: boolean;
  isSuccess: boolean;
  /** Reset watch asset state */
  reset: () => void;
  /** Current status */
  status: 'error' | 'idle' | 'pending' | 'success';
  /** Additional variables */
  variables?: WatchAssetVariables;
}

interface WatchAssetVariables {
  /** Asset type (currently only 'ERC20' supported) */
  type: 'ERC20';
  /** Token options */
  options: {
    /** Token contract address */
    address: Address;
    /** Token symbol */
    symbol?: string;
    /** Token decimals */
    decimals?: number;
    /** Token image URL */
    image?: string;
  };
}

type WatchAssetData = boolean; // Whether user accepted the request

Usage Example:

import { useWatchAsset } from "wagmi";

function AddTokenButton() {
  const { watchAsset, isPending } = useWatchAsset();

  const handleAddToken = () => {
    watchAsset({
      type: 'ERC20',
      options: {
        address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
        symbol: 'DAI',
        decimals: 18,
        image: 'https://wallet-asset-matic.s3.amazonaws.com/img/tokens/dai.svg',
      },
    });
  };

  return (
    <button onClick={handleAddToken} disabled={isPending}>
      {isPending ? 'Adding...' : 'Add DAI to Wallet'}
    </button>
  );
}

Advanced Watching Patterns

Multi-Contract Event Aggregator

import { useWatchContractEvent } from "wagmi";
import { erc20Abi } from "viem";
import { useState } from "react";

interface TokenEvent {
  token: Address;
  event: string;
  data: Log;
  timestamp: number;
}

function MultiTokenWatcher() {
  const [events, setEvents] = useState<TokenEvent[]>([]);
  
  const tokens = [
    '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    '0xA0b86a33E6417C90CC5F6d2c4a29f9D7e5D8ecf0', // USDC
    '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
  ];

  // Watch Transfer events for all tokens
  tokens.forEach(token => {
    useWatchContractEvent({
      abi: erc20Abi,
      address: token,
      eventName: 'Transfer',
      onLogs(logs) {
        const tokenEvents: TokenEvent[] = logs.map(log => ({
          token: token,
          event: 'Transfer',
          data: log,
          timestamp: Date.now(),
        }));
        setEvents(prev => [...prev.slice(-50), ...tokenEvents]);
      },
    });
  });

  return (
    <div>
      <h3>Multi-Token Event Monitor</h3>
      <p>Total events: {events.length}</p>
      {events.slice(-10).map((event, i) => (
        <div key={i} style={{ border: '1px solid #ccc', margin: '4px', padding: '8px' }}>
          <p>Token: {event.token}</p>
          <p>Event: {event.event}</p>
          <p>Block: {event.data.blockNumber?.toString()}</p>
          <p>Time: {new Date(event.timestamp).toLocaleTimeString()}</p>
        </div>
      ))}
    </div>
  );
}

Real-time Portfolio Tracker

import { 
  useWatchContractEvent, 
  useAccount, 
  useBalance 
} from "wagmi";
import { erc20Abi } from "viem";
import { useState, useEffect } from "react";

function PortfolioTracker() {
  const { address } = useAccount();
  const [lastUpdate, setLastUpdate] = useState<Date>();
  const [transactionCount, setTransactionCount] = useState(0);

  const { data: ethBalance, refetch: refetchEth } = useBalance({ 
    address: address!,
    query: { enabled: !!address }
  });

  const { data: daiBalance, refetch: refetchDai } = useBalance({
    address: address!,
    token: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    query: { enabled: !!address }
  });

  // Watch for transactions affecting this address
  useWatchContractEvent({
    abi: erc20Abi,
    address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    eventName: 'Transfer',
    args: {
      from: address,
    },
    enabled: !!address,
    onLogs(logs) {
      console.log('Outgoing DAI transfers:', logs);
      setTransactionCount(prev => prev + logs.length);
      setLastUpdate(new Date());
      refetchDai();
    },
  });

  useWatchContractEvent({
    abi: erc20Abi,
    address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    eventName: 'Transfer',
    args: {
      to: address,
    },
    enabled: !!address,
    onLogs(logs) {
      console.log('Incoming DAI transfers:', logs);
      setTransactionCount(prev => prev + logs.length);
      setLastUpdate(new Date());
      refetchDai();
    },
  });

  // Watch for new blocks to refresh ETH balance
  useWatchBlockNumber({
    enabled: !!address,
    onBlockNumber() {
      refetchEth();
    },
  });

  if (!address) return <p>Please connect wallet</p>;

  return (
    <div>
      <h3>Real-time Portfolio</h3>
      <p>ETH Balance: {ethBalance?.formatted} {ethBalance?.symbol}</p>
      <p>DAI Balance: {daiBalance?.formatted} {daiBalance?.symbol}</p>
      <p>DAI Transactions Detected: {transactionCount}</p>
      {lastUpdate && <p>Last Update: {lastUpdate.toLocaleTimeString()}</p>}
    </div>
  );
}

Event Log Analyzer

import { useWatchContractEvent } from "wagmi";
import { useState } from "react";
import { decodeEventLog } from "viem";

function EventAnalyzer() {
  const [eventStats, setEventStats] = useState<Record<string, number>>({});

  useWatchContractEvent({
    abi: erc20Abi,
    address: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI
    onLogs(logs) {
      logs.forEach(log => {
        try {
          const decoded = decodeEventLog({
            abi: erc20Abi,
            data: log.data,
            topics: log.topics,
          });

          setEventStats(prev => ({
            ...prev,
            [decoded.eventName]: (prev[decoded.eventName] || 0) + 1,
          }));
        } catch (error) {
          console.error('Failed to decode event:', error);
        }
      });
    },
  });

  return (
    <div>
      <h3>Event Statistics</h3>
      {Object.entries(eventStats).map(([event, count]) => (
        <p key={event}>{event}: {count}</p>
      ))}
    </div>
  );
}

Common Types

type Hash = `0x${string}`;
type Hex = `0x${string}`;
type Address = `0x${string}`;

interface Transaction {
  hash: Hash;
  blockHash?: Hash;
  blockNumber?: bigint;
  transactionIndex?: number;
  from: Address;
  to?: Address;
  value: bigint;
  gas: bigint;
  gasPrice?: bigint;
  maxFeePerGas?: bigint;
  maxPriorityFeePerGas?: bigint;
  input: Hex;
  nonce: number;
  type?: 'legacy' | 'eip2930' | 'eip1559';
}

interface Abi {
  readonly [key: number]: AbiItem;
}

interface AbiItem {
  type: 'function' | 'event' | 'error' | 'constructor' | 'fallback' | 'receive';
  name?: string;
  inputs?: AbiParameter[];
  outputs?: AbiParameter[];
  stateMutability?: 'pure' | 'view' | 'nonpayable' | 'payable';
  anonymous?: boolean;
}

interface AbiParameter {
  name: string;
  type: string;
  components?: AbiParameter[];
  indexed?: boolean;
}

interface WatchAssetMutateOptions {
  onError?: (error: Error, variables: WatchAssetVariables, context?: unknown) => void;
  onSuccess?: (data: boolean, variables: WatchAssetVariables, context?: unknown) => void;
  onSettled?: (data?: boolean, error?: Error, variables?: WatchAssetVariables, context?: unknown) => void;
}

type WatchAssetErrorType = Error;

Install with Tessl CLI

npx tessl i tessl/npm-wagmi

docs

account.md

advanced.md

batch.md

blockchain.md

contracts.md

ens.md

gas-fees.md

index.md

signing.md

transactions.md

watch.md

tile.json