Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.stablenet.network/llms.txt

Use this file to discover all available pages before exploring further.

Stream new blocks and contract events from StableNet using WebSocket subscriptions and log queries.

What you’ll learn

By the end of this tutorial, you’ll be able to:
  • Subscribe to new block headers via WebSocket
  • Subscribe to contract events matching a topic filter
  • Query historical logs for a contract using eth_getLogs

Prerequisites

  • Node.js ≥ 18
  • npm install ethers (v6)
  • A deployed contract that emits events (e.g., the WKRCPayment contract from Deploy with Foundry)

Connect via WebSocket

eth_subscribe requires a persistent WebSocket connection. HTTP endpoints do not support subscriptions.
import { ethers } from "ethers";

const wsProvider = new ethers.WebSocketProvider(
  "wss://api.test.stablenet.network/ws"
);

Subscribe to new block headers

Each new block emits a header event. Use this to track chain progress or trigger polling logic.
wsProvider.on("block", async (blockNumber) => {
  const block = await wsProvider.getBlock(blockNumber);
  console.log(`Block ${block.number} — hash: ${block.hash}`);
});
Block 1234567 — hash: 0xabc...
Block 1234568 — hash: 0xdef...

Subscribe to contract events

To receive events from a specific contract, pass the contract’s ABI and address to an ethers.Contract instance. The example below listens for Payment events from the WKRCPayment contract.
const CONTRACT_ADDRESS = "0xYourDeployedContract";
const ABI = [
  "event Payment(address indexed from, address indexed to, uint256 amount)"
];

const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, wsProvider);

contract.on("Payment", (from, to, amount, event) => {
  console.log(`Payment from ${from} to ${to}: ${ethers.formatEther(amount)} WKRC`);
  console.log(`  tx: ${event.log.transactionHash}`);
});
Payment from 0xSender to 0xRecipient: 1.0 WKRC
  tx: 0xabc...

Filter events by topic

To receive events only from a specific sender, add a topic filter. EVM topic filters use null as a wildcard.
// Listen only for payments sent by a specific address
const filter = contract.filters.Payment("0xSpecificSender");
contract.on(filter, (from, to, amount) => {
  console.log(`Filtered payment: ${ethers.formatEther(amount)} WKRC`);
});

Query historical logs with eth_getLogs

Use eth_getLogs to query past events without a persistent connection. Specify a block range and optional topic filters.
const httpProvider = new ethers.JsonRpcProvider(
  "https://api.test.stablenet.network"
);

const logs = await httpProvider.getLogs({
  address: CONTRACT_ADDRESS,
  fromBlock: 1200000,
  toBlock: "latest",
  topics: [
    ethers.id("Payment(address,address,uint256)")  // keccak256 of event signature
  ],
});

for (const log of logs) {
  const parsed = contract.interface.parseLog(log);
  console.log(
    `Block ${log.blockNumber}: ${ethers.formatEther(parsed.args.amount)} WKRC`
  );
}
Block 1234500: 1.0 WKRC
Block 1234512: 0.5 WKRC

Clean up subscriptions

Remove event listeners when you no longer need them to avoid memory leaks.
// Remove a specific listener
contract.off("Payment", listenerFunction);

// Remove all listeners for an event
contract.removeAllListeners("Payment");

// Close the WebSocket connection
await wsProvider.destroy();

Topic matching rules

Topics map to indexed event parameters. Multiple values in one position are OR conditions; positions without a value are wildcards.
PositionMeaning
topics[0]Event signature hash (always required)
topics[1]First indexed parameter (from)
topics[2]Second indexed parameter (to)
null at any positionMatches any value
A maximum of 4 topic positions is supported.

Next steps

Deploy with Foundry

Deploy a contract that emits events.

RPC API Reference

Full reference for eth_subscribe, eth_getLogs, and filter methods.

Read On-Chain Data

Query balances, storage slots, and contract state.

Fee Delegation

Let a separate account pay gas for your users.