diff --git a/content/api-reference/data/hypercore/concepts/markets-assets-and-dexes.mdx b/content/api-reference/data/hypercore/concepts/markets-assets-and-dexes.mdx index d22cb9b13..c185b84e7 100644 --- a/content/api-reference/data/hypercore/concepts/markets-assets-and-dexes.mdx +++ b/content/api-reference/data/hypercore/concepts/markets-assets-and-dexes.mdx @@ -7,4 +7,39 @@ description: "HyperCore private-preview documentation." # Markets, assets, and DEXes -A market identifier selects a tradeable HyperCore market. Asset and DEX semantics must be sourced from the native metadata contract. This private-preview uses `BTC` only as an illustrative market identifier. +## Market identifiers + +HyperCore coin strings are unambiguous across market types — the format tells you the type: + +| Form | Market type | Examples | +| --- | --- | --- | +| Readable name | Perpetual | `BTC`, `ETH`, `HYPE`, `SOL` | +| `@index` | Spot | `@1`, `@107`, `@142` | +| `#N` | Outcome market (HIP-4) | `#90` | +| `dex:name` | HIP-3 DEX market | `xyz:SP500` | + +There is no overlap between forms: `BTC` is always the perpetual, and spot BTC is a separate `@index` coin. `PURR/USDC` is a documented spot-market exception with a readable name. Discover `@index` mappings through the native `meta` and `spotMeta` metadata endpoints. + +Coin strings are case-sensitive. + +## Market types and DEXes + +The `marketTypes` filter accepts `perp`, `spot`, `outcome`, or `*`. Its default is `["perp"]`, and the default never grows: request new types explicitly or pass `["*"]` to opt in to future types automatically. + +The `dex` selector is `main` for Hyperliquid perpetuals or a named DEX for HIP-3 deployments. Outcome markets carry two coins per outcome, one per side. + +## Price aggregation + +| Parameter | Accepted values | Effect | +| --- | --- | --- | +| `nSigFigs` | `2`, `3`, `4`, `5` | Significant figures used to bucket price levels | +| `mantissa` | `2` or `5` | Mantissa step within the bucket. Valid only when `nSigFigs` is `5` | +| `nLevels` | `1`, `10`, `20` (default), `50` | Levels returned per side | + +Aggregation rounds bids down and asks up. With `nSigFigs: 5` and `mantissa: 2`, a bid of `70325` becomes `70324` and an ask of `70325` becomes `70326`. When aggregation parameters are omitted, each distinct price level is reported individually. + +A snapshot and the diffs applied to it must use identical aggregation parameters, or the resulting book is invalid. + +## Level semantics + +A price level reports total resting size and an order count — `px`, `sz`, and `n`. One level may represent many orders; `n` is how many. Level-aggregated streams expose no order IDs and no user addresses. Order-level detail requires `l4BookUpdates`. diff --git a/content/api-reference/data/hypercore/concepts/timestamps-cursors-and-replay.mdx b/content/api-reference/data/hypercore/concepts/timestamps-cursors-and-replay.mdx index cb24e9811..87b1438de 100644 --- a/content/api-reference/data/hypercore/concepts/timestamps-cursors-and-replay.mdx +++ b/content/api-reference/data/hypercore/concepts/timestamps-cursors-and-replay.mdx @@ -7,4 +7,49 @@ description: "HyperCore private-preview documentation." # Timestamps, cursors, and replay -The intended contract uses Unix milliseconds and opaque cursors. Cursors order events within a subscription and are not business identifiers. Replay begins after the supplied cursor. Clients store and return cursors unmodified because their format may change. +## Time + +All timestamps are Unix milliseconds. + +## Block height + +HyperCore produces a block roughly every 70 ms, and block numbers on the chain are sequential. + +Block-derived messages identify their source block by height or round. Whether a skipped height indicates a gap depends on the stream — block-complete streams expect continuity, change-driven streams do not. `bbo` emits only when the best bid or ask moves, and `l2Book` sends a market only when that market's book changed. Stateful diff streams use their own sequence fields for gap detection, described below. + +## Cursors + +On a replay-capable stream, a cursor marks a position in a subscription. It is opaque: store it and return it unmodified, because its format may change. Cursors are per subscription, not per connection — subscriptions sharing a connection resume independently, and replay resumes after the supplied cursor. `l2Book` and `bbo` carry no cursor. + +## Snapshot and diff streams + +The stateful market-data streams use two recovery models. This taxonomy does not classify event feeds such as fills, order updates, funding, and ledger events. + +**Complete-snapshot streams** — `l2Book` and `bbo`. Every message is self-contained and replaces prior state. There is no cursor and nothing to replay: after a disconnect, resubscribe and the next message re-establishes state. + +**Incremental streams** — `l2BookDiff`, `l4BookUpdates`, and `tpslUpdates`. Messages carry changes that chain onto previous state. These carry a cursor and support replay. + +> A message with `isSnapshot: true` replaces your local state. Any message without it is a diff that must chain onto your previous state. If continuity is broken, a fresh message with `isSnapshot: true` is pushed to you — there is no separate resynchronization message and no epoch to track. + +## Detecting gaps + +**Client-side detection**, on `l2BookDiff`: each per-market diff carries `seq` and `prev_seq`. If `prev_seq` does not match your current position for that market, you have a gap. + +**Server-side detection**, on `l4BookUpdates` and `tpslUpdates`: these carry no sequence fields. When continuity breaks, the service pushes a message with `isSnapshot: true` rather than requiring the client to detect the gap itself. A client on these streams has no gap-detection bookkeeping to implement. + +## Deduplicating on reconnect + +When resuming from a cursor, replayed and live messages may overlap. There is no single deduplication key across all streams. Deduplicate using the identity fields the stream actually documents: + +| Stream kind | Identity for deduplication | +| --- | --- | +| `l2BookDiff` | The per-market `seq` value | +| `l4BookUpdates`, `tpslUpdates` | No client-side deduplication is required — a pushed snapshot replaces state | +| Block streams | Block `height` or `round`, according to the API surface | +| Event streams | The identity fields documented by that stream, such as `(time, txIndex)` where both are present | + +A cursor identifies a resume position, not an event. It is not itself a deduplication key. + +## Replay depth + +Replay depth is bounded by node block-data retention, currently approximately 48 hours. For block-derived streams, gaps that replay cannot bridge can be recovered with the block lookup methods. diff --git a/content/api-reference/data/hypercore/historical-data/overview.mdx b/content/api-reference/data/hypercore/historical-data/overview.mdx index f2b2ea9a5..b859c0a75 100644 --- a/content/api-reference/data/hypercore/historical-data/overview.mdx +++ b/content/api-reference/data/hypercore/historical-data/overview.mdx @@ -7,6 +7,8 @@ description: "HyperCore private-preview documentation." # Historical data -HyperCore is designed for deep historical coverage. Replay, recovery, corrections, and bulk export are first-class capabilities; exact coverage and retention will be published as the service is finalized. +HyperCore is designed for deep historical coverage. Replay, recovery, corrections, and bulk export are first-class capabilities. + +Replay depth is bounded by node block-data retention, currently approximately 48 hours. For block-derived streams, gaps that replay cannot bridge can be recovered with the block lookup methods. Indexed historical APIs and bulk export are separate surfaces, and coverage varies by dataset. Existing native-compatible `/info` reads are available through the existing Hyperliquid endpoint and are node-bound in depth. Planned indexed historical APIs are a separate HyperCore product surface for deeper querying and export. Raw bulk exports are not equivalent to queryable API depth. Availability may differ by dataset and access mode. diff --git a/content/api-reference/data/hypercore/overview.mdx b/content/api-reference/data/hypercore/overview.mdx index 0ebc6ce60..5a3a8c045 100644 --- a/content/api-reference/data/hypercore/overview.mdx +++ b/content/api-reference/data/hypercore/overview.mdx @@ -16,7 +16,7 @@ HyperCore brings together real-time market and account events, native-compatible Subscribe to real-time exchange and account events. - Consume block and order-book streams through the intended RPC service. + Consume block and order-book streams through the gRPC service. Use native-compatible and enriched read operations. @@ -37,6 +37,24 @@ HyperCore brings together real-time market and account events, native-compatible | Block lookup and bounded backfill | JSON-RPC | | Deep historical analysis and export | Historical APIs | -## Contract notation +## Connection details Connection details are provided for private-preview access. + +## Common tasks + +| I want to… | Use | +| --- | --- | +| Watch deposits, withdrawals, and transfers for an address | [userNonFundingLedgerUpdates](/docs/chains/websockets/hypercore/streams/user-non-funding-ledger-updates) | +| Watch ledger activity across all addresses | [allUserNonFundingLedgerUpdates](/docs/chains/websockets/hypercore/streams/all-user-non-funding-ledger-updates) | +| Track funding payments | [funding rates](/docs/chains/websockets/hypercore/streams/funding-rates) | +| Display an order book | [l2Book](/docs/chains/websockets/hypercore/streams/l2-book) | +| Maintain a live order book efficiently | [l2BookDiff](/docs/chains/websockets/hypercore/streams/l2-book-diff) | +| Track prices and spreads only | [bbo](/docs/chains/websockets/hypercore/streams/bbo) | +| Analyze order-level depth and queue position | [l4BookUpdates](/docs/chains/websockets/hypercore/streams/l4-book-updates) | +| Monitor stop and take-profit orders | [tpslUpdates](/docs/chains/websockets/hypercore/streams/tpsl-updates) | +| Watch fills for an address | [userFills](/docs/chains/websockets/hypercore/streams/user-fills) | +| Index every block | [StreamBlocks](/docs/chains/hypercore-grpc/api-reference/stream-blocks) | +| Look up a single block | [hl_getBlock](/docs/chains/hyperliquid/hypercore/json-rpc/overview) | +| Backfill a block range after a gap | [hl_getBatchBlocks](/docs/chains/hyperliquid/hypercore/json-rpc/overview) | +| Read account state on demand | [REST reference](/docs/data/hypercore/rest-api) | diff --git a/content/api-reference/hypercore-grpc/overview.mdx b/content/api-reference/hypercore-grpc/overview.mdx index 3595a0c8d..dc2618f58 100644 --- a/content/api-reference/hypercore-grpc/overview.mdx +++ b/content/api-reference/hypercore-grpc/overview.mdx @@ -7,10 +7,27 @@ description: "HyperCore private-preview documentation." # gRPC streaming -## API reference +HyperCore gRPC provides block streaming and order-book streaming at price-level, +top-of-book, and order-level detail, plus trigger-order updates. Connection details and +generated client configuration will be published as the service is finalized. -This preview documents block and order-book gRPC streams. Connection details and generated client configuration will be published as the service is finalized. [StreamBlocks](/docs/chains/hypercore-grpc/api-reference/stream-blocks) is the most fully specified stream today; the order-book streams remain earlier design proposals. +## Available streams + +| Stream | Delivers | +| --- | --- | +| [StreamBlocks](/docs/chains/hypercore-grpc/api-reference/stream-blocks) | Raw blocks, one message per block | +| [StreamL2Book](/docs/chains/hypercore-grpc/api-reference/stream-l2-book) | Aggregated price-level snapshots | +| [StreamL2BookDiff](/docs/chains/hypercore-grpc/api-reference/stream-l2-book-diff) | Incremental price-level changes | +| [StreamL4BookUpdates](/docs/chains/hypercore-grpc/api-reference/stream-l4-book-updates) | Per-order changes with queue position | +| [StreamBboBook](/docs/chains/hypercore-grpc/api-reference/stream-bbo-book) | Top-of-book best bid and offer | +| [StreamTpslUpdates](/docs/chains/hypercore-grpc/api-reference/stream-tpsl-updates) | Take-profit and stop-loss order lifecycle | ## Choosing a transport -WebSocket and gRPC can expose the same market data through different transports. Use [WebSocket streams](/docs/chains/websockets/hypercore) when integrating with the subscription envelope, and use [gRPC streams](/docs/chains/hypercore-grpc/getting-started/overview) when integrating with the RPC service definition. For L2 books, [l2Book](/docs/chains/websockets/hypercore/streams/l2-book) and [l2BookDiff](/docs/chains/websockets/hypercore/streams/l2-book-diff) describe complementary snapshot and diff representations. +WebSocket and gRPC can expose the same market data through different transports. Use +[WebSocket streams](/docs/chains/websockets/hypercore) when integrating with the +subscription envelope, and use [gRPC streams](/docs/chains/hypercore-grpc/getting-started/overview) +when integrating with the RPC service definition. For L2 books, +[l2Book](/docs/chains/websockets/hypercore/streams/l2-book) and +[l2BookDiff](/docs/chains/websockets/hypercore/streams/l2-book-diff) describe +complementary snapshot and diff representations. diff --git a/content/api-reference/hypercore-grpc/stream-bbo-book.mdx b/content/api-reference/hypercore-grpc/stream-bbo-book.mdx index e3efe5086..440a013fd 100644 --- a/content/api-reference/hypercore-grpc/stream-bbo-book.mdx +++ b/content/api-reference/hypercore-grpc/stream-bbo-book.mdx @@ -5,25 +5,72 @@ description: "HyperCore private-preview documentation." -# StreamBboBook +# Stream BBO book -## Intended RPC +`StreamBboBook` delivers the top-of-book best bid and offer when either side changes. +This is ideal for live price and spread displays, routing decisions, and applications +where full depth is wasted bandwidth. -`rpc StreamBboBook(StreamBboBookRequest) returns (stream BboBookEnvelope);` +> The contract below is proposed and will be confirmed before general availability. -Carries best-bid-and-offer book data. For the WebSocket representation, see [bbo](/docs/chains/websockets/hypercore/streams/bbo). +## Overview -## Intended message +* Emitted only when the best bid or the best ask changes for a market +* Top of book only — use `StreamL2Book` for depth +* A null side means there are no resting orders on that side +* Every message is complete, so there is nothing to replay -The envelope below is illustrative and non-binding: its field names, field numbers, scalar types, payload type names, and finality semantics remain provisional. It makes no wire-compatibility promise. +## Request structure ```proto -message BboBookEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - BboBookPayload best_bid_offer = 4; +message StreamBboBookRequest { + repeated string coins = 1; + repeated string market_types = 2; } ``` -The service will publish the request and payload message definitions. +### Coins + +**Field**: `coins` +**Type**: `repeated string` + +Markets to subscribe to. Empty means all markets. + +### Market types + +**Field**: `market_types` +**Type**: `repeated string` + +Accepted values are `perp`, `spot`, `outcome`, or `*`. The default is `["perp"]`, so +spot and outcome markets are not delivered unless requested. The default never grows: +add new market types explicitly, or pass `["*"]` to opt in to future types automatically. +This field is rejected when combined with an explicit `coins` list. + +## Response structure + +```proto +message BboBookUpdate { + string coin = 1; + uint64 height = 2; + uint64 time = 3; + Level bid = 4; + Level ask = 5; +} +``` + +### Key fields + +**`coin`**: Market symbol. + +**`height`**: Block number. + +**`time`**: Block timestamp in milliseconds. + +**`bid`**: The best bid as a `Level` (`px`, `sz`, `n`). Null when there are no resting bids. + +**`ask`**: The best ask as a `Level` (`px`, `sz`, `n`). Null when there are no resting asks. + +## When to use BBO + +Use this stream for spread monitoring, price displays, routing decisions, and any case +where full depth is wasted bandwidth. diff --git a/content/api-reference/hypercore-grpc/stream-blocks.mdx b/content/api-reference/hypercore-grpc/stream-blocks.mdx index 1aed54776..b4bc04321 100644 --- a/content/api-reference/hypercore-grpc/stream-blocks.mdx +++ b/content/api-reference/hypercore-grpc/stream-blocks.mdx @@ -5,37 +5,106 @@ description: "HyperCore private-preview documentation." -# StreamBlocks +# Stream blocks -## What the stream carries +`StreamBlocks` delivers raw HyperCore blocks as they are produced — every signed action +the block contained, together with its execution results. This is ideal for full-chain +indexers, action and response analysis, deposit and transfer monitoring, and +reconciliation against your own records. -StreamBlocks is intended to carry block data for full-chain indexing, action and response analysis, deposit and transfer monitoring, and reconciliation. `round` identifies a block, and `parent_round` links it to its predecessor. See [raw and normalized HyperCore blocks](/docs/chains/hyperliquid/hypercore/concepts/raw-and-normalized-blocks) for the payload structure. +> The contract below is proposed and will be confirmed before general availability. -## Intended RPC +## Overview -`rpc StreamBlocks(StreamBlocksRequest) returns (stream BlockEnvelope);` +HyperCore produces a block roughly every 70 ms, and block numbers increment by exactly +one. The stream reflects that directly: -The current request sketch is illustrative and pending engineering confirmation. It proposes a starting position, an optional cursor, and inclusion controls for commands, actions, events, and fills. These dimensions are not an approved request contract. +* One message per block, in order, including blocks with no activity +* Block number is the stream sequence — there is no separate sequence counter to track +* A missing block number is therefore an unambiguous gap +* Blocks are delivered as passthrough — the raw block, not a normalized projection -## Intended message +Because the stream is dense, gap detection needs no heartbeat and no bookkeeping beyond +remembering the last block you processed. -> The envelope below is illustrative and non-binding. Its field names, field numbers, scalar types, payload type names, and semantics are provisional; it establishes no wire compatibility. +## Request structure + +```proto +message StreamBlocksRequest { + optional uint64 start_height = 1; + string cursor = 2; +} +``` + +### Start height + +**Field**: `start_height` +**Type**: `uint64` + +Block number to begin streaming from. Omit to start from the current head. + +### Cursor + +**Field**: `cursor` +**Type**: `string` + +Resume token from a previous session. Opaque — store it and return it unmodified. +Takes precedence over `start_height` when both are supplied. + +## Response structure ```proto message BlockEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - BlockData block = 4; + uint64 height = 1; + string cursor = 2; + BlockData block = 3; } ``` -The exact request, payload, and `.proto` definitions will be published with the service. +### Key fields + +**`height`**: Block number and stream sequence. Compare it with the last processed block +to detect a gap. + +**`cursor`**: Resume position for this message. Persist it after processing. + +**`block`**: The raw block. + +## Block contents + +| Field | Description | +| --- | --- | +| `abci_block.round` | Block number. Use this as the block identifier. | +| `abci_block.parent_round` | Preceding block number, for verifying continuity. | +| `abci_block.time` | Block timestamp. | +| `abci_block.proposer` | Validator that proposed the block. | +| `abci_block.hardfork` | Protocol version and the round it activated. | +| `abci_block.signed_action_bundles` | Signed actions in the block, each with signature, action type, nonce, and vault address, plus builder attribution where present. | +| `resps` | Execution result per action, keyed by transaction hash, with the acting user and an ok or error status. | + +See [raw and normalized HyperCore blocks](/docs/chains/hyperliquid/hypercore/concepts/raw-and-normalized-blocks) +for how these relate to the normalized objects returned by the JSON-RPC block methods. + +## Recovering from a gap + +1. Track the block number of the last message you processed. +2. On reconnect, send that number plus one as `start_height`, or send your stored `cursor`. +3. If `parent_round` does not match your last processed block, fetch the missing range + with [`hl_getBatchBlocks`](/docs/chains/hyperliquid/hypercore/json-rpc/overview) + and reconcile before resuming. + +Replay depth is bounded by node block-data retention, currently approximately 48 hours. For block-derived streams, gaps that replay cannot bridge can be recovered with the block lookup methods. -## Workflow +## Stream vs block lookup -Use this as a design pattern: backfill an initial range with `hl_getBlock` or `hl_getBatchBlocks`, consume the live stream, use bounded block lookup to repair a gap, and reconcile against historical lookups when needed. The [JSON-RPC block-method overview](/docs/chains/hyperliquid/hypercore/json-rpc/overview) describes those lookup methods. This does not establish a retention guarantee. +| | StreamBlocks | JSON-RPC block methods | +| --- | --- | --- | +| **Delivery** | Push, one message per block | Request/response | +| **Latency** | Lowest available | Higher — per-call round trip | +| **Range** | Live, plus bounded replay | Bounded historical lookup | +| **Use case** | Continuous indexing | Backfill, gap repair, spot checks | ## Message size -Raw HyperCore blocks can be large. Clients should configure receive limits and processing queues appropriate to the service limits published at launch. +Raw HyperCore blocks can be large, and high-activity blocks substantially more so. +Configure your client's maximum receive size and processing queues accordingly. diff --git a/content/api-reference/hypercore-grpc/stream-l2-book-diff.mdx b/content/api-reference/hypercore-grpc/stream-l2-book-diff.mdx index 7c5d1acf5..b04405fed 100644 --- a/content/api-reference/hypercore-grpc/stream-l2-book-diff.mdx +++ b/content/api-reference/hypercore-grpc/stream-l2-book-diff.mdx @@ -5,25 +5,151 @@ description: "HyperCore private-preview documentation." -# StreamL2BookDiff +# Stream L2 book diff -## Intended RPC +`StreamL2BookDiff` delivers incremental price-level changes so that a client can maintain +a local order book at a fraction of snapshot bandwidth. This is ideal for +latency-sensitive consumers that need continuous book state. -`rpc StreamL2BookDiff(StreamL2BookDiffRequest) returns (stream L2BookDiffEnvelope);` +> The contract below is proposed and will be confirmed before general availability. -Carries L2 order-book diffs. [StreamL2Book](/docs/chains/hypercore-grpc/api-reference/stream-l2-book) is the corresponding snapshot stream. For the WebSocket representation, see [l2BookDiff](/docs/chains/websockets/hypercore/streams/l2-book-diff). +## Overview -## Intended message +* Each message contains changes for the markets that changed in its block +* The initial snapshot supplies current levels unless `skip_initial_snapshot` is set +* Diffs carry absolute level sizes, not size deltas +* Per-market sequence values identify continuity for each local book -This draft shape is non-binding. Field names, field numbers, scalar types, payload type names, and finality semantics are all provisional; no wire compatibility follows from this sketch. +## Request structure ```proto -message L2BookDiffEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - L2BookDiffPayload diff = 4; +message StreamL2BookDiffRequest { + repeated string coins = 1; + repeated string market_types = 2; + uint32 n_levels = 3; + uint32 n_sig_figs = 4; + uint64 mantissa = 5; + bool skip_initial_snapshot = 6; } ``` -Request and payload message definitions will be published with the service. +### Coins + +**Field**: `coins` +**Type**: `repeated string` + +Markets to subscribe to. Empty means all markets. + +### Market types + +**Field**: `market_types` +**Type**: `repeated string` + +Accepted values are `perp`, `spot`, `outcome`, or `*`. The default is `["perp"]`, so +spot and outcome markets are not delivered unless requested. The default never grows: +add new market types explicitly, or pass `["*"]` to opt in to future types automatically. +This field is rejected when combined with an explicit `coins` list. + +### Levels + +**Field**: `n_levels` +**Type**: `uint32` + +Levels per side: `1`, `10`, `20` (default), or `50`. + +### Significant figures + +**Field**: `n_sig_figs` +**Type**: `uint32` + +Accepted values are `2`, `3`, `4`, or `5`. + +### Mantissa + +**Field**: `mantissa` +**Type**: `uint64` + +Accepted values are `2` or `5`, and this field is valid only when `n_sig_figs = 5`. +Aggregation rounds bids down and asks up. With `n_sig_figs = 5` and `mantissa = 2`, a +bid of `70325` becomes `70324` and an ask of `70325` becomes `70326`. + +### Skip initial snapshot + +**Field**: `skip_initial_snapshot` +**Type**: `bool` + +Default: `false`. When false, the first message for each market carries that market's +current levels as a snapshot. Set true only if you already hold a compatible snapshot +and position. + +## Response structure + +```proto +message L2BookDiffUpdate { + uint64 height = 1; + uint64 time = 2; + bool snapshot = 3; + string cursor = 4; + repeated CoinDiff diffs = 5; +} + +message CoinDiff { + string coin = 1; + uint64 seq = 2; + uint64 prev_seq = 3; + bool snapshot = 4; + repeated Level bids = 5; + repeated Level asks = 6; +} +``` + +### Key fields + +**`height`**: Block number. + +**`time`**: Block timestamp in milliseconds. + +**`snapshot`**: True when this message carries initial levels for any market. + +**`cursor`**: Resume position. Persist after applying. + +**`diffs`**: One entry per market that changed in this block. + +**`seq`** / **`prev_seq`**: Per-market sequence and its predecessor. If `prev_seq` does +not match your current position for that market, you have a gap. + +**`bids`** / **`asks`**: Changed levels only. + +## Applying diffs + +* A level with `sz` of `"0"` has been removed from the book. Delete that price. +* Any other level is an upsert: set that price to the given `sz` and `n`. +* Sizes are absolute — the level's new total, not a delta. +* Levels not present in a diff are unchanged. +* The snapshot and all subsequent diffs must use identical `n_levels`, `n_sig_figs`, and + `mantissa`. Applying diffs from one aggregation setting to a snapshot taken at another + produces an invalid book. + +## Recovery + +A message flagged as a snapshot replaces your local state. Anything else is a diff that +must chain onto your previous block. + +If continuity is broken, a fresh snapshot is pushed to you. There is no separate +resynchronization message to handle and no epoch to track — receiving a snapshot is the +signal to discard local state and adopt it. + +1. After applying each message, persist `cursor` and the per-market `seq`. +2. On reconnect, send `cursor`. +3. Check `prev_seq` against your position for each market on every diff. +4. If a snapshot arrives for a market, discard your book for that market and adopt it. + +## Choosing a book stream + +| | StreamL2Book | StreamL2BookDiff | StreamL4BookUpdates | +| --- | --- | --- | --- | +| **Payload** | Full snapshot per block | Changed levels only | Per-order changes | +| **Client state** | None required | Maintains a local book | Maintains a local book | +| **Bandwidth** | Highest | Low | Moderate | +| **Detail** | Aggregated levels | Aggregated levels | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Market making, queue analysis | diff --git a/content/api-reference/hypercore-grpc/stream-l2-book.mdx b/content/api-reference/hypercore-grpc/stream-l2-book.mdx index 4b28d60e9..ba53727dc 100644 --- a/content/api-reference/hypercore-grpc/stream-l2-book.mdx +++ b/content/api-reference/hypercore-grpc/stream-l2-book.mdx @@ -5,25 +5,116 @@ description: "HyperCore private-preview documentation." -# StreamL2Book +# Stream L2 book -## Intended RPC +`StreamL2Book` delivers aggregated price-level order book snapshots, one per block for +each market whose book changed. This is ideal for order book displays, depth analysis, +pricing, and applications that need current book state without maintaining it +incrementally. -`rpc StreamL2Book(StreamL2BookRequest) returns (stream L2BookEnvelope);` +> The contract below is proposed and will be confirmed before general availability. -Carries L2 order-book snapshots. For the WebSocket representation, see [l2Book](/docs/chains/websockets/hypercore/streams/l2-book). Use [StreamL2BookDiff](/docs/chains/hypercore-grpc/api-reference/stream-l2-book-diff) for the corresponding diff stream. +## Overview -## Intended message +* Every message is a complete snapshot for the market it names +* A market is sent only when its book changed in that block +* Levels are aggregated: a single level can represent many orders, and `n` reports how many +* Order IDs and user addresses are not exposed on this stream -This is a non-binding illustration: field names, field numbers, scalar types, payload type names, and finality semantics are provisional. It does not imply wire compatibility. +## Request structure ```proto -message L2BookEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - L2BookSnapshot snapshot = 4; +message StreamL2BookRequest { + repeated string coins = 1; + repeated string market_types = 2; + uint32 n_levels = 3; + uint32 n_sig_figs = 4; + uint64 mantissa = 5; } ``` -The request and payload message definitions will be published with the service. +### Coins + +**Field**: `coins` +**Type**: `repeated string` + +Markets to subscribe to. Empty means all markets. + +### Market types + +**Field**: `market_types` +**Type**: `repeated string` + +Accepted values are `perp`, `spot`, `outcome`, or `*`. The default is `["perp"]`, so +spot and outcome markets are not delivered unless requested. The default never grows: +add new market types explicitly, or pass `["*"]` to opt in to future types automatically. +This field is rejected when combined with an explicit `coins` list. + +### Levels + +**Field**: `n_levels` +**Type**: `uint32` + +Levels per side: `1`, `10`, `20` (default), or `50`. + +### Significant figures + +**Field**: `n_sig_figs` +**Type**: `uint32` + +Accepted values are `2`, `3`, `4`, or `5`. + +### Mantissa + +**Field**: `mantissa` +**Type**: `uint64` + +Accepted values are `2` or `5`, and this field is valid only when `n_sig_figs = 5`. +Aggregation rounds bids down and asks up. With `n_sig_figs = 5` and `mantissa = 2`, a +bid of `70325` becomes `70324` and an ask of `70325` becomes `70326`. + +## Response structure + +```proto +message L2BookUpdate { + string coin = 1; + uint64 height = 2; + uint64 time = 3; + repeated Level bids = 4; + repeated Level asks = 5; +} + +message Level { + string px = 1; + string sz = 2; + uint32 n = 3; +} +``` + +### Key fields + +**`coin`**: Market symbol. + +**`height`**: Block number this snapshot reflects. + +**`time`**: Block timestamp in milliseconds. + +**`bids`**: Repeated `Level`, sorted descending by `px`. + +**`asks`**: Repeated `Level`, sorted ascending by `px`. + +**`px`**: Price, as a decimal string. + +**`sz`**: Total size resting at this price level, as a decimal string. + +**`n`**: Number of orders aggregated into this level. + +## Choosing a book stream + +| | StreamL2Book | StreamL2BookDiff | StreamL4BookUpdates | +| --- | --- | --- | --- | +| **Payload** | Full snapshot per block | Changed levels only | Per-order changes | +| **Client state** | None required | Maintains a local book | Maintains a local book | +| **Bandwidth** | Highest | Low | Moderate | +| **Detail** | Aggregated levels | Aggregated levels | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Market making, queue analysis | diff --git a/content/api-reference/hypercore-grpc/stream-l4-book-updates.mdx b/content/api-reference/hypercore-grpc/stream-l4-book-updates.mdx index dfb4d0c54..ff9968185 100644 --- a/content/api-reference/hypercore-grpc/stream-l4-book-updates.mdx +++ b/content/api-reference/hypercore-grpc/stream-l4-book-updates.mdx @@ -5,27 +5,122 @@ description: "HyperCore private-preview documentation." -# StreamL4BookUpdates +# Stream L4 book updates -The L4 delivery model is still being finalized. Candidate models are an initial snapshot followed by incremental updates, or update-only delivery. L4 volumes make a full snapshot per block impractical. +`StreamL4BookUpdates` delivers every individual order placed, resized, or removed, +including its position in the price-level queue. This is ideal for market making, +queue-position analysis, liquidity attribution, and reconstructing an exact book. -## Intended RPC +> The contract below is proposed and will be confirmed before general availability. -`rpc StreamL4BookUpdates(StreamL4BookUpdatesRequest) returns (stream L4BookUpdatesEnvelope);` +## Overview -Carries order-level book updates. For the WebSocket representation, see [l4BookUpdates](/docs/chains/websockets/hypercore/streams/l4-book-updates). [StreamL4Book](/docs/chains/hypercore-grpc/api-reference/stream-l4-book) is the full order-level stream. +* The first message after subscribing is a full snapshot: every resting order is delivered + as a `NEW` diff with `snapshot` set true +* `UPDATE` means the order's size changed, typically a partial fill +* `REMOVE` is terminal — the order was filled or cancelled +* Aggregating these orders by price yields an exact L2 view, so a single subscription can + serve both order-level and level-aggregated needs -## Intended message +## Request structure -Read this as a provisional, non-binding outline: field names, field numbers, scalar types, payload type names, and finality semantics can change, and the outline does not imply wire compatibility. +```proto +message StreamL4BookUpdatesRequest { + repeated string coins = 1; + repeated string market_types = 2; +} +``` + +### Coins + +**Field**: `coins` +**Type**: `repeated string` + +Markets to subscribe to. Empty means all markets. + +### Market types + +**Field**: `market_types` +**Type**: `repeated string` + +Accepted values are `perp`, `spot`, `outcome`, or `*`. The default is `["perp"]`, so +spot and outcome markets are not delivered unless requested. The default never grows: +add new market types explicitly, or pass `["*"]` to opt in to future types automatically. +This field is rejected when combined with an explicit `coins` list. + +## Response structure ```proto -message L4BookUpdatesEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - L4BookUpdatesPayload order_updates = 4; +message L4BookUpdatesUpdate { + uint64 height = 1; + uint64 time = 2; + bool snapshot = 3; + string cursor = 4; + repeated OrderDiff diffs = 5; +} + +message OrderDiff { + DiffType diff_type = 1; + string coin = 2; + uint64 oid = 3; + string user = 4; + string side = 5; + string px = 6; + string sz = 7; + optional uint64 insert_before = 8; +} + +enum DiffType { + DIFF_TYPE_NEW = 0; + DIFF_TYPE_UPDATE = 1; + DIFF_TYPE_REMOVE = 2; } ``` -The request and payload definitions will be published with the service. +### Key fields + +**`oid`**: Order ID, unique and stable for the life of the order. + +**`user`**: Address that placed the order. + +**`side`**: `B` for bid, `A` for ask. + +**`px`**: Limit price, as a decimal string. + +**`sz`**: Current size on `NEW` and `UPDATE`. Absent on `REMOVE`. + +**`insert_before`**: Queue placement. Insert this order immediately ahead of the resting +order with this ID at the same price level. Absent means append to the tail of the queue. +If the named order is no longer at that level, append to the tail. + +### Field presence by operation + +| Operation | Fields present | +| --- | --- | +| `NEW` | `coin`, `oid`, `user`, `side`, `px`, `sz`, and `insert_before` when applicable | +| `UPDATE` | `coin`, `oid`, `sz` | +| `REMOVE` | `coin`, `oid` | + +## Queue position + +`insert_before` reflects HyperCore's priority placement rules. It supplies the queue +position that makes order-level consumption useful beyond aggregated levels. + +## Recovery + +A message flagged as a snapshot replaces your local state. Anything else is a diff that +must chain onto your previous block. + +If continuity is broken, a fresh snapshot is pushed to you. There is no separate +resynchronization message to handle and no epoch to track — receiving a snapshot is the +signal to discard local state and adopt it. + +## Choosing a book stream + +| | StreamL2Book | StreamL2BookDiff | StreamL4BookUpdates | +| --- | --- | --- | --- | +| **Payload** | Full snapshot per block | Changed levels only | Per-order changes | +| **Client state** | None required | Maintains a local book | Maintains a local book | +| **Bandwidth** | Highest | Low | Moderate | +| **Detail** | Aggregated levels | Aggregated levels | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Market making, queue analysis | diff --git a/content/api-reference/hypercore-grpc/stream-l4-book.mdx b/content/api-reference/hypercore-grpc/stream-l4-book.mdx index c8304cdb8..10317934b 100644 --- a/content/api-reference/hypercore-grpc/stream-l4-book.mdx +++ b/content/api-reference/hypercore-grpc/stream-l4-book.mdx @@ -5,27 +5,8 @@ description: "HyperCore private-preview documentation." -# StreamL4Book +# Stream L4 book -The L4 delivery model is still being finalized. Candidate models are an initial snapshot followed by incremental updates, or update-only delivery. L4 volumes make a full snapshot per block impractical. +`StreamL4Book` is under evaluation. Consumers wanting order-level book data should use [StreamL4BookUpdates](/docs/chains/hypercore-grpc/api-reference/stream-l4-book-updates), which provides typed per-order diffs across multiple markets with queue-position information. This is ideal for consumers that need order-level book data. -## Intended RPC - -`rpc StreamL4Book(StreamL4BookRequest) returns (stream L4BookEnvelope);` - -Carries a full order-level book stream rather than an update stream. There is no WebSocket counterpart for this surface; [StreamL4BookUpdates](/docs/chains/hypercore-grpc/api-reference/stream-l4-book-updates) covers the update-oriented gRPC stream. - -## Intended message - -Treat this as a non-binding sketch only. Its field names, field numbers, scalar types, payload type names, and finality semantics are provisional, and it establishes no wire compatibility. - -```proto -message L4BookEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - L4BookSnapshot full_book = 4; -} -``` - -Request and payload message definitions will be published with the service. +> The contract below is proposed and will be confirmed before general availability. diff --git a/content/api-reference/hypercore-grpc/stream-tpsl-updates.mdx b/content/api-reference/hypercore-grpc/stream-tpsl-updates.mdx index 780adef3f..de67f4c85 100644 --- a/content/api-reference/hypercore-grpc/stream-tpsl-updates.mdx +++ b/content/api-reference/hypercore-grpc/stream-tpsl-updates.mdx @@ -5,25 +5,119 @@ description: "HyperCore private-preview documentation." -# StreamTpslUpdates +# Stream TP/SL updates -## Intended RPC +`StreamTpslUpdates` delivers the lifecycle of resting take-profit and stop-loss trigger +orders. This is ideal for trigger heatmaps, stop and liquidation monitoring, frontend +overlays, and alerting. -`rpc StreamTpslUpdates(StreamTpslUpdatesRequest) returns (stream TpslUpdatesEnvelope);` +> The contract below is proposed and will be confirmed before general availability. -Carries take-profit and stop-loss update data. For the WebSocket representation, see [tpslUpdates](/docs/chains/websockets/hypercore/streams/tpsl-updates). +## Overview -## Intended message +* The first message after subscribing is a snapshot of all open trigger orders, delivered + as `ADD` diffs with `snapshot` set true +* Trigger orders are immutable: a modified order appears as a `REMOVE` followed by an + `ADD` with a new `oid` +* A `REMOVE` is always terminal +* Perpetual markets only -This non-binding example is intentionally provisional: field names, field numbers, scalar types, payload type names, and finality semantics have not been fixed, and it implies no wire compatibility. +## Request structure ```proto -message TpslUpdatesEnvelope { - string cursor = 1; - uint64 sequence = 2; - bool is_final = 3; - TpslUpdatesPayload tpsl_updates = 4; +message StreamTpslUpdatesRequest { + repeated string coins = 1; } ``` -The service will publish request and payload message definitions. +### Coins + +**Field**: `coins` +**Type**: `repeated string` + +Trigger orders exist only on perpetual markets. Empty means all perpetual markets. + +## Response structure + +```proto +message TpslUpdatesUpdate { + uint64 height = 1; + uint64 time = 2; + bool snapshot = 3; + string cursor = 4; + repeated TpslOrderDiff diffs = 5; +} + +message TpslOrderDiff { + TpslDiffType diff_type = 1; + uint64 oid = 2; + string coin = 3; + string user = 4; + string side = 5; + string trigger_px = 6; + string limit_px = 7; + string sz = 8; + string trigger_condition = 9; + string order_type = 10; + bool is_position_tpsl = 11; + bool reduce_only = 12; + uint64 timestamp = 13; + string reason = 14; +} + +enum TpslDiffType { + TPSL_DIFF_TYPE_ADD = 0; + TPSL_DIFF_TYPE_REMOVE = 1; +} +``` + +### Key fields + +**`oid`**: Order ID. + +**`side`**: `B` for buy, `A` for sell. + +**`trigger_px`**: Price at which the order triggers. + +**`limit_px`**: Limit price applied once triggered. + +**`sz`**: Order size. `"0.0"` indicates a position-level TP/SL sized by the position +rather than a fixed quantity. + +**`trigger_condition`**: Human-readable condition, for example `Price above 50000`. + +**`order_type`**: For example `Stop Market`, `Take Profit Limit`. + +**`is_position_tpsl`**: True when the order is attached to a position rather than standing +alone. + +**`reduce_only`**: True when the order can only reduce a position. + +**`timestamp`**: Order creation time in milliseconds. + +**`reason`**: Present on `REMOVE` only. Why the order left the book. + +## Removal reasons + +| Reason | Meaning | +| --- | --- | +| `triggered` | Condition met; the order was placed on the book | +| `canceled` | Cancelled by the user | +| `reduceOnlyCanceled` | Reduce-only order cancelled because the position closed | +| `marginCanceled` | Cancelled due to insufficient margin | +| `rejected` | Rejected by the matching engine | +| `siblingFilledCanceled` | A paired TP/SL order triggered, cancelling this one | +| `liquidatedCanceled` | Cancelled because the position was liquidated | + +`reason` is informational — treat every `REMOVE` as terminal regardless of its value. New +reason values may appear as HyperCore adds order statuses, so do not branch on an exhaustive +set. + +## Recovery + +A message flagged as a snapshot replaces your local state. Anything else is a diff that +must chain onto your previous block. + +If continuity is broken, a fresh snapshot is pushed to you. There is no separate +resynchronization message to handle and no epoch to track — receiving a snapshot is the +signal to discard local state and adopt it. diff --git a/content/api-reference/hyperliquid/hypercore/concepts/blocks-and-finality.mdx b/content/api-reference/hyperliquid/hypercore/concepts/blocks-and-finality.mdx index f8974869d..ec070fe08 100644 --- a/content/api-reference/hyperliquid/hypercore/concepts/blocks-and-finality.mdx +++ b/content/api-reference/hyperliquid/hypercore/concepts/blocks-and-finality.mdx @@ -7,7 +7,12 @@ description: "HyperCore private-preview documentation." # Blocks and finality -HyperCore block data is modeled as normalized metadata plus raw commands, actions, events, and fills. Do not map these concepts to EVM transactions. The finality signal and correction policy remain service-finalization items. +* HyperCore orders blocks through HyperBFT consensus, producing a block roughly every 70 ms. +* Block numbers on the chain are sequential. +* The APIs use block number as both the block identifier and the ordering value. +* The stream envelopes carry no finality field. + +HyperCore uses exchange concepts — markets, orders, fills, and actions — rather than EVM transactions. ## Historical analysis diff --git a/content/api-reference/hyperliquid/hypercore/concepts/raw-and-normalized-blocks.mdx b/content/api-reference/hyperliquid/hypercore/concepts/raw-and-normalized-blocks.mdx index 1924ec367..619267f7c 100644 --- a/content/api-reference/hyperliquid/hypercore/concepts/raw-and-normalized-blocks.mdx +++ b/content/api-reference/hyperliquid/hypercore/concepts/raw-and-normalized-blocks.mdx @@ -7,18 +7,22 @@ description: "HyperCore private-preview documentation." # Raw and normalized HyperCore blocks -The Chain API keeps raw source material distinct from normalized block-oriented objects. It does not force EVM transaction terminology onto HyperCore. +The Chain API keeps raw source material distinct from normalized block-oriented objects. HyperCore uses exchange concepts — markets, orders, fills, and actions — rather than EVM transactions. ## Raw block structure | Field | Type | Description | | --- | --- | --- | | `abci_block.round` | integer | The block identifier. | -| `parent_round` | integer | Links to the preceding block. | -| `time` | value | Raw block time value. | -| `proposer` | value | Raw proposer value. | -| `hardfork` | object | Protocol version and activation round. | -| `signed_action_bundles` | array | Pairs of `[tx_hash, bundle]`. Each bundle carries signed actions, including signature, action type, nonce, vault address, and expiry, together with broadcaster and broadcaster nonce. | +| `abci_block.parent_round` | integer | Links to the preceding block. | +| `abci_block.time` | integer | Block timestamp in milliseconds. | +| `abci_block.proposer` | string | Address of the validator that proposed the block. | +| `abci_block.hardfork` | object | Protocol version and activation round. | +| `abci_block.signed_action_bundles` | array | Pairs of `[tx_hash, bundle]`. Each bundle carries signed actions, including signature, action type, nonce, vault address, and expiry, together with broadcaster and broadcaster nonce. | | `resps` | object | Execution results keyed by transaction hash. Each result includes a user address and an `ok` or `err` status. | +## Raw versus normalized + +The gRPC block stream exposes raw HyperCore block content. The JSON-RPC block methods return normalized block objects for lookup and bounded backfill. The two surfaces describe the same block data at different semantic levels. + For data-product queries over normalized historical material, see [historical data](/docs/data/hypercore/historical-data). diff --git a/content/api-reference/hyperliquid/hypercore/overview.mdx b/content/api-reference/hyperliquid/hypercore/overview.mdx index f97d5d0bd..00ee69c2f 100644 --- a/content/api-reference/hyperliquid/hypercore/overview.mdx +++ b/content/api-reference/hyperliquid/hypercore/overview.mdx @@ -7,10 +7,20 @@ description: "HyperCore private-preview documentation." # HyperCore Chain API -Use the HyperCore Chain API for protocol-level reads, raw blocks, block-oriented JSON-RPC methods, and chain-level streaming. It is the intended Chain tab entry point for Hyperliquid's native exchange engine. +Use the HyperCore Chain API for protocol-level reads, raw blocks, block-oriented JSON-RPC methods, and chain-level streaming. It is the Chain tab entry point for Hyperliquid's native exchange engine. For purpose-built market streams, enriched wallet and account data, and historical query products, see [the HyperCore Data API](/docs/data/hypercore/overview). +## Choosing a surface + +| Need | Use | +| --- | --- | +| Live block stream | [StreamBlocks](/docs/chains/hypercore-grpc/api-reference/stream-blocks) | +| Single block lookup | [hl_getBlock](/docs/chains/hyperliquid/hypercore/json-rpc/overview) | +| Bounded block backfill | [hl_getBatchBlocks](/docs/chains/hyperliquid/hypercore/json-rpc/overview) | +| Real-time market and account events | [WebSocket streams](/docs/chains/websockets/hypercore) | +| Native-compatible account reads | [REST reference](/docs/data/hypercore/rest-api) | + ## Included surfaces * Protocol and network concepts diff --git a/content/api-reference/websockets/hypercore/all-user-non-funding-ledger-updates.mdx b/content/api-reference/websockets/hypercore/all-user-non-funding-ledger-updates.mdx index 7ebfae051..1e09071c9 100644 --- a/content/api-reference/websockets/hypercore/all-user-non-funding-ledger-updates.mdx +++ b/content/api-reference/websockets/hypercore/all-user-non-funding-ledger-updates.mdx @@ -8,75 +8,39 @@ description: "HyperCore private-preview documentation." # allUserNonFundingLedgerUpdates stream ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "allUserNonFundingLedgerUpdates", - "eventTypes": [ - "deposit", - "transfer" - ] - } -} +{"method":"subscribe","subscription":{"type":"allUserNonFundingLedgerUpdates","eventTypes":["deposit","transfer"]}} ``` ## Acknowledgement + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "allUserNonFundingLedgerUpdates" - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"allUserNonFundingLedgerUpdates"}} ``` ## Event envelope ```json -{ - "channel": "allUserNonFundingLedgerUpdates", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "user": "0x1111111111111111111111111111111111111111", - "eventType": "transfer", - "asset": "USDC", - "amount": "25.00", - "time": 1780000000000 - } -} +{"channel":"allUserNonFundingLedgerUpdates","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"cursor":"","data":{"user":"0x1111111111111111111111111111111111111111","delta":{"type":"internalTransfer","usdc":"25.00"},"time":1780000000000}} ``` ## Payload fields -The payload shape is proposed. - | Field | Type | Description | | --- | --- | --- | -| user | string | User identifier. | -| eventType | string | Illustrative eventType value. | -| asset | string | Illustrative asset value. | -| amount | string | Illustrative amount value. | -| time | integer | Source time. | +| `user` | string | Address associated with the ledger update. | +| `delta` | object | Ledger operation and its type-specific fields. | +| `time` | integer | Event timestamp in milliseconds. | + + + ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "allUserNonFundingLedgerUpdates", - "eventTypes": [ - "deposit", - "transfer" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"allUserNonFundingLedgerUpdates","eventTypes":["deposit","transfer"]}} ``` + ## Resume To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change. diff --git a/content/api-reference/websockets/hypercore/bbo.mdx b/content/api-reference/websockets/hypercore/bbo.mdx index 76995f6cd..47412fd06 100644 --- a/content/api-reference/websockets/hypercore/bbo.mdx +++ b/content/api-reference/websockets/hypercore/bbo.mdx @@ -7,92 +7,75 @@ description: "HyperCore private-preview documentation." # bbo stream +`bbo` delivers the top-of-book best bid and offer when either side changes. This is ideal for live prices and spreads. + For the corresponding gRPC stream, see [StreamBboBook](/docs/chains/hypercore-grpc/api-reference/stream-bbo-book). ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "bbo", - "coins": [ - "BTC" - ] - } -} +{"method":"subscribe","subscription":{"type":"bbo","coins":["BTC"]}} +``` + +Use `marketTypes` instead of `coins` to subscribe to all markets of selected types: + +```json +{"method":"subscribe","subscription":{"type":"bbo","marketTypes":["spot"]}} ``` +## Subscription parameters + +| Parameter | Type | Required | Source | Description | +| --- | --- | --- | --- | --- | +| `coins` | string[] | No | Alchemy extension | Markets to subscribe to. Omit to subscribe to every market of the types in `marketTypes`, which defaults to perpetuals. The native API takes a single `coin` per subscription; the plural array is an Alchemy extension. | +| `marketTypes` | string[] | No | Alchemy extension | Restricts delivery by market type. Accepted values: `perp`, `spot`, `outcome`, or `*`. Defaults to `["perp"]`. Rejected if combined with `coins`. | + +The default never grows. New market types must be added to `marketTypes` explicitly, or pass `["*"]` to opt in to future types automatically. + ## Acknowledgement + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "bbo" - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"bbo"}} ``` ## Event envelope ```json -{ - "channel": "bbo", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "coin": "BTC", - "time": 1780000000000, - "levels": [ - [ - { - "px": "100000.0", - "sz": "1.25", - "n": 0 - } - ], - [ - { - "px": "100001.0", - "sz": "0.80", - "n": 0 - } - ] - ] - } -} +{"channel":"bbo","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"data":{"coin":"BTC","time":1780000000000,"bbo":[{"px":"100000.0","sz":"1.25","n":3},{"px":"100001.0","sz":"0.80","n":2}]}} ``` ## Payload fields -This table is a native compatibility target. - | Field | Type | Description | | --- | --- | --- | -| coin | string | Market identifier. | -| time | integer | Source time. | -| levels | array | Bid and ask level arrays. | -| levels\[\] | array | Bid and ask level arrays. | -| levels\[\]\[\] | object | Bid and ask level arrays. | -| levels\[\]\[\].px | string | Price value. | -| levels\[\]\[\].sz | string | Size value. | -| levels\[\]\[\].n | integer | Order-count value. | +| `coin` | string | Market symbol. | +| `time` | integer | Block timestamp in milliseconds. | +| `bbo` | array | Two-element tuple of `[best_bid, best_ask]`. Either element is `null` when that side has no resting orders. | +| `bbo[].px` | string | Price, as a decimal string. | +| `bbo[].sz` | string | Total size at this level, as a decimal string. | +| `bbo[].n` | integer | Number of orders at this level. | + +The `bbo` tuple always has exactly two elements. This matches the native `WsBbo` shape. + +## Update behavior + +* Emitted only when the best bid or the best ask changes for a market +* Top of book only, with no depth — use `l2Book` for depth +* A `null` element means that side of the book is empty + +## Choosing a book stream + +| | l2Book | l2BookDiff | bbo | l4BookUpdates | +| --- | --- | --- | --- | --- | +| **Delivers** | Complete aggregated snapshot | Changed aggregated levels | Best bid and ask only | Changed individual orders | +| **Client state** | None required | Maintains a local book | None required | Maintains a local book | +| **Detail** | Aggregated levels | Aggregated levels | Top of book | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Price and spread tracking | Market making, queue analysis | + ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "bbo", - "coins": [ - "BTC" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"bbo","coins":["BTC"]}} ``` -## Resume -To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change. +Every message is a complete snapshot, so there is nothing to replay. After a disconnect, resubscribe and the next message re-establishes your state. diff --git a/content/api-reference/websockets/hypercore/connection-lifecycle.mdx b/content/api-reference/websockets/hypercore/connection-lifecycle.mdx index 7ea25d2b6..992629bd6 100644 --- a/content/api-reference/websockets/hypercore/connection-lifecycle.mdx +++ b/content/api-reference/websockets/hypercore/connection-lifecycle.mdx @@ -13,30 +13,24 @@ description: "HyperCore private-preview documentation." 2. Authenticate when the connection is established. 3. Send one or more subscription frames. 4. Wait for an acknowledgement for each subscription. -5. Process messages and persist the latest cursor for each subscription. +5. Process messages and persist the latest cursor for each replay-capable subscription. 6. If the connection closes, reconnect with exponential backoff and jitter. -7. Resume each subscription from its last persisted cursor. If that cursor is no longer valid, resynchronize from a snapshot. +7. Resume replay-capable subscriptions from their last persisted cursor. Complete-snapshot streams resubscribe without a cursor. ## Heartbeats -The connection uses WebSocket ping and pong frames. Clients must respond promptly and should treat a missed pong as a dead connection, then reconnect. The ping interval and idle timeout will be published with the service. +The connection uses WebSocket ping and pong frames. Clients must respond promptly and should treat a missed pong as a dead connection, then reconnect. -## Cursors and gap detection +## Sequencing and recovery -Every message carries a cursor. Clients persist the latest cursor for each subscription. A replay response indicates whether a gap occurred, so clients can determine when local state is untrustworthy. +For the sequencing and recovery model, see [timestamps, cursors, and replay](/docs/data/hypercore/concepts/timestamps-cursors-and-replay). -## Resuming - -Supply the last persisted cursor in the subscription object of the subscribe frame. Resume is per subscription rather than per connection because one connection can carry subscriptions at different positions. The cursor is opaque: clients store and return it unmodified, and its format may change. - -## When to resynchronize - -If a cursor is expired or rejected, or a gap is reported, discard local state and rebuild from a fresh snapshot before trusting it. This is especially important for book streams. +> For replay-capable subscriptions, resume is per subscription: supply the last persisted cursor in that subscription's subscribe frame. Complete-snapshot streams resubscribe without a cursor. ## Backpressure and slow consumers -Clients should apply bounded queues. A consumer that cannot keep up may receive an error frame before the connection is disconnected. The applicable thresholds will be published with the service. +Clients should apply bounded queues. A consumer that cannot keep up may receive an error frame before the connection is disconnected. ## Errors -Errors arrive as a structured frame on the same connection. The error-frame shape and error codes will be published with the service. +Errors arrive as a structured frame on the same connection. diff --git a/content/api-reference/websockets/hypercore/l2-book-diff.mdx b/content/api-reference/websockets/hypercore/l2-book-diff.mdx index e382571b7..35b0de8c6 100644 --- a/content/api-reference/websockets/hypercore/l2-book-diff.mdx +++ b/content/api-reference/websockets/hypercore/l2-book-diff.mdx @@ -7,98 +7,100 @@ description: "HyperCore private-preview documentation." # l2BookDiff stream +`l2BookDiff` delivers incremental price-level changes so clients can maintain a +local order book without receiving a complete snapshot on every update. This is +ideal for latency-sensitive consumers needing continuous book state. + For the corresponding gRPC diff stream, see [StreamL2BookDiff](/docs/chains/hypercore-grpc/api-reference/stream-l2-book-diff). [l2Book](/docs/chains/websockets/hypercore/streams/l2-book) is the snapshot representation. ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "l2BookDiff", - "coins": [ - "BTC", - "ETH" - ] - } -} +{"method":"subscribe","subscription":{"type":"l2BookDiff","coins":["BTC","ETH"],"nSigFigs":5,"mantissa":2,"nLevels":20}} +``` + +Use `marketTypes` instead of `coins` to subscribe to all markets of selected types: + +```json +{"method":"subscribe","subscription":{"type":"l2BookDiff","marketTypes":["spot"]}} ``` +## Subscription parameters + +| Parameter | Type | Required | Source | Description | +| --- | --- | --- | --- | --- | +| `coins` | string[] | No | Alchemy extension | Markets to subscribe to. Omit to subscribe to every market of the types in `marketTypes`, which defaults to perpetuals. The native API takes a single `coin` per subscription; the plural array is an Alchemy extension. | +| `marketTypes` | string[] | No | Alchemy extension | Restricts delivery by market type. Accepted values: `perp`, `spot`, `outcome`, or `*`. Defaults to `["perp"]`. Rejected if combined with `coins`. | +| `nSigFigs` | number | No | Foundation native | Aggregate price levels to N significant figures. Accepted values: `2`, `3`, `4`, `5`. | +| `mantissa` | number | No | Foundation native | Snap prices to a mantissa step. Accepted values: `2` or `5`. Valid only when `nSigFigs` is `5`. | +| `nLevels` | number | No | Alchemy extension | Levels per side: `1`, `10`, `20` (default), or `50`. | + +The default never grows. New market types must be added to `marketTypes` explicitly, or pass `["*"]` to opt in to future types automatically. + +Aggregation rounds bids down and asks up. With `nSigFigs: 5` and `mantissa: 2`, a bid of `70325` becomes `70324` and an ask of `70325` becomes `70326`. + ## Acknowledgement + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "l2BookDiff" - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"l2BookDiff"}} ``` ## Event envelope ```json -{ - "channel": "l2BookDiff", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "coin": "BTC", - "changes": [ - { - "px": "100000.0", - "sz": "1.50", - "n": 4 - } - ], - "isSnapshot": false - } -} +{"channel":"l2BookDiff","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"cursor":"","data":{"height":123456,"time":1780000000000,"isSnapshot":false,"diffs":[{"coin":"BTC","seq":42,"prev_seq":41,"levels":[[{"px":"100000.0","sz":"1.50","n":4}],[]]}]}} ``` -## Filters and behavior +## Payload fields -* `coins` is an array of market symbols. One subscription can cover several markets. Omitting `coins` requests the stream's default market-wide scope. -* Supply `cursor` in the subscription object to request replay after that cursor. The cursor is opaque: clients store and return it unmodified, and its format may change. -* Start from a compatible `l2Book` snapshot before applying `l2BookDiff` updates. +| Field | Type | Description | +| --- | --- | --- | +| `height` | integer | Block height. | +| `time` | integer | Block timestamp in milliseconds. | +| `isSnapshot` | boolean | `true` when the message contains a complete replacement snapshot; absent or `false` for an incremental update. | +| `diffs` | array | One entry per market that changed in this block. | +| `diffs[].coin` | string | Market symbol. | +| `diffs[].seq` | integer | Per-market sequence number, incrementing by one per diff for that market. | +| `diffs[].prev_seq` | integer | The preceding per-market sequence number, for gap detection. | +| `diffs[].levels` | array | Two-element tuple of `[bids, asks]`, containing changed levels only. | +| `diffs[].levels[][].px` | string | Price, as a decimal string. | +| `diffs[].levels[][].sz` | string | New total size at this price level. `"0"` means the level was removed. | +| `diffs[].levels[][].n` | integer | Number of orders at this level. `0` when the level was removed. | + +## Applying diffs + +* A level with `sz` of `"0"` has been removed. Delete that price from your book. +* Any other level is an upsert: set that price to the given `sz` and `n`. +* Sizes are absolute — the level's new total, not a delta. +* Levels absent from a diff are unchanged. +* The snapshot and all subsequent diffs must use identical `nSigFigs`, `mantissa`, and `nLevels`. Applying diffs from one aggregation setting to a snapshot taken at another produces an invalid book. ## Snapshot-to-diff bootstrap 1. Subscribe to `l2Book` and install the received snapshot as local book state. -2. Persist the snapshot cursor after the snapshot is processed. -3. The approved snapshot example does not contain a sequence or other ordering-position field. The position field needed to order the snapshot against later diffs is pending confirmation. -4. Subscribe to `l2BookDiff` for the same coin scope and apply only diffs that follow the installed snapshot once the ordering contract is confirmed. -5. If replay reports a gap, or a cursor is rejected, discard local state and start again from a fresh snapshot. +2. The snapshot establishes the local book state. +3. Subscribe to `l2BookDiff` for the same coin scope and apply its diffs to that state. +4. If continuity is broken, discard local state and start again from a fresh snapshot. -## Payload fields +## Choosing a book stream -The payload shape is proposed. +| | l2Book | l2BookDiff | bbo | l4BookUpdates | +| --- | --- | --- | --- | --- | +| **Delivers** | Complete aggregated snapshot | Changed aggregated levels | Best bid and ask only | Changed individual orders | +| **Client state** | None required | Maintains a local book | None required | Maintains a local book | +| **Detail** | Aggregated levels | Aggregated levels | Top of book | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Price and spread tracking | Market making, queue analysis | -| Field | Type | Description | -| --- | --- | --- | -| coin | string | Market identifier. | -| changes | array | Order-book changes. | -| changes[] | object | Order-book changes. | -| changes[].px | string | Price value. | -| changes[].sz | string | Size value. | -| changes[].n | integer | Order-count value. | -| isSnapshot | boolean | Illustrative isSnapshot value. | ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "l2BookDiff", - "coins": [ - "BTC", - "ETH" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"l2BookDiff","coins":["BTC","ETH"]}} ``` -## Resume -To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change. +## Recovery + +* Persist `cursor` and each market's `seq` after applying a message. +* On reconnect, supply `cursor` in the subscription object. +* Check `prev_seq` against your position for that market on every diff. +* A message with `isSnapshot: true` replaces your local state. Any message without it is a diff that must chain onto your previous state. +* If continuity is broken, a fresh message with `isSnapshot: true` is pushed to you. There is no separate resynchronization message and no epoch to track — `isSnapshot: true` is the signal to discard local state and adopt the supplied snapshot. diff --git a/content/api-reference/websockets/hypercore/l2-book.mdx b/content/api-reference/websockets/hypercore/l2-book.mdx index e557484e3..8ae815110 100644 --- a/content/api-reference/websockets/hypercore/l2-book.mdx +++ b/content/api-reference/websockets/hypercore/l2-book.mdx @@ -7,104 +7,80 @@ description: "HyperCore private-preview documentation." # l2Book stream +`l2Book` delivers aggregated price-level order book snapshots, one per block for each +market whose book changed. This is ideal for order book displays, depth analysis, and pricing. + For the corresponding gRPC snapshot stream, see [StreamL2Book](/docs/chains/hypercore-grpc/api-reference/stream-l2-book). For the diff representation and bootstrap procedure, see [l2BookDiff](/docs/chains/websockets/hypercore/streams/l2-book-diff#snapshot-to-diff-bootstrap). ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "l2Book", - "coins": [ - "BTC", - "ETH" - ] - } -} +{"method":"subscribe","subscription":{"type":"l2Book","coins":["BTC","ETH"],"nSigFigs":5,"mantissa":2,"nLevels":20}} +``` + +Use `marketTypes` instead of `coins` to subscribe to all markets of selected types: + +```json +{"method":"subscribe","subscription":{"type":"l2Book","marketTypes":["spot"]}} ``` +## Subscription parameters + +| Parameter | Type | Required | Source | Description | +| --- | --- | --- | --- | --- | +| `coins` | string[] | No | Alchemy extension | Markets to subscribe to. Omit to subscribe to every market of the types in `marketTypes`, which defaults to perpetuals. The native API takes a single `coin` per subscription; the plural array is an Alchemy extension. | +| `marketTypes` | string[] | No | Alchemy extension | Restricts delivery by market type. Accepted values: `perp`, `spot`, `outcome`, or `*`. Defaults to `["perp"]`. Rejected if combined with `coins`. | +| `nSigFigs` | number | No | Foundation native | Aggregate price levels to N significant figures. Accepted values: `2`, `3`, `4`, `5`. | +| `mantissa` | number | No | Foundation native | Snap prices to a mantissa step. Accepted values: `2` or `5`. Valid only when `nSigFigs` is `5`. | +| `nLevels` | number | No | Alchemy extension | Levels per side: `1`, `10`, `20` (default), or `50`. | + +The default never grows. New market types must be added to `marketTypes` explicitly, or pass `["*"]` to opt in to future types automatically. + +Aggregation rounds bids down and asks up. With `nSigFigs: 5` and `mantissa: 2`, a bid of `70325` becomes `70324` and an ask of `70325` becomes `70326`. + ## Acknowledgement + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "l2Book" - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"l2Book"}} ``` ## Event envelope ```json -{ - "channel": "l2Book", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "coin": "BTC", - "time": 1780000000000, - "levels": [ - [ - { - "px": "100000.0", - "sz": "1.25", - "n": 3 - } - ], - [ - { - "px": "100001.0", - "sz": "0.80", - "n": 2 - } - ] - ] - } -} +{"channel":"l2Book","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"data":{"coin":"BTC","time":1780000000000,"levels":[[{"px":"100000.0","sz":"1.25","n":3}],[{"px":"100001.0","sz":"0.80","n":2}]]}} ``` -## Filters and behavior +## Payload fields -* `coins` is an array of market symbols. One subscription can cover several markets. Omitting `coins` requests the stream's default market-wide scope. -* Supply `cursor` in the subscription object to request replay after that cursor. The cursor is opaque: clients store and return it unmodified, and its format may change. -* `l2Book` provides snapshot state. Before applying `l2BookDiff` updates, begin from a compatible `l2Book` snapshot. +| Field | Type | Description | +| --- | --- | --- | +| `coin` | string | Market symbol. | +| `time` | integer | Block timestamp in milliseconds. | +| `levels` | array | Two-element tuple of `[bids, asks]`. Bids sorted descending, asks ascending. | +| `levels[][].px` | string | Price, as a decimal string. | +| `levels[][].sz` | string | Total size resting at this price level, as a decimal string. | +| `levels[][].n` | integer | Number of orders aggregated into this level. | -## Native aggregation parameters +## Snapshot behavior -`nSigFigs` and `mantissa` are native aggregation parameters whose HyperCore support is pending confirmation. In one-off observations of the native endpoint, `nSigFigs` accepted values from 2 through 5. In the same observations, `mantissa` accepted 2 or 5 only when `nSigFigs` was also supplied. These are observed values, not a guaranteed contract. The native endpoint returns up to 20 levels per side. +* Every message is a complete snapshot for the market it names +* A market is sent only when its book changed in that block +* Levels are aggregated: one level may represent many orders, and `n` reports how many +* Order IDs and user addresses are not exposed on this stream — use `l4BookUpdates` for those -## Payload fields +## Choosing a book stream -This table is a native compatibility target. +| | l2Book | l2BookDiff | bbo | l4BookUpdates | +| --- | --- | --- | --- | --- | +| **Delivers** | Complete aggregated snapshot | Changed aggregated levels | Best bid and ask only | Changed individual orders | +| **Client state** | None required | Maintains a local book | None required | Maintains a local book | +| **Detail** | Aggregated levels | Aggregated levels | Top of book | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Price and spread tracking | Market making, queue analysis | -| Field | Type | Description | -| --- | --- | --- | -| coin | string | Market identifier. | -| time | integer | Source time. | -| levels | array | Bid and ask level arrays. | -| levels\[\] | array | Bid and ask level arrays. | -| levels\[\]\[\] | object | Bid and ask level arrays. | -| levels\[\]\[\].px | string | Price value. | -| levels\[\]\[\].sz | string | Size value. | -| levels\[\]\[\].n | integer | Order-count value. | ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "l2Book", - "coins": [ - "BTC", - "ETH" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"l2Book","coins":["BTC","ETH"]}} ``` -## Resume -To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change. +Every message is a complete snapshot, so there is nothing to replay. After a disconnect, resubscribe and the next message re-establishes your state. diff --git a/content/api-reference/websockets/hypercore/l4-book-updates.mdx b/content/api-reference/websockets/hypercore/l4-book-updates.mdx index a9bbcab5a..24ede934b 100644 --- a/content/api-reference/websockets/hypercore/l4-book-updates.mdx +++ b/content/api-reference/websockets/hypercore/l4-book-updates.mdx @@ -7,91 +7,92 @@ description: "HyperCore private-preview documentation." # l4BookUpdates stream -The L4 delivery model is still being finalized. Candidate models are an initial snapshot followed by incremental updates, or update-only delivery. L4 volumes make a full snapshot per block impractical. +`l4BookUpdates` delivers every individual order placed, resized, or removed, +including its position in the price-level queue. This is ideal for market making, +queue-position analysis, liquidity attribution, and reconstructing an order-level book. For the corresponding gRPC update stream, see [StreamL4BookUpdates](/docs/chains/hypercore-grpc/api-reference/stream-l4-book-updates). For the snapshot-to-diff recovery pattern, see [l2BookDiff](/docs/chains/websockets/hypercore/streams/l2-book-diff#snapshot-to-diff-bootstrap). ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "l4BookUpdates", - "coins": [ - "BTC", - "ETH" - ] - } -} +{"method":"subscribe","subscription":{"type":"l4BookUpdates","coins":["BTC","ETH"]}} ``` -## Acknowledgement +Use `marketTypes` instead of `coins` to subscribe to all markets of selected types: + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "l4BookUpdates" - } -} +{"method":"subscribe","subscription":{"type":"l4BookUpdates","marketTypes":["spot"]}} ``` -## Event envelope +## Subscription parameters + +| Parameter | Type | Required | Source | Description | +| --- | --- | --- | --- | --- | +| `coins` | string[] | No | Alchemy extension | Markets to subscribe to. Omit to subscribe to every market of the types in `marketTypes`, which defaults to perpetuals. The native API takes a single `coin` per subscription; the plural array is an Alchemy extension. | +| `marketTypes` | string[] | No | Alchemy extension | Restricts delivery by market type. Accepted values: `perp`, `spot`, `outcome`, or `*`. Defaults to `["perp"]`. Rejected if combined with `coins`. | + +The default never grows. New market types must be added to `marketTypes` explicitly, or pass `["*"]` to opt in to future types automatically. + +## Acknowledgement ```json -{ - "channel": "l4BookUpdates", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "coin": "BTC", - "orders": [ - { - "orderId": "12345", - "px": "100000.0", - "sz": "0.10", - "action": "upsert" - } - ] - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"l4BookUpdates"}} ``` -## Filters and behavior +## Event envelope -* `coins` is an array of market symbols. One subscription can cover several markets. Omitting `coins` requests the stream's default market-wide scope. -* Supply `cursor` in the subscription object to request replay after that cursor. The cursor is opaque: clients store and return it unmodified, and its format may change. +```json +{"channel":"l4BookUpdates","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"cursor":"","data":{"height":123456,"time":1780000000000,"isSnapshot":false,"diffs":[{"type":"new","coin":"BTC","oid":12345,"user":"0x1111111111111111111111111111111111111111","side":"B","px":"100000.0","sz":"0.10","insertBefore":12346}]}} +``` ## Payload fields -The payload shape is proposed. - | Field | Type | Description | | --- | --- | --- | -| coin | string | Market identifier. | -| orders | array | Order records. | -| orders[] | object | Order records. | -| orders[].orderId | string | Illustrative orderId value. | -| orders[].px | string | Price value. | -| orders[].sz | string | Size value. | -| orders[].action | string | Illustrative action value. | +| `height` | integer | Block height. | +| `time` | integer | Block timestamp in milliseconds. | +| `isSnapshot` | boolean | `true` when the message contains a complete replacement snapshot; absent or `false` for an incremental update. | +| `diffs` | array | Per-order changes in this block. | +| `diffs[].type` | string | `new`, `update`, or `remove`. | +| `diffs[].coin` | string | Market symbol. | +| `diffs[].oid` | integer | Order ID, unique and stable for the life of the order. | +| `diffs[].user` | string | Address that placed the order. | +| `diffs[].side` | string | `B` for bid, `A` for ask. | +| `diffs[].px` | string | Limit price, as a decimal string. | +| `diffs[].sz` | string | Current size. Present on `new` and `update`, absent on `remove`. | +| `diffs[].insertBefore` | integer | Optional, on `new` only. Queue placement — see below. | + +## Queue position + +`insertBefore` places this order immediately ahead of the resting order with that ID at the same price level, reflecting HyperCore's priority placement rules. When absent, append the order to the tail of the queue. If the named order is no longer at that level, append to the tail. + +## Update behavior + +* `update` means the order's size changed, typically a partial fill +* `remove` is terminal — the order was filled or cancelled +* Grouping these orders by price produces the corresponding level-aggregated view — sum the sizes and count the orders at each price — so one subscription can serve both order-level and level-aggregated needs. This corresponds to an unaggregated `l2Book`; it does not reproduce a book requested with `nSigFigs` or `mantissa` applied. + +## Choosing a book stream + +| | l2Book | l2BookDiff | bbo | l4BookUpdates | +| --- | --- | --- | --- | --- | +| **Delivers** | Complete aggregated snapshot | Changed aggregated levels | Best bid and ask only | Changed individual orders | +| **Client state** | None required | Maintains a local book | None required | Maintains a local book | +| **Detail** | Aggregated levels | Aggregated levels | Top of book | Individual orders, with queue position | +| **Use case** | Displays, periodic reads | Efficient live book | Price and spread tracking | Market making, queue analysis | + ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "l4BookUpdates", - "coins": [ - "BTC", - "ETH" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"l4BookUpdates","coins":["BTC","ETH"]}} ``` -## Resume -To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change. +## Recovery + +`l4BookUpdates` carries no per-market `seq` or `prev_seq`; gap detection is server-side, so there is no client sequence bookkeeping. See [detecting gaps](/docs/data/hypercore/concepts/timestamps-cursors-and-replay#detecting-gaps). + +* Persist `cursor` after applying a message. +* On reconnect, supply `cursor` in the subscription object. +* A message with `isSnapshot: true` replaces your local state. Any message without it is a diff that must chain onto your previous state. +* If continuity is broken, a fresh message with `isSnapshot: true` is pushed to you. There is no separate resynchronization message and no epoch to track — `isSnapshot: true` is the signal to discard local state and adopt the supplied snapshot. diff --git a/content/api-reference/websockets/hypercore/ledger-delta-types.mdx b/content/api-reference/websockets/hypercore/ledger-delta-types.mdx new file mode 100644 index 000000000..1abb1e6c5 --- /dev/null +++ b/content/api-reference/websockets/hypercore/ledger-delta-types.mdx @@ -0,0 +1,57 @@ +## Delta types + +Every ledger update carries a `delta` object whose `type` field identifies the operation. + +### Transfers + +| Type | Source | Description | Fields | +| --- | --- | --- | --- | +| `internalTransfer` | Foundation documented | Transfer between accounts. | `usdc`, `user`, `destination` | +| `send` | Additional HyperCore type | Transfer to another address. | `token`, `amount`, `destination` | +| `subAccountTransfer` | Foundation documented | Transfer involving a subaccount. | `usdc`, `user`, `destination` | +| `accountClassTransfer` | Foundation documented | Transfer between account classes. | `usdc`, `user`, `destination` | +| `perpDexClassTransfer` | Additional HyperCore type | Transfer between perpetual DEX account classes. | `usdc`, `user`, `destination` | +| `spotTransfer` | Foundation documented | Spot-asset transfer between accounts. | `token`, `amount`, `user`, `destination` | + +### Deposits and withdrawals + +| Type | Source | Description | Fields | +| --- | --- | --- | --- | +| `deposit` | Foundation documented | Bridge transfer from Arbitrum to Hyperliquid. | `usdc`, `user` | +| `withdraw` | Foundation documented | Bridge transfer from Hyperliquid to Arbitrum. | `usdc`, `user`, `destination` | + +### Vault operations + +| Type | Source | Description | Fields | +| --- | --- | --- | --- | +| `vaultCreate` | Foundation documented | Managed vault creation. | `vault`, `user` | +| `vaultDeposit` | Foundation documented | Deposit into a managed vault. | `vault`, `user`, `amount` | +| `vaultWithdraw` | Foundation documented | Withdrawal from a managed vault. | `vault`, `user`, `amount` | +| `vaultDistribution` | Foundation documented | Distribution from a managed vault. | `vault`, `user`, `amount` | +| `vaultLeaderCommission` | Foundation documented | Commission paid to a vault leader. | `vault`, `user`, `amount` | + +### Staking and cross-chain + +| Type | Source | Description | Fields | +| --- | --- | --- | --- | +| `cStakingTransfer` | Additional HyperCore type | Transfer related to core staking. | `user`, `amount` | +| `spotGenesis` | Foundation documented | Spot-market genesis allocation. | `token`, `amount`, `user` | + +### System operations + +| Type | Source | Description | Fields | +| --- | --- | --- | --- | +| `rewardsClaim` | Foundation documented | Claim of account rewards. | `user`, `amount` | +| `borrowLend` | Additional HyperCore type | Borrow or lend account operation. | `token`, `user`, `amount` | +| `borrowLendBackstopLiquidation` | Additional HyperCore type | Backstop liquidation in the borrow and lend system. | `token`, `user`, `amount` | +| `accountActivationGas` | Additional HyperCore type | Account-activation gas charge. | `user`, `amount` | +| `activateDexAbstraction` | Additional HyperCore type | DEX-abstraction activation. | `user` | +| `deployGasAuction` | Additional HyperCore type | Gas-auction deployment operation. | `user`, `amount` | + +### Liquidations + +| Type | Source | Description | Fields | +| --- | --- | --- | --- | +| `liquidation` | Foundation documented | Liquidation of an account position. | `user`, `liquidatedNtlPos` | + +Funding payments are delivered separately on the [funding rates stream](/docs/chains/websockets/hypercore/streams/funding-rates), not as a ledger delta. diff --git a/content/api-reference/websockets/hypercore/overview.mdx b/content/api-reference/websockets/hypercore/overview.mdx index c510345a6..c64875f2f 100644 --- a/content/api-reference/websockets/hypercore/overview.mdx +++ b/content/api-reference/websockets/hypercore/overview.mdx @@ -11,7 +11,7 @@ description: "HyperCore private-preview documentation." Use the native subscription envelope: `{"method":"subscribe","subscription":{...}}`. Use the same subscription object with `"method":"unsubscribe"` to close a stream. Acknowledgements use `"channel":"subscriptionResponse"`; data frames use `{"channel":"","data":{...}}`. -HyperCore retains additive top-level metadata in its illustrative data frames: `subscriptionId`, `blockHeight`, `blockTime`, and `cursor`. The presence and placement of these top-level Alchemy extension fields are pending engineering confirmation. These examples use native naming as a compatibility target; they do not promise byte-for-byte wire compatibility with native clients. +HyperCore data frames carry additive top-level metadata: `subscriptionId`, `blockHeight`, `blockTime`, and, on replay-capable streams, `cursor`. ## Envelope fields @@ -19,14 +19,14 @@ HyperCore retains additive top-level metadata in its illustrative data frames: ` | --- | --- | --- | | channel | string | Subscription-response channel or stream type. | | data | object | Stream-specific payload. | -| subscriptionId | string | Proposed subscription identifier. | -| blockHeight | integer | Proposed source-block height. | -| blockTime | integer | Proposed source-block time. | -| cursor | string | Opaque proposed resume token. | +| subscriptionId | string | Subscription identifier. | +| blockHeight | integer | Source-block height. | +| blockTime | integer | Source-block time. | +| cursor | string | Opaque resume token on replay-capable streams. | ## Subscription fields -Native subscriptions use singular `coin` and `user` fields. HyperCore's `coins`, `users`, `builders`, `intervals`, and `eventTypes` arrays are proposed Alchemy extensions for multi-entity subscriptions, not native fields. Their support and the expected value form for `users` remain pending confirmation. Candle subscriptions include both a coin dimension and an interval dimension. +Native subscriptions use singular `coin` and `user` fields. HyperCore's `coins`, `users`, `builders`, `intervals`, and `eventTypes` arrays are Alchemy extensions for multi-entity subscriptions. Candle subscriptions include both a coin dimension and an interval dimension. ## Stream catalog @@ -41,7 +41,7 @@ Native subscriptions use singular `coin` and `user` fields. HyperCore's `coins`, | [allUserNonFundingLedgerUpdates](/docs/chains/websockets/hypercore/streams/all-user-non-funding-ledger-updates) | Non-funding ledger updates. | | [bbo](/docs/chains/websockets/hypercore/streams/bbo) | Best-bid and offer book updates. | | [builderFills](/docs/chains/websockets/hypercore/streams/builder-fills) | Builder fill updates. | -| [builderLiquidation](/docs/chains/websockets/hypercore/streams/builder-liquidation) | Intended builder-context liquidation updates. | +| [builderLiquidation](/docs/chains/websockets/hypercore/streams/builder-liquidation) | Builder-context liquidation updates. | | [builderOrderUpdates](/docs/chains/websockets/hypercore/streams/builder-order-updates) | Builder order updates. | | [candles](/docs/chains/websockets/hypercore/streams/candles) | Candle updates for selected coins and intervals. | | [fundingRates](/docs/chains/websockets/hypercore/streams/funding-rates) | Funding-rate updates. | @@ -52,8 +52,8 @@ Native subscriptions use singular `coin` and `user` fields. HyperCore's `coins`, | [setOracleUpdates](/docs/chains/websockets/hypercore/streams/set-oracle-updates) | Oracle updates. | | [tpslUpdates](/docs/chains/websockets/hypercore/streams/tpsl-updates) | Take-profit and stop-loss updates. | | [userFills](/docs/chains/websockets/hypercore/streams/user-fills) | User fill updates. | -| [userIsolatedMarginUpdates](/docs/chains/websockets/hypercore/streams/user-isolated-margin-updates) | Intended user-context isolated-margin updates. | -| [userLeverageUpdates](/docs/chains/websockets/hypercore/streams/user-leverage-updates) | Intended user-context leverage updates. | +| [userIsolatedMarginUpdates](/docs/chains/websockets/hypercore/streams/user-isolated-margin-updates) | User-context isolated-margin updates. | +| [userLeverageUpdates](/docs/chains/websockets/hypercore/streams/user-leverage-updates) | User-context leverage updates. | | [userNonFundingLedgerUpdates](/docs/chains/websockets/hypercore/streams/user-non-funding-ledger-updates) | User non-funding ledger updates. | | [userOrderUpdates](/docs/chains/websockets/hypercore/streams/user-order-updates) | User order updates. | diff --git a/content/api-reference/websockets/hypercore/replay-and-recovery.mdx b/content/api-reference/websockets/hypercore/replay-and-recovery.mdx index feea265e3..425e8830b 100644 --- a/content/api-reference/websockets/hypercore/replay-and-recovery.mdx +++ b/content/api-reference/websockets/hypercore/replay-and-recovery.mdx @@ -7,8 +7,10 @@ description: "HyperCore private-preview documentation." # Replay and recovery -Each subscription advances through opaque cursors. Persist the latest cursor after processing a message, then supply it in that subscription's next subscribe frame to request replay. Clients store and return the cursor unmodified because its format may change. +For the sequencing and recovery model, see [timestamps, cursors, and replay](/docs/data/hypercore/concepts/timestamps-cursors-and-replay). -A replay response indicates whether a gap occurred. When a cursor is invalid or a gap is reported, discard the affected local state and resynchronize from a fresh snapshot before trusting subsequent updates. Resume is per subscription, so subscriptions sharing a connection can resume from different cursors. - -The replay-window length and cursor-retention period will be published with the service. +1. Persist the cursor after processing each message on a replay-capable stream. +2. On disconnect, reconnect with exponential backoff and jitter. +3. Resubscribe, supplying the last persisted cursor in each replay-capable subscription object. Complete-snapshot streams resubscribe without a cursor. +4. Deduplicate overlapping messages using the identity documented for that stream — per-market sequence for book diffs, block height or round for block streams, and the event identity fields where a stream provides them. +5. For stateful snapshot-and-diff streams, a message with `isSnapshot: true` replaces local state for that market. diff --git a/content/api-reference/websockets/hypercore/tpsl-updates.mdx b/content/api-reference/websockets/hypercore/tpsl-updates.mdx index 7a64f9b36..c50565f07 100644 --- a/content/api-reference/websockets/hypercore/tpsl-updates.mdx +++ b/content/api-reference/websockets/hypercore/tpsl-updates.mdx @@ -7,76 +7,91 @@ description: "HyperCore private-preview documentation." # tpslUpdates stream +`tpslUpdates` delivers the lifecycle of resting take-profit and stop-loss trigger +orders. This is ideal for trigger heatmaps, stop-order monitoring, frontend +overlays, and alerting. + For the corresponding gRPC stream, see [StreamTpslUpdates](/docs/chains/hypercore-grpc/api-reference/stream-tpsl-updates). ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "tpslUpdates", - "users": [ - "0x1111111111111111111111111111111111111111" - ] - } -} +{"method":"subscribe","subscription":{"type":"tpslUpdates","coins":["BTC","ETH"]}} ``` +## Subscription parameters + +| Parameter | Type | Required | Source | Description | +| --- | --- | --- | --- | --- | +| `coins` | string[] | No | Alchemy extension | Markets to subscribe to. Omit to subscribe to all perpetual markets. | + +Trigger orders exist only on perpetual markets, so no market-type filter applies. + ## Acknowledgement + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "tpslUpdates" - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"tpslUpdates"}} ``` ## Event envelope ```json -{ - "channel": "tpslUpdates", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "user": "0x1111111111111111111111111111111111111111", - "orderId": "12345", - "triggerType": "stopLoss", - "triggerPrice": "99000.0", - "status": "triggered" - } -} +{"channel":"tpslUpdates","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"cursor":"","data":{"height":123456,"time":1780000000000,"isSnapshot":false,"diffs":[{"type":"add","oid":12345,"coin":"BTC","user":"0x1111111111111111111111111111111111111111","side":"B","triggerPx":"99000.0","limitPx":"98900.0","sz":"0.10","triggerCondition":"Price below 99000","orderType":"Stop Limit","isPositionTpsl":false,"reduceOnly":true,"timestamp":1780000000000}]}} ``` ## Payload fields -The payload shape is proposed. - | Field | Type | Description | | --- | --- | --- | -| user | string | User identifier. | -| orderId | string | Illustrative orderId value. | -| triggerType | string | Illustrative triggerType value. | -| triggerPrice | string | Illustrative triggerPrice value. | -| status | string | Illustrative status value. | +| `height` | integer | Block height. | +| `time` | integer | Block timestamp in milliseconds. | +| `isSnapshot` | boolean | `true` when the message contains a complete replacement snapshot; absent or `false` for an incremental update. | +| `diffs[].type` | string | `add` or `remove`. | +| `diffs[].oid` | integer | Order ID. | +| `diffs[].coin` | string | Market symbol. | +| `diffs[].user` | string | Address that placed the order. | +| `diffs[].side` | string | `B` for buy, `A` for sell. | +| `diffs[].triggerPx` | string | Price at which the order triggers. | +| `diffs[].limitPx` | string | Limit price applied once triggered. | +| `diffs[].sz` | string | Order size. `"0.0"` indicates a position-level TP/SL sized by the position rather than a fixed quantity. | +| `diffs[].triggerCondition` | string | Human-readable condition, for example `Price above 50000`. | +| `diffs[].orderType` | string | For example `Stop Market`, `Take Profit Limit`. | +| `diffs[].isPositionTpsl` | boolean | True when attached to a position rather than standing alone. | +| `diffs[].reduceOnly` | boolean | True when the order can only reduce a position. | +| `diffs[].timestamp` | integer | Order creation time in milliseconds. | +| `diffs[].reason` | string | Present on `remove` only. Why the order left the book. | + +## Update behavior + +* Trigger orders are immutable. There is no update operation — a modified order appears as a `remove` followed by an `add` with a new `oid` +* A `remove` is always terminal +* Perpetual markets only + +## Removal reasons + +| Reason | Meaning | +| --- | --- | +| `triggered` | Condition met; the order was placed on the book | +| `canceled` | Cancelled by the user | +| `reduceOnlyCanceled` | Reduce-only order cancelled because the position closed | +| `marginCanceled` | Cancelled due to insufficient margin | +| `rejected` | Rejected by the matching engine | +| `siblingFilledCanceled` | A paired TP/SL order triggered, cancelling this one | +| `liquidatedCanceled` | Cancelled because the position was liquidated | + +`reason` is informational — treat every `remove` as terminal regardless of its value. New reason values may appear as HyperCore adds order statuses, so do not branch on an exhaustive set. + ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "tpslUpdates", - "users": [ - "0x1111111111111111111111111111111111111111" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"tpslUpdates","coins":["BTC","ETH"]}} ``` -## Resume -To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change. +## Recovery + +`tpslUpdates` carries no per-market `seq` or `prev_seq`; gap detection is server-side, so there is no client sequence bookkeeping. See [detecting gaps](/docs/data/hypercore/concepts/timestamps-cursors-and-replay#detecting-gaps). + +* Persist `cursor` after applying a message. +* On reconnect, supply `cursor` in the subscription object. +* A message with `isSnapshot: true` replaces your local state. Any message without it is a diff that must chain onto your previous state. +* If continuity is broken, a fresh message with `isSnapshot: true` is pushed to you. There is no separate resynchronization message and no epoch to track — `isSnapshot: true` is the signal to discard local state and adopt the supplied snapshot. diff --git a/content/api-reference/websockets/hypercore/user-non-funding-ledger-updates.mdx b/content/api-reference/websockets/hypercore/user-non-funding-ledger-updates.mdx index da1a10a17..f5983f1ae 100644 --- a/content/api-reference/websockets/hypercore/user-non-funding-ledger-updates.mdx +++ b/content/api-reference/websockets/hypercore/user-non-funding-ledger-updates.mdx @@ -8,73 +8,39 @@ description: "HyperCore private-preview documentation." # userNonFundingLedgerUpdates stream ## Subscribe -> The values below illustrate the intended request shape. ```json -{ - "method": "subscribe", - "subscription": { - "type": "userNonFundingLedgerUpdates", - "users": [ - "0x1111111111111111111111111111111111111111" - ] - } -} +{"method":"subscribe","subscription":{"type":"userNonFundingLedgerUpdates","users":["0x1111111111111111111111111111111111111111"]}} ``` ## Acknowledgement + ```json -{ - "channel": "subscriptionResponse", - "data": { - "subscriptionId": "sub_01", - "type": "userNonFundingLedgerUpdates" - } -} +{"channel":"subscriptionResponse","data":{"subscriptionId":"sub_01","type":"userNonFundingLedgerUpdates"}} ``` ## Event envelope ```json -{ - "channel": "userNonFundingLedgerUpdates", - "subscriptionId": "sub_01", - "blockHeight": 123456, - "blockTime": 1780000000000, - "cursor": "", - "data": { - "user": "0x1111111111111111111111111111111111111111", - "eventType": "deposit", - "asset": "USDC", - "amount": "100.00", - "time": 1780000000000 - } -} +{"channel":"userNonFundingLedgerUpdates","subscriptionId":"sub_01","blockHeight":123456,"blockTime":1780000000000,"cursor":"","data":{"user":"0x1111111111111111111111111111111111111111","delta":{"type":"deposit","usdc":"100.00"},"time":1780000000000}} ``` ## Payload fields -The payload shape is proposed. - | Field | Type | Description | | --- | --- | --- | -| user | string | User identifier. | -| eventType | string | Illustrative eventType value. | -| asset | string | Illustrative asset value. | -| amount | string | Illustrative amount value. | -| time | integer | Source time. | +| `user` | string | Address associated with the ledger update. | +| `delta` | object | Ledger operation and its type-specific fields. | +| `time` | integer | Event timestamp in milliseconds. | + + + ## Unsubscribe + ```json -{ - "method": "unsubscribe", - "subscription": { - "type": "userNonFundingLedgerUpdates", - "users": [ - "0x1111111111111111111111111111111111111111" - ] - } -} +{"method":"unsubscribe","subscription":{"type":"userNonFundingLedgerUpdates","users":["0x1111111111111111111111111111111111111111"]}} ``` + ## Resume To resume a stream, supply `cursor` in the subscription object. The cursor is opaque: clients store and return it unmodified, and its format may change.