Skip to main content

Node snapshot reads

These reads return exchange status, account helpers, vault and validator summaries, and the peer roster.

They are read queries on POST /info. That page describes the endpoint, the request envelope, the number planes and the error shape. These apply to every query here.

Node snapshot query types​

These reads answer from the committed state of the node. They use the same {type, data} envelope and the same conventions as every other read: money as decimal strings, addresses as 0x-hex, asset ids as unsigned integers, and map keys in sorted order. Each read is a keyed lookup, not a scan, except where the set is small by nature (markets, vaults, validators).

Perpetual market reads are on the perpetual queries page. Spot, spot-margin and Earn reads are on the spot & margin queries page. The reads below belong to no single product: exchange status, open-order helpers, liquidation, rate limits, vaults, validators and multi-sig.

Global exchange trading status​

This read returns the global trading status. It takes no parameters.

{ "type": "exchange_status" }

Response

{
"data": {
"type": "exchange_status",
"chain_identity": "c114514-t1788275280000-g8f6fce34e462c553",
"spot_disabled": false,
"post_only": false,
"mip3_enabled": true,
"frozen": false,
"timestamp": 1735689600000
}
}
FieldTypeMeaning
chain_identitystringThe chain that answered. See chain identity below
spot_disabledboolSpot trading is disabled globally
post_onlyboolA post-only window is in force. New orders must be maker-only
frozenboolThe chain is in a pending upgrade halt
timestampuint64Consensus block time, in ms. It is the "as of" time for every field above
mip3_enabledbooltrue when any MIP-3 market or pair spec is registered
info

This read reports the current status only. It does not return the pending upgrade height or the replay progress of the node. frozen shows that a halt is coming. It does not give a date.

Chain identity​

A chain_id does not identify a chain. Two chains can run the same chain_id. All their other stable properties can also be identical: the endpoint shape, the validator addresses and the eth_chainId answer. Only the moving state differs, and a client cannot assert on moving state.

chain_identity is the value that identifies one chain. It reads c<chain_id>-t<chain start, ms>-g<first 16 hex of the genesis hash>. The genesis hash includes the validator set, the epoch length and the initial state root. Two chains that agree on all three parts are the same chain.

Assert it at startup, and refuse to run on a mismatch.

  1. Put the expected value in your configuration next to the endpoint URL.
  2. Read exchange_status before your first write.
  3. Compare the two strings.
  4. Exit if they differ.

A required URL setting alone is not sufficient. It stops the use of a default endpoint, not of a wrong one. Rows written against the wrong chain have the same shape as correct rows. Their only provenance is a chain_id that collides, so nobody can find the mistake later.

ValueMeaningWhat to do
c…-t…-g…The chain the node runsCompare to your configured constant
underivableThe node proves no genesisTreat as a mismatch. Never as a match
absentA node older than the fieldTreat as a mismatch

underivable can never collide with the value of a real chain, because a derived identity always starts with c and a digit.

When it changes. Only a re-genesis of the chain that you read changes it. It survives a node restart, a release, a node upgrade and a validator-set change. A re-genesis of a different chain does not change it. Cache it for the life of your process, and read it again on every reconnect to a new endpoint.

It also survives any config edit that the node still boots with. Two edits are not in that set. If you remove the genesis file, the value becomes underivable. If you change the genesis timestamp under a genesis file, the node does not boot. Neither edit can produce a false match: one refuses, and the other never starts.

warning

frontend_open_orders is removed (folded into open_orders, wire-v2 phase 2). A request now returns 400 UNKNOWN_TYPE. Every open_orders row already has the TIF, cloid and trigger detail that it used to return. See that entry.

Active TWAP parents for an account​

This read returns the active TWAP parent orders of the account. These are the running slice schedulers, with the total size and the executed size. A TWAP that completes or is cancelled leaves this set. The set holds current TWAPs only, not history. For the history of slice fills, use user_twap_slice_fills. Required: address (0x hex).

{ "type": "user_twaps", "address": "0x<addr>" }

Response

{
"data": {
"type": "user_twaps",
"address": "0x<addr>",
"twaps": [
{
"twap_id": 1,
"coin": "BTC",
"side": "B",
"sz": "1.5",
"executed_sz": "0.6",
"slices_total": 10,
"slices_done": 4,
"delay_ms": 3000,
"last_fire_ts": 42000,
"reduce_only": false
}
]
}
}
FieldTypeMeaning
twaps[*].twap_iduint64Parent TWAP id (pass it to twap_cancel)
twaps[*].coinstringMarket symbol
twaps[*].side"B" / "A"Side token. It uses the same "B"/"A" form as user_fills
twaps[*].szDecimal stringTotal size of the parent (whole units)
twaps[*].executed_szDecimal stringThe size that fired slices already filled (whole units)
twaps[*].slices_totaluint32The slice count of the parent schedule
twaps[*].slices_doneuint32Slices fired so far
twaps[*].delay_msuint64Delay between slices (ms)
twaps[*].last_fire_tsuint64Timestamp of the last slice fire (consensus ms)
twaps[*].reduce_onlyboolThe parent is reduce-only

Rows are in ascending twap_id order. There is no duration field. Calculate it as slices_total × delay_ms. The wire has only the independent values.

All vault summaries​

This read returns a summary of all vaults. It takes no parameters.

{ "type": "vault_summaries" }

Response

{
"data": {
"type": "vault_summaries",
"vaults": [
{ "id": 7, "address": "0x<vault>", "leader": "0x<leader>", "name": "MLP", "tvl": "10000000000", "follower_count": 2, "kind": "user" }
]
}
}
FieldTypeMeaning
vaults[*].iduint64Vault id
vaults[*].address / leaderhex addressOn-chain address of the vault, and its leader
vaults[*].namestringDisplay name of the vault. Present on every row
vaults[*].tvldecimal stringMark-to-market NAV, in whole USDC. It is the same figure as vault_state.tvl
vaults[*].follower_countuint64Number of share holders
vaults[*].kind"user" | "metaliquidity"Vault kind

Every vault appears, and each row names its leader. To list the vaults that one address leads, filter these rows on leader. There is no read for each leader.

User action counters​

This read returns the action counters of a user. Required: address (0x hex).

This read does not report a rate-limit budget, although its name suggests it. It returns only nonce and action counters, not bucket state. No read shows the remaining budget. Track your own spend against rate limits.

{ "type": "user_rate_limit", "address": "0x<addr>" }

Response

{
"data": { "type": "user_rate_limit", "address": "0x<addr>", "last_nonce": 9, "pending_count": 2, "lifetime_count": 123 }
}
FieldTypeMeaning
last_nonceuint64Last accepted action nonce
pending_countuint32Count of pending (in-flight) actions
lifetime_countuint64Actions submitted over the lifetime of the account

An address with no record reads as all zeros.

Approved broker-fee grants​

This read returns every builder-fee grant that an account has approved, and the bps ceiling of each. Required: address (0x hex). To check one (address, builder) pair, find the builder in this list. An address that is absent is not approved. That is the same answer as a "0" ceiling.

{ "type": "approved_brokers", "address": "0x<addr>" }

Response

{
"data": {
"type": "approved_brokers",
"address": "0x<addr>",
"builders": [
{ "builder": "0x<builder_a>", "max_fee_bps": "25" },
{ "builder": "0x<builder_b>", "max_fee_bps": "50" }
]
}
}
FieldTypeMeaning
builders[*].builderhex addressApproved builder address
builders[*].max_fee_bpsstringApproved bps ceiling, as a decimal string of whole basis points

Builders are in ascending address order. An account with no approvals returns an empty array.

Validator oracle vote metadata​

This read returns the current validator L1 votes. It takes no parameters.

{ "type": "validator_l1_votes" }

Response

{
"data": {
"type": "validator_l1_votes",
"latest_round": 0,
"votes": [ { "round": 43000000, "validator": "0x<validator>", "submitted_at": 1700000000000 } ]
}
}
FieldTypeMeaning
latest_rounduint64A governance proposal-id counter. It is not the latest vote round, and it is not the maximum round in votes. The governance proposal path increments it. Nothing derives it from the votes. On a chain that has opened no proposal, it stays 0 while votes[*].round goes into the millions. Never use it to page or to date the votes
votes[*].rounduint64Vote round
votes[*].validatorhex addressCasting validator
votes[*].submitted_atuint64Submission timestamp (consensus ms)

The vote payload is opaque oracle bytes that the node decodes internally. This read reports metadata only, not the raw payload.

Validator stake and status​

This read returns a snapshot for every validator in the active validator registry: stake, status and delegation. The registry is a small, bounded set. Rows are in ascending key order.

Optional: address (0x hex). If you name an address, every row includes the stake of that caller. It changes nothing else.

{ "type": "validator_summaries", "address": "0x<addr>" }

Response

{
"data": {
"type": "validator_summaries",
"total_stake": "1400",
"n_active": 1,
"validators": [
{
"validator": "0x1111…", "signer": "0xa1a1…", "validator_index": 0,
"display_name": "alice.mtf",
"stake": "1000", "self_stake": "100", "delegated_stake": "900",
"your_stake": "7", "commission_bps": "500",
"is_active": true, "is_jailed": false, "jailed_at": null,
"unjail_at": null, "first_active_epoch": 2
}
]
}
}
FieldTypeMeaning
total_stakedecimal stringΣ stake across all validators
n_activeuint64Size of the active set
validators[*].validator0x addressPrimary address of the validator
validators[*].signer0x addressOperational signer (hot key)
validators[*].validator_indexuint32Consensus index
validators[*].display_namestring | nullThe handle that the operator chose (set_display_name), or null when it set none
validators[*].stakedecimal stringTotal stake: the self stake and the stake of all others
validators[*].self_stakedecimal stringThe contribution of the validator
validators[*].delegated_stakedecimal stringstake − self_stake: all stake from accounts other than the validator
validators[*].your_stakedecimal string | nullThe stake that the requesting address has delegated to this validator
validators[*].commission_bpsstringCommission in whole basis points, as a decimal string
validators[*].is_activeboolIn the active set this epoch
validators[*].is_jailedboolJailed now
validators[*].jailed_atuint64 | nullJail start ts (null if not jailed)
validators[*].unjail_atuint64 | nullEarliest unjail ts (null if not jailed)
validators[*].first_active_epochuint64The first epoch in which the validator was active

A display_name of null means unset, never "unknown". Use the address instead. Do not invent a name, and do not read null as a node older than the field.

your_stake has two different blank values. "0" means that the request named an address, and that address has delegated nothing to this validator. null means that the request named no address, so the field is about nobody. Show the column as empty, not as a zero balance.

delegated_stake is derived, not stored. It is exactly stake − self_stake, so it always agrees with the two figures next to it. Do not sum it across rows to get total_stake. That sum excludes the self stake of every validator.

There is no epoch key, and there never was one in use. No production code writes the current-epoch counter of the chain. Any value served would be a constant, not the real epoch of the chain. Read first_active_epoch for each validator instead.

The chain does not track n_recent_blocks. The read omits it and does not invent a value.

Advertised peer roster​

This read returns the nodes that this deployment advertises for peer discovery. It takes no parameters. It reports network topology, not committed state.

Active

A running node answers with the peers shape below. The previous shape, { "root_ips": ["host:port", ...] }, is removed. There is no root_ips key.

{ "type": "gossip_root_ips" }

Response

{
"data": {
"type": "gossip_root_ips",
"peers": [
{
"id": 3,
"gossip": "203.0.113.7:4001",
"peer_rpc": "203.0.113.7:4002",
"auth": "203.0.113.7:4003",
"pubkey_hex": "02ab..."
}
]
}
}
FieldTypeMeaning
peersobject[]One row for each advertised node. Empty when the deployment advertises nothing.
peers[*].iduint16The numeric id of the node
peers[*].gossipstringPublic gossip endpoint, host:port
peers[*].peer_rpcstringPublic peer-RPC endpoint, host:port
peers[*].authstringPublic auth endpoint, host:port
peers[*].pubkey_hexstring (optional)Compressed secp256k1 public key for the TCP auth of the peer. The key is absent when the operator did not publish it.

Row shape. A row has the shape of a peer config entry. The five fields map one-to-one onto the peer entry of a joining node, so you can paste a row and dial it.

Row source. Each node serves a roster that the operator curates in its own config. The roster states public reachability. It is not the internal dial list of the node, and no address from that dial list can appear here.

A node that advertises nothing is absent from the rows. There is no fallback. A validator can run, vote and serve while it publishes no address. Such a validator does not appear. An empty peers array is therefore the correct answer for a deployment that advertises nothing. It is not an error, and it does not show an unhealthy node.

The roster shows the node config published at startup. It is not committed state, and it is not part of the AppHash.