Wallet-side library that watches on-chain payment transactions in real-time via raw JSON-RPC. Solves the "I paid the dashboard, it said executed, then nothing happened" UX gap that plagues crypto-payment-to-credits flows, fiat-to-token conversions, and DEX-mediated checkout pipelines.
Built by Elyan Labs after we hit this exact problem live during a ChainGPT credit purchase: we paid ~$14 BNB across 3 TXs, the dashboard said "executed", and 5+ days later the credits still hadn't propagated. The dashboard never told us anything was wrong — it just went silent.
This library makes that silence preventable.
Given a transaction hash + (optionally) the expected destination contract, the tracker:
- Polls a public EVM RPC (free, no auth, no third-party indexer) for TX status
- Emits live events as the TX moves through
submitted → in_mempool → mined → confirming → confirmed - Detects destination mismatch if the TX went to a different contract than expected
- Detects revert (TX failed on-chain)
- Provides time estimates ("~36 seconds to finality") so the UI can show a meaningful progress bar
- Falls back across multiple public RPCs — Binance dataseed, defibit, publicnode, 1rpc — so a single dead RPC doesn't break tracking
Zero external dependencies. Works in Node and browsers.
Most payment dashboards rely on their own backend indexer to detect payment receipt. That works when the indexer is fast. It breaks badly when the indexer is slow, crashed, or under-resourced — which happens regularly with crypto startups.
A wallet-side tracker bypasses the platform's indexer entirely. The user's app reads the chain directly, knows exactly when their TX is confirmed, and can show real-time UI updates the moment the transaction lands. The platform's indexer can still be late — but the user is no longer in the dark.
npm install chain-payment-trackerimport { PaymentTracker, RpcClient } from 'chain-payment-tracker';
const rpc = RpcClient.forChain('bsc'); // or 'ethereum'
const tracker = new PaymentTracker({
rpcClient: rpc,
txHash: '0x059d76593fdd4ceca866ee1f14efc159b0d5bcc3644c17337a623dd7f0e17d7e',
expectedDestination: '0xB8c49C78c4D3bAE228C1BDc2df829275303FfE95',
finalityConfs: 12,
});
tracker.on('mined', (e) => console.log(`Mined at block ${e.blockNumber}`));
tracker.on('confirming', (e) => console.log(`${e.confirmations}/12 confirmations`));
tracker.on('confirmed', (e) => console.log(`Finality reached!`));
tracker.on('reverted', (e) => console.log(`TX failed on-chain`));
await tracker.start();| Event | When | Payload includes |
|---|---|---|
submitted |
Tracker started | txHash |
in_mempool |
TX seen but not yet mined | actualDestination |
mined |
TX in a block, 1 confirmation | blockNumber, actualDestination, destinationMismatch |
confirming |
Each new confirmation past 1 | confirmations, expectedRemainingSeconds, destinationMismatch |
confirmed |
finalityConfs reached (default 12) |
confirmations, blockNumber, actualDestination |
reverted |
TX status === 0x0 |
blockNumber, error |
timeout |
Never confirmed within maxWaitSeconds |
error |
warning |
Transient RPC error (tracker keeps trying) | error |
update |
Fires on EVERY state change (catch-all) | full event payload |
The repo includes examples/track-bsc-payment.js — a CLI demo that
tracks a real on-chain TX. Default is the actual May 9 2026 ChainGPT BNB payment that motivated
this library:
node examples/track-bsc-payment.jsOutput (since the TX is already confirmed many times over):
[ 0.0s] SUBMITTED — TX hash known, polling network...
[ 0.5s] ✓ CONFIRMED — block #97395196, 860280+ confirmations, finality reached
Destination: 0xb8c49c78c4d3bae228c1bdc2df829275303ffe95
For real-time tracking on a fresh TX, the lib emits each confirmation as it lands.
There's also examples/integrate-with-dashboard.html —
a complete browser integration showing how a payment dashboard would use this lib for live UI
updates with a progress bar.
new PaymentTracker({
rpcClient: RpcClient, // RpcClient instance
txHash: string, // 0x... 32-byte hash
expectedDestination?: string, // 0x... contract address (optional, enables mismatch detection)
finalityConfs?: number, // default 12 (BSC/ETH standard)
pollIntervalMs?: number, // default 3000ms
maxWaitSeconds?: number, // default 300 (5 min)
});npm testTests run against live BSC using a known historical TX — no mocks. 6/6 should pass.
MIT — Elyan Labs
- RustChain — Elyan Labs' DePIN attestation chain
- RustChain Attestation Bridge — sister PoC for hardware-attestation-as-a-service