QubicTypeScript

Decode event

decodeEvent — parse a raw BobLogEvent into a typed discriminated union.

decodeEvent takes a raw BobLogEvent from bob.subscription.subscribeLogs, decodes its binary data field, and returns a TypedEvent discriminated on logType.

decodeEvent(event)

import { decodeEvent } from "@qubic.org/events"

const typed = decodeEvent(rawEvent)
// typed.logType narrows typed.data to the matching shape

Parameters

NameTypeDescription
eventBobLogEventRaw log event from subscribeLogs or the archive client

Returns TypedEvent — a discriminated union with logType, tick, and data fields.

Throws EventDecodeError — when event.data is not a valid base64 string, the payload is too short for the declared logType, or the logType is unknown.


Narrowing with a switch

Switch on typed.logType to access the correctly typed data field. TypeScript narrows data in each branch.

import { decodeEvent, LOG_TYPE } from "@qubic.org/events"
import { EventDecodeError } from "@qubic.org/events"

for await (const event of bob.subscription.subscribeLogs({ identity })) {
  if (event.isCatchUp) continue

  let typed
  try {
    typed = decodeEvent(event.data)
  } catch (e) {
    if (e instanceof EventDecodeError) {
      console.warn("Malformed event at tick", event.data.tick, e.message)
      continue
    }
    throw e
  }

  switch (typed.logType) {
    case LOG_TYPE.QU_TRANSFER: {
      const { source, destination, amount } = typed.data
      console.log(`${source} -> ${destination}: ${amount}n QU`)
      break
    }
    case LOG_TYPE.ASSET_ISSUANCE: {
      const { issuer, assetName, numberOfShares } = typed.data
      console.log(`Issued ${numberOfShares} shares of ${assetName} by ${issuer}`)
      break
    }
    case LOG_TYPE.ASSET_OWNERSHIP_CHANGE: {
      const { assetName, source, destination, numberOfShares } = typed.data
      console.log(`${assetName}: ${numberOfShares} shares ${source} -> ${destination}`)
      break
    }
    case LOG_TYPE.CONTRACT_ERROR_MESSAGE: {
      console.error(`Contract ${typed.data.contractIndex} error, type ${typed.data.contractMessageType}`)
      break
    }
    case LOG_TYPE.BURNING: {
      console.log(`${typed.data.amount}n QU burned from ${typed.data.source}`)
      break
    }
    default:
      console.log("Unhandled log type:", typed.logType)
  }
}

TypedEvent shape

All variants share logType and tick. The data field varies by type.

type TypedEvent =
  | { logType: 0;   tick: number; data: QuTransferData }
  | { logType: 1;   tick: number; data: AssetIssuanceData }
  | { logType: 2;   tick: number; data: AssetOwnershipChangeData }
  | { logType: 3;   tick: number; data: AssetPossessionChangeData }
  | { logType: 4;   tick: number; data: SmartContractMessageData }  // error
  | { logType: 5;   tick: number; data: SmartContractMessageData }  // warning
  | { logType: 6;   tick: number; data: SmartContractMessageData }  // info
  | { logType: 7;   tick: number; data: SmartContractMessageData }  // debug
  | { logType: 8;   tick: number; data: BurningData }
  | { logType: 9;   tick: number; data: DustBurningData }
  | { logType: 10;  tick: number; data: SpectrumStatsData }
  | { logType: 11;  tick: number; data: AssetOwnershipManagingContractChangeData }
  | { logType: 12;  tick: number; data: AssetPossessionManagingContractChangeData }
  | { logType: 13;  tick: number; data: ContractReserveDeductionData }
  | { logType: 14;  tick: number; data: OracleQueryStatusData }
  | { logType: 15;  tick: number; data: OracleSubscriberLogMessageData }
  | { logType: 255; tick: number; data: Uint8Array }  // CUSTOM_MESSAGE

Data shapes by log type

QU_TRANSFER (0)

typed.data.source       // Identity — sender
typed.data.destination  // Identity — recipient
typed.data.amount       // bigint — QU amount

ASSET_ISSUANCE (1)

typed.data.issuer                // Identity
typed.data.assetName             // string
typed.data.numberOfShares        // bigint
typed.data.managingContractIndex // number
typed.data.numberOfDecimalPlaces // number
typed.data.unitOfMeasurement     // string

ASSET_OWNERSHIP_CHANGE (2) / ASSET_POSSESSION_CHANGE (3)

typed.data.source                // Identity — previous holder
typed.data.destination           // Identity — new holder
typed.data.issuer                // Identity
typed.data.assetName             // string
typed.data.numberOfShares        // bigint
typed.data.managingContractIndex // number
typed.data.numberOfDecimalPlaces // number
typed.data.unitOfMeasurement     // string

Contract messages (4–7)

CONTRACT_ERROR_MESSAGE, CONTRACT_WARNING_MESSAGE, CONTRACT_INFORMATION_MESSAGE, CONTRACT_DEBUG_MESSAGE share the same shape:

typed.data.contractIndex        // number — which contract emitted this
typed.data.contractMessageType  // number — message subtype defined by the contract

BURNING (8)

typed.data.source        // Identity — whose QU was burned
typed.data.amount        // bigint — amount burned
typed.data.contractIndex // number — contract that triggered the burn

DUST_BURNING (9)

typed.data.burns  // Array<{ source: Identity; amount: bigint }>

SPECTRUM_STATS (10)

typed.data.totalAmount           // bigint
typed.data.dustThresholdBurnAll  // bigint
typed.data.dustThresholdBurnHalf // bigint
typed.data.numberOfEntities      // number

ASSET_OWNERSHIP_MANAGING_CONTRACT_CHANGE (11)

typed.data.owner                      // Identity
typed.data.issuer                     // Identity
typed.data.sourceContractIndex        // number
typed.data.destinationContractIndex   // number
typed.data.numberOfShares             // bigint
typed.data.assetName                  // string

ASSET_POSSESSION_MANAGING_CONTRACT_CHANGE (12)

typed.data.possessor                  // Identity
typed.data.owner                      // Identity
typed.data.issuer                     // Identity
typed.data.sourceContractIndex        // number
typed.data.destinationContractIndex   // number
typed.data.numberOfShares             // bigint
typed.data.assetName                  // string

CONTRACT_RESERVE_DEDUCTION (13)

typed.data.deductedAmount  // bigint
typed.data.remainingAmount // bigint
typed.data.contractIndex   // number

ORACLE_QUERY_STATUS_CHANGE (14)

typed.data.queryingEntity  // Identity
typed.data.queryId         // bigint
typed.data.interfaceIndex  // number
typed.data.queryType       // number
typed.data.queryStatus     // number

ORACLE_SUBSCRIBER_LOG_MESSAGE (15)

typed.data.subscriptionId        // number
typed.data.interfaceIndex        // number
typed.data.contractIndex         // number
typed.data.periodMillis          // number
typed.data.firstQueryTimestamp   // bigint

CUSTOM_MESSAGE (255)

typed.data  // Uint8Array — contract-specific binary payload

Decode CUSTOM_MESSAGE payloads with decodePayload from @qubic.org/registry.


EventDecodeError

Thrown when a payload cannot be decoded.

import { EventDecodeError } from "@qubic.org/events"

try {
  const typed = decodeEvent(rawEvent)
} catch (e) {
  if (e instanceof EventDecodeError) {
    console.warn(`logType ${e.logType}: ${e.message}`)
  } else {
    throw e
  }
}

Properties

PropertyTypeDescription
logTypenumberThe log type that failed to decode
messagestringDescription of the failure

LOG_TYPE constants

import { LOG_TYPE } from "@qubic.org/events"

LOG_TYPE.QU_TRANSFER                               // 0
LOG_TYPE.ASSET_ISSUANCE                            // 1
LOG_TYPE.ASSET_OWNERSHIP_CHANGE                    // 2
LOG_TYPE.ASSET_POSSESSION_CHANGE                   // 3
LOG_TYPE.CONTRACT_ERROR_MESSAGE                    // 4
LOG_TYPE.CONTRACT_WARNING_MESSAGE                  // 5
LOG_TYPE.CONTRACT_INFORMATION_MESSAGE              // 6
LOG_TYPE.CONTRACT_DEBUG_MESSAGE                    // 7
LOG_TYPE.BURNING                                   // 8
LOG_TYPE.DUST_BURNING                              // 9
LOG_TYPE.SPECTRUM_STATS                            // 10
LOG_TYPE.ASSET_OWNERSHIP_MANAGING_CONTRACT_CHANGE  // 11
LOG_TYPE.ASSET_POSSESSION_MANAGING_CONTRACT_CHANGE // 12
LOG_TYPE.CONTRACT_RESERVE_DEDUCTION                // 13
LOG_TYPE.ORACLE_QUERY_STATUS_CHANGE                // 14
LOG_TYPE.ORACLE_SUBSCRIBER_LOG_MESSAGE             // 15
LOG_TYPE.CUSTOM_MESSAGE                            // 255

On this page