Real-time events
Instead of polling balances or scanning blocks, let ChainGate push events to your code. Subscribe with a callback and receive new blocks, balance changes, transaction activity and pending transactions the moment they happen — on Bitcoin, Litecoin, Dogecoin, Bitcoin Cash, Bitcoin Testnet, Ethereum and Avalanche.
import { ChainGate } from 'chaingate'
const cg = new ChainGate()
const btc = cg.explore(cg.networks.bitcoin)
btc.onBlock((block) => {
console.log(`Block ${block.height} — ${block.numTxs} transactions`)
})
btc.onBalance('bc1q...', async ({ confirmed }) => {
console.log('New balance:', confirmed.base(), confirmed.symbol)
console.log('In USD:', await confirmed.toCurrency('usd'))
})
Events are included with every API key, and work without one too (with the keyless rate limit).
Two ways to subscribe
Explorers follow any address you pass, no wallet needed:
const eth = cg.explore(cg.networks.ethereum)
eth.onTransaction('0x...', ({ height }) => console.log('Activity in block', height))
Connectors follow the wallet's own address — it is derived for you:
const wallet = cg.connect(cg.networks.bitcoin, myWallet)
const sub = wallet.onTransaction(({ received, amount, txid }) => {
console.log(received ? 'Received' : 'Sent', amount.base(), 'BTC in', txid)
})
await sub.ready
console.log('Following', sub.address) // the wallet's address
Connector methods accept the same address options as the rest of the connector ({ index, addressType, derivationPath }), so you can follow any address of an HD wallet:
wallet.onBalance(({ confirmed }) => console.log(confirmed.base()), { index: 3 })
Available events
| Method | What you receive | UTXO | EVM |
|---|---|---|---|
onBlock(cb) | A summary of every new block | ✓ | ✓ |
onFullBlock(cb) | Every new block with all its transactions | ✓ | ✓ |
onBalance(address, cb) | The confirmed balance after every block that changes it | ✓ | ✓ |
onPendingBalance(address, cb) | The pending (mempool) balance delta as it changes | ✓ | ✓ |
onTransaction(address, cb) | Every confirmed transaction of the address | ✓ | ✓ |
onPendingTransaction(address, cb) | Every pending transaction that touches the address | ✓ | ✓ |
onMempoolTransaction(cb) | Every pending transaction seen on the network | ✓ | ✓ |
onContractInteraction(address, cb) | Each new contract the address interacts with | — | ✓ |
onError(cb) | Connection and subscription errors | ✓ | ✓ |
Connectors expose the same methods without the address parameter.
The subscription handle
Every method returns a Subscription right away:
const sub = btc.onBalance('bc1q...', (event) => { /* ... */ })
await sub.ready // resolves once the server has confirmed the subscription
sub.address // the address being followed (undefined for onBlock & co.)
sub.unsubscribe() // stop receiving events; safe to call more than once
ready rejects with an EventSubscriptionError if the server refuses the subscription. Passing an address that is not valid for the network throws the same error immediately, before anything is sent.
Amounts
Amounts in events are Amount instances, exactly like the values returned by the explorers and connectors: .base() for the human-readable value, .min() for the smallest unit (satoshis, wei) as a bigint, .symbol, and .toCurrency('usd') for fiat conversion. Pending balance deltas can be negative.
Supported networks
| Network | cg.networks.* | Family |
|---|---|---|
| Bitcoin | bitcoin | UTXO |
| Bitcoin Testnet | bitcointestnet | UTXO |
| Litecoin | litecoin | UTXO |
| Dogecoin | dogecoin | UTXO |
| Bitcoin Cash | bitcoincash | UTXO |
| Ethereum | ethereum | EVM |
| Avalanche | avalanche | EVM |
Networks reached through a custom JSON-RPC endpoint (cg.networks.evmRpc()) do not provide events.
Key points
- No polling: events arrive as soon as a block is finalized (or, for pending events, as soon as a transaction is seen).
- One connection per network: every subscription of a network shares a single connection, opened with the first subscription and closed when the last one is removed. See Connection & errors.
- Automatic reconnection: if the connection drops, it is re-established and your subscriptions are restored without any action on your side.
- Typed callbacks: every event has its own TypeScript type, with camelCase fields and
Amountvalues. - Transaction confirmations use them too:
broadcasted.onConfirmed()is notified through these events, so it fires as soon as your transaction is included in a block. See Transfer funds.