Skip to main content

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​

MethodWhat you receiveUTXOEVM
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​

Networkcg.networks.*Family
BitcoinbitcoinUTXO
Bitcoin TestnetbitcointestnetUTXO
LitecoinlitecoinUTXO
DogecoindogecoinUTXO
Bitcoin CashbitcoincashUTXO
EthereumethereumEVM
AvalancheavalancheEVM

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 Amount values.
  • 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.