Subscribe
method: "unsubscribe" to stop delivery.
Each stream requires a 0x-prefixed wallet address; addresses are case insensitive.
Delivery and recovery
The subscription acknowledgment precedes an initial snapshot, including an empty snapshot. Snapshots contain the latest 100 matching rows, oldest first. Live messages contain only new or changed rows, in batches of at most 100. All messages carrydata.user,
data.isSnapshot, and Notional’s data.blockNumber committed-state watermark.
The snapshot read and publication finish synchronously before live delivery can begin.
Rows use the same projection as HTTP ledger history,
including assigned-market funding, LP accrual journals, and outcome operation state.
Amounts remain decimal strings, timestamps remain Unix milliseconds, and unavailable
accounting metadata remains absent or null.
Upsert by the canonical row’s id, an opaque stable string. A terminal withdrawal keeps
the pending withdrawal’s id even though its hash and time can change. Outcome operations
also retain their identity through pending, active, reconciliation, and terminal statuses.
Separate rows from one transaction have distinct IDs. Do not deduplicate by timestamp or
transaction hash alone, and do not let an older pending row replace a terminal row.
On reconnect, resubscribe and read HTTP history to recover gaps larger than the snapshot
and lifecycle changes to older rows. A snapshot is a recent window, not a replacement for
complete cached history. The frontend performs this recovery and retains live rows while
HTTP reads finish. Successful HTTP reads refresh nonterminal stream state received before
the request; stream updates received during the request still take precedence. Terminal
receipts remain retained across reconnects, including before the first successful HTTP read.
Cache and subscription identities include the wallet and network.
HTTP remains available for complete retained history and exports.
There is no durable WebSocket replay cursor or exactly-once delivery guarantee. Consumers
must tolerate duplicates and repeated snapshots. Dropped messages at the server’s backpressure
limit close the connection so recovery can run. Projection failures also close affected streams.
HTTP history uses bounded timestamp pages (2,000 rows by default); complete recovery and
exports traverse every page with a fixed endTime. Each stream seeds its accounting projection
from canonical history, independently of HTTP page limits, then applies newly committed
transactions and journal rows in committed order. Old lifecycle changes and backdated funding
remain deliverable without replaying retained history for every update. A new wallet initializes
its LP replay when its first wallet event arrives. Projection state is disposable: unsubscribe,
restart, or a missed commit requires a fresh snapshot; commit gaps close affected streams.
Funding envelope
usdc means funding received; negative means paid. fundingRate copies ledger.delta.rate
when present and is omitted when unavailable. ledger preserves the complete HTTP row.
Non-funding envelope
{ "channel": "userNonFundingLedgerUpdates", "data": { "user": "0x...", "isSnapshot": true, "blockNumber": 123, "nonFundingLedgerUpdates": [] } }
Every array element is a canonical ledger row,
including id, hash, time, delta, and any status, transfer, or outcome metadata.
Transfers retain native asset units; outcome activity retains exact signed outcome.assetDeltas.
Interest is delivered exclusively by userBorrowLendInterest.
Borrow/lend envelope
{ "channel": "userBorrowLendInterest", "data": { "user": "0x...", "isSnapshot": false, "blockNumber": 123, "interest": [] } }
Each element contains time, token, borrow, supply, and ledger. borrow is the positive
magnitude of a borrower charge; supply is lender interest income. The opposite side is "0".
Both are in token units. The signed amount, eligible balance or debt, rate basis, APR, and
accrual interval remain unchanged in ledger. pUSD borrower charges stay in pUSD. USDC supplier
distributions classified as rewards remain on the non-funding stream. The canonical projection
does not currently itemize pUSD supplier yield.
Hyperliquid compatibility
The subscription names,{ channel, data } envelopes, user and isSnapshot fields, and funding
and non-funding array names follow Hyperliquid’s subscription contract.
The userBorrowLendInterest name, interest array, and time/token/borrow/supply fields
were verified against the official deployed client on October 16, 2026;
this stream is absent from the published subscription list.
The testnet client and live testnet
snapshots were also checked on October 17, 2026. All three streams use the same payload array
names above. The observed funding snapshot contained 100 rows ordered oldest first;
non-funding snapshots also arrived oldest first.
The deployed frontend retains 100 funding/interest rows on desktop, 30 on mobile, and 30
non-funding rows. It sorts newest first, resubscribes after reconnect, and merges live funding
ahead of complete HTTP funding history. Notional keeps its existing recent-history display
limit and HTTP fallback, while preserving settled receipts when a read replica lags.
The testnet trading client was rechecked on
October 19, 2026. Its deployed history modules still use these stream selectors, bounded
live history, and separate complete HTTP reads. Notional additionally reconciles mutable
operation statuses and retains terminal receipts as described above.
Notional intentionally adds blockNumber, canonical row IDs, and the lossless ledger field
on funding and interest entries. Non-funding entries use Notional ledger deltas, including
withdrawal rather than Hyperliquid’s withdraw, pending/failed statuses, and multi-asset
outcome metadata. These describe the user’s Notional ledger, including omnibus allocations;
they are not raw events from an individual Hyperliquid account.
Funding and interest entries remain separate canonical legs even when they share a market/token
and timestamp. Notional therefore deduplicates by row id, rather than the deployed client’s
funding key of coin plus timestamp. Interest token uses Notional’s canonical ledger asset label,
including pUSD; paid and earned amounts keep their native units and decimal-string precision.
The official HTTP history contract
uses userFunding (singular) for funding and userNonFundingLedgerUpdates for other activity,
with inclusive millisecond startTime/endTime bounds. Time-range requests are
paginated at 500 entries or distinct blocks.
Notional’s HTTP recovery and exports use its ledger read with types, inclusive
startTime/endTime, limit, and the stable row afterId boundary. Complete reads keep
one fixed endTime while traversing pages and fail if any page is unavailable or incomplete.
The WebSocket reconnect guidance
allows recovery from a fresh subscription snapshot or an HTTP history read. Notional uses both
because a bounded snapshot can omit older lifecycle changes. Its existing socket heartbeat
sends { "method": "ping" } and accepts { "channel": "pong" }, matching the
documented heartbeat protocol.