> ## Documentation Index
> Fetch the complete documentation index at: https://hypernode-docs.polynode.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Format

> Structure of every event delivered by hypernode

## Two consensus layers

hypernode merges two data sources into one stream. Every event is tagged with its consensus state:

| Layer             | `consensus`   | What you see                                                  | Latency                  |
| ----------------- | ------------- | ------------------------------------------------------------- | ------------------------ |
| **Pre-consensus** | `"pre"`       | Cancel and modify actions before block commit                 | \~1s ahead of public API |
| **Confirmed**     | `"confirmed"` | Every order, fill, cancellation, rejection after block commit | \~0.5s behind live       |

Pre-consensus events are raw user-submitted actions intercepted from the gossip protocol before validators commit them. Confirmed events are the validator output after matching, filling, or rejecting.

## Event structure

```json theme={null}
{
  "block": 70852325,
  "timestamp": 1776147484247,
  "type": "cancel",
  "consensus": "pre",
  "user": "0x31ca8395cf837de08b24da3f660e77761dfb974b",
  "asset": "ALGO",
  "asset_id": 158,
  "data": {
    "cancels": [
      {"asset": 158, "oid": 380721371885}
    ]
  },
  "network": "mainnet"
}
```

## Fields

| Field       | Type   | Description                                                                                                 |
| ----------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| `type`      | string | Event type (see table below)                                                                                |
| `consensus` | string | `"pre"` (gossip) or `"confirmed"` (node)                                                                    |
| `timestamp` | number | Unix milliseconds                                                                                           |
| `block`     | number | L1 block number. Populated for pre-consensus events; `0` for confirmed events                               |
| `user`      | string | Wallet address                                                                                              |
| `asset`     | string | Human-readable asset name. Absent on `scheduleCancel` and `setReferrer`                                     |
| `asset_id`  | number | Numeric asset identifier. Present on pre-consensus events; may be absent on some confirmed events           |
| `data`      | any    | Event-specific payload. Usually an object, but a number for `scheduleCancel` and a string for `setReferrer` |
| `network`   | string | `"mainnet"` or `"testnet"`                                                                                  |

## Event types

### Confirmed events

These appear after the validator processes the action. Every order placed on HyperLiquid produces one of these:

| Type                      | Description                                         | Key data fields                                            |
| ------------------------- | --------------------------------------------------- | ---------------------------------------------------------- |
| `order`                   | New resting limit order (`data.status` is `"open"`) | coin, side, px, sz, oid, tif                               |
| `order_filled`            | Order filled immediately                            | coin, side, px, sz, oid                                    |
| `order_canceled`          | Order was canceled                                  | coin, side, px, sz, oid                                    |
| `order_rejected`          | Order rejected (see rejection reasons below)        | coin, side, px, sz, status                                 |
| `fill`                    | Trade execution                                     | coin, side (A/B), px, sz, dir, closedPnl, fee, liquidation |
| `triggered`               | Trigger/stop order activated (rare)                 | coin, side, px, sz                                         |
| `siblingFilledCanceled`   | Sibling order canceled due to fill (rare)           | coin, side, px, sz, oid                                    |
| `perpMaxPositionRejected` | Rejected due to max position limit (rare)           | coin, side, px, sz                                         |

<Note>
  The `"order"` type name covers new resting orders where `data.status` is `"open"`. There is no separate `order_open` type on the wire. To identify new resting orders, filter for `"order"` and check `data.status === "open"`.
</Note>

Rejection reasons in `data.status`: `badAloPxRejected`, `perpMarginRejected`, `insufficientSpotBalanceRejected`, `iocCancelRejected`, `reduceOnlyCanceled`, `reduceOnlyRejected`, `minTradeNtlRejected`, `selfTradeCanceled`.

### Pre-consensus events (from gossip protocol)

These arrive before the validator commits them to a block:

| Type             | Description                    | Key data fields                               |
| ---------------- | ------------------------------ | --------------------------------------------- |
| `cancel`         | Cancel by order ID             | cancels\[].asset, cancels\[].oid              |
| `cancelByCloid`  | Cancel by client order ID      | cancels\[].asset, cancels\[].cloid            |
| `batchModify`    | Modify existing orders         | modifies\[].oid, modifies\[].order.price/size |
| `scheduleCancel` | Dead man's switch              | `data` is a number (cancel timestamp)         |
| `setReferrer`    | Set referral code              | `data` is a string (referral code)            |
| `evmRawTx`       | Pre-block HyperEVM transaction | `data` (raw RLP-encoded signed tx hex string) |

## Confirmed order example

```json theme={null}
{
  "block": 0,
  "timestamp": 1776147483883,
  "type": "order",
  "consensus": "confirmed",
  "user": "0xfc667adba8d4e79a22cac8e8f6d2a5b5c17cfa94",
  "asset": "BTC",
  "data": {
    "status": "open",
    "coin": "BTC",
    "side": "B",
    "px": "74400.0",
    "sz": "0.04158",
    "oid": 380721383669,
    "orderType": "Limit",
    "tif": "Alo",
    "reduceOnly": false,
    "cloid": "0x000000334e47524d534c363834483736",
    "hash": "0x9d660b786cd389ac9edf04391b7dd901...",
    "builder": null,
    "origSz": "0.04158"
  },
  "network": "mainnet"
}
```

## Fill example

```json theme={null}
{
  "block": 0,
  "timestamp": 1776147483883,
  "type": "fill",
  "consensus": "confirmed",
  "user": "0x9690bcfc16394e2bd25b00e83d6b06c9ab3f5de5",
  "asset": "HYPE",
  "data": {
    "coin": "HYPE",
    "side": "B",
    "px": "22.608",
    "sz": "442.0",
    "dir": "Close Short",
    "closedPnl": "0.920686",
    "fee": "0.035973",
    "feeToken": "USDC",
    "oid": 380721384070,
    "tid": 910601406,
    "hash": "0xa9a32c7c2b7fb452ab1c...",
    "crossed": true,
    "builder": null,
    "builderFee": null,
    "liquidation": null
  },
  "network": "mainnet"
}
```

### Fill `dir` field values

| Value          | Meaning                             |
| -------------- | ----------------------------------- |
| `Open Long`    | New long position opened            |
| `Open Short`   | New short position opened           |
| `Close Long`   | Existing long position closed       |
| `Close Short`  | Existing short position closed      |
| `Long > Short` | Position flipped from long to short |
| `Short > Long` | Position flipped from short to long |
| `Buy` / `Sell` | Spot market fills                   |

The `side` field is separate: `B` = bid (buy order), `A` = ask (sell order).

## Liquidation fill example

<Warning>
  The `data.liquidation` field is **always present** on fill events. It is `null` when the fill is not part of a liquidation, and an object when it is. Do NOT check `"liquidation" in data` — that will be true for every fill. Check `data.liquidation !== null` instead.
</Warning>

Liquidation fills carry a populated `data.liquidation` object in addition to the standard fill fields. Use the `liquidations_only` filter to subscribe to only these events.

```json theme={null}
{
  "block": 0,
  "timestamp": 1776147612530,
  "type": "fill",
  "consensus": "confirmed",
  "user": "0xf27f22d0988f958837c4393284297377a00387ed",
  "asset": "SUI",
  "data": {
    "coin": "SUI",
    "side": "A",
    "px": "88.588",
    "sz": "142.0",
    "dir": "Close Long",
    "closedPnl": "-123.45",
    "fee": "0.0012",
    "feeToken": "USDC",
    "oid": 381234567890,
    "tid": 912345678,
    "hash": "0x3a4b5c...",
    "crossed": true,
    "liquidation": {
      "liquidatedUser": "0xf27f22d0988f958837c4393284297377a00387ed",
      "markPx": "88.588",
      "method": "market"
    }
  },
  "network": "mainnet"
}
```

Both sides of a liquidation (the liquidated user and the liquidator) appear as separate fill events with the same `tid` and `hash`. Correlate them using these shared fields to see the full liquidation flow.

**Liquidation object fields:**

| Field            | Description                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| `liquidatedUser` | Address of the account being liquidated                                 |
| `markPx`         | Mark price at the moment of liquidation                                 |
| `method`         | Liquidation method (currently `"market"` for all observed liquidations) |

## evmRawTx example (pre-block HyperEVM)

Every HyperEVM smart contract transaction appears as an `evmRawTx` event before it is included in a block. The `data` field is a hex string containing the full EIP-2718 envelope: a 1-byte tx type prefix followed by RLP-encoded transaction fields. There are **no top-level decoded fields** — you decode the hex to extract `to`, `calldata`, `chainId`, `gas`, etc.

```json theme={null}
{
  "block": 70861403,
  "timestamp": 1776225421823,
  "type": "evmRawTx",
  "consensus": "pre",
  "user": "0x000000362b9ddd0000000000333ce9b04c000000",
  "data": "02f8d48203e782071084b2d05e0085746a52...",
  "network": "mainnet"
}
```

<Note>
  The `user` field on `evmRawTx` events is a gossip internal identifier, not the transaction sender. To get the real sender, you must recover it from the signature during decoding.
</Note>

### Decoding `data` (Python)

The hex starts with the EIP-2718 tx type byte (`0x02` for EIP-1559). Everything after that is RLP:

```python theme={null}
import rlp
from eth_hash.auto import keccak

def decode_evm_raw_tx(hex_data: str) -> dict:
    raw = bytes.fromhex(hex_data)
    tx_type = raw[0]

    if tx_type == 0x02:
        # EIP-1559: [chainId, nonce, maxPrioFee, maxFee, gas, to, value, data, accessList, v, r, s]
        decoded = rlp.decode(raw[1:])
        return {
            "tx_hash": "0x" + keccak(raw).hex(),
            "tx_type": tx_type,
            "chain_id": int.from_bytes(decoded[0], "big"),
            "nonce": int.from_bytes(decoded[1], "big"),
            "max_fee_per_gas": int.from_bytes(decoded[3], "big"),
            "gas_limit": int.from_bytes(decoded[4], "big"),
            "to": "0x" + decoded[5].hex() if decoded[5] else None,
            "value": int.from_bytes(decoded[6], "big"),
            "calldata": decoded[7].hex(),
            "function_selector": "0x" + decoded[7][:4].hex() if len(decoded[7]) >= 4 else None,
        }
    else:
        raise ValueError(f"Unsupported tx type: {tx_type}")

# Usage
event = {"type": "evmRawTx", "data": "02f8d4820..."}
decoded = decode_evm_raw_tx(event["data"])
print(decoded["to"], decoded["function_selector"], decoded["chain_id"])
# 0xa4ea0e42eaab32e638703db88da1192fb42517f4 0xf3dc4762 999
```

All observed `evmRawTx` events have been EIP-1559 (tx type `0x02`). `chainId` is always `999` (HyperEVM mainnet). Measured lead time vs HyperLiquid's public RPC: 250ms to 3 seconds, averaging \~1 second.

See [EVM RPC](/rest/evm-rpc) for pointer-back info on why the HL RPC cannot serve this data.

## Pre-consensus cancel example

```json theme={null}
{
  "block": 70852325,
  "timestamp": 1776147484247,
  "type": "cancel",
  "consensus": "pre",
  "user": "0x31ca8395cf837de08b24da3f660e77761dfb974b",
  "asset": "ALGO",
  "asset_id": 158,
  "data": {
    "cancels": [
      {"asset": 158, "oid": 380721371885},
      {"asset": 158, "oid": 380721371886}
    ]
  },
  "network": "mainnet"
}
```

## Prediction market events

Events for HIP-4 outcome tokens include a `prediction` object in the data:

```json theme={null}
{
  "type": "order",
  "consensus": "confirmed",
  "asset": "#39890",
  "data": {
    "coin": "#39890",
    "side": "B",
    "px": "0.95",
    "sz": "200",
    "prediction": {
      "outcome_id": 3989,
      "side_index": 0,
      "asset_id": 100039890
    }
  }
}
```

Outcome token naming: `#{10 * outcome_id + side_index}`. See [Prediction Markets](/actions/prediction-markets) for details.

## Timestamp

Unix milliseconds. To convert:

```typescript theme={null}
const date = new Date(event.timestamp);
```

```python theme={null}
from datetime import datetime
dt = datetime.fromtimestamp(event["timestamp"] / 1000)
```
