QubicTypeScript
Packages

@qubic.org/events

Typed event decoding and chainable filter builder for Qubic smart contract log events.

Introduction

Raw logs vs typed events

A Bob event log ("eventLogs" subscription) delivers BobLogEvent objects with a numeric eventType and a base64-encoded binary eventData. You have to know the format of each type to do anything useful with it.

decodeEvent handles that decoding:

// Before: raw
event.eventType   // 0
event.eventData   // "AAAAAAAAAA..." (base64)

// After: typed
const typed = decodeEvent(event)
if (typed.logType === LOG_TYPE.QU_TRANSFER) {
  typed.data.source       // Identity
  typed.data.destination  // Identity
  typed.data.amount       // bigint
}

TypeScript narrows typed.data based on logType — no manual casting.

16 event types

@qubic.org/events covers all 16 Qubic log types plus CUSTOM_MESSAGE (255): QU transfers, asset events, contract messages, burn events, spectrum stats, oracle events, and more.

Filter builder

The eventFilter() builder is immutable and chainable — compose filters by identity, contract index, log type, and tick range, then pass the result to a subscription helper or use it manually.


Installation

bun add @qubic.org/events
npm install @qubic.org/events
pnpm add @qubic.org/events

API reference

PageWhat's covered
Decode eventdecodeEvent, LOG_TYPE constants, all typed event shapes
Event filtereventFilter() builder, subscribeQuTransfers, subscribeAssetEvents, subscribeContractLogs, subscribeAllEvents

All exports

import {
  decodeEvent,
  eventFilter,
  subscribeQuTransfers,
  subscribeAssetEvents,
  subscribeContractLogs,
  subscribeAllEvents,
  LOG_TYPE,
  EventDecodeError,
} from "@qubic.org/events"

Log types at a glance

IDNameKey data fields
0QU_TRANSFERsource, destination, amount
1ASSET_ISSUANCEissuer, assetName, numberOfShares
2ASSET_OWNERSHIP_CHANGEissuer, assetName, owner, newOwner
3ASSET_POSSESSION_CHANGEissuer, assetName, owner, newPossessor
4–7Contract messagescontractIndex, message
8BURNINGsourceId, amount
255CUSTOM_MESSAGEUint8Array

Examples

Decode and handle events inline

import { createBobClient } from "@qubic.org/bob"
import { decodeEvent, LOG_TYPE, EventDecodeError } from "@qubic.org/events"
import { toIdentity } from "@qubic.org/types"

const bob = createBobClient({ autoResubscribe: true })
await bob.connect()

const identity = toIdentity("CFBMEMZOIDEXQAUXYYSZIURADQLAPWPMNJXQSNVQZAHYVOPYUKKJBJUCTVJL")

bob.subscribe("eventLogs", identity, (events) => {
  for (const raw of events) {
    try {
      const typed = decodeEvent(raw)
      if (typed.logType === LOG_TYPE.QU_TRANSFER) {
        const { source, destination, amount } = typed.data
        console.log(`Transfer: ${amount}n QU from ${source} to ${destination}`)
      }
    } catch (e) {
      if (e instanceof EventDecodeError) console.warn("Skipping malformed event")
      else throw e
    }
  }
})

Use a subscription helper with a filter

import { createBobClient } from "@qubic.org/bob"
import { subscribeQuTransfers, eventFilter } from "@qubic.org/events"
import { toIdentity } from "@qubic.org/types"

const bob = createBobClient({ autoResubscribe: true })
await bob.connect()

const identity = toIdentity("CFBMEMZOIDEXQAUXYYSZIURADQLAPWPMNJXQSNVQZAHYVOPYUKKJBJUCTVJL")
const filter   = eventFilter().fromTick(25_000_000).build()

const unsub = subscribeQuTransfers(bob, identity, (transfer, meta) => {
  if (meta.isCatchUp) return
  const direction = transfer.data.source === identity ? "OUT" : "IN"
  console.log(`[${direction}] ${transfer.data.amount}n QU at tick ${transfer.tick}`)
}, filter)

// Later
unsub()

Compose a multi-criteria filter

import { eventFilter, LOG_TYPE } from "@qubic.org/events"
import { toIdentity } from "@qubic.org/types"

const filter = eventFilter()
  .forIdentity(toIdentity("CFBMEMZOIDEX..."))
  .ofTypes(LOG_TYPE.QU_TRANSFER, LOG_TYPE.BURNING)
  .fromTick(25_000_000)
  .toTick(26_000_000)
  .build()

On this page