Asset ids and naming
Orders name a market by an integer asset id and info requests by a coin string, and perps, spot, HIP-3 and outcomes each derive both by a different rule.
One wrong number sends your order to another market, or returns another market’s data. Validator-operated perps, spot pairs, HIP-3 perps and HIP-4 outcomes each derive the order’s a and the coin string from a metadata list.
Say you want HYPE spot on mainnet. The HYPE/USDC pair has index 107, so reads use @107 and orders use asset id 10000 + 107 = 10107. Use HYPE’s token index, 150, instead and you get 10150: pair 150, another market.
Perps on the first dex are the simple case: BTC is asset 0 on mainnet. Every formula is under The numbers; the sections below cover the traps.
Spot pairs are indexed apart from their tokens
Section titled “Spot pairs are indexed apart from their tokens”Pairs are @<index>, except legacy pairs that keep a name: PURR/USDC is index 0, asset id 10000.
| Network | HYPE token index | HYPE/USDC pair | Coin | Asset id |
|---|---|---|---|---|
| Mainnet | 150 | 107 | @107 |
10107 |
| Testnet | 1105 | 1035 | @1035 |
11035 |
USDH: token 360, pair 230 on mainnet; token 1452, pair 1338 on testnet. spotMeta.universe[].tokens lists [base, quote] token indices: @107 is [150, 0], HYPE and USDC.
Transfers use neither index: a token is NAME:0x<32 hex characters>, from name and tokenId in spotMeta.tokens, for example PURR:0xc1fb593aeffbeb02f85e0308e9956a90 (see transfers).
HIP-3 perps add a dex offset
Section titled “HIP-3 perps add a dex offset”perpDexs[0] is null: that slot is the first perp dex, which uses plain indices. The docs’ example: test:ABC on testnet has perpDexIndex 1 and index 0 in meta with {"dex": "<name>"}, so asset id 110000. That meta already returns qualified names such as xyz:XYZ100.
Outcomes pack outcome and side into one number
Section titled “Outcomes pack outcome and side into one number”Sides 0 and 1 are positions in sideSpecs in outcomeMeta; on a plain binary market side 0 is Yes and side 1 No. Every identifier derives from one encoding:
encoding = 10 * outcome + side| Where | Form | Outcome 1, side 0 |
|---|---|---|
| Order asset id | 100000000 + encoding |
100000010 |
| Coin in info requests, WebSocket and fills | #<encoding> |
#10 |
Token name in spotClearinghouseState balances |
+<encoding> |
+10 |
Outcome coins appear in spotMetaAndAssetCtxs, keyed by # coin, not in meta.universe; positions are spot balances. Payoffs are on what an outcome market is.
The numbers
Section titled “The numbers”| Market | Asset id | Coin string | Where the index comes from |
|---|---|---|---|
| Perp, first dex | index |
name, e.g. BTC |
position in meta.universe |
| Spot | 10000 + index |
@<index>, or a legacy name like PURR/USDC |
the pair’s index field in spotMeta.universe |
| HIP-3 perp | 100000 + perpDexIndex * 10000 + index |
dex:COIN |
position in perpDexs; position in meta for that dex |
| Outcome side | 100000000 + 10 * outcome + side |
#<10 * outcome + side>; balances +<...> |
outcome and sideSpecs in outcomeMeta |
Comparing markets across tools
Section titled “Comparing markets across tools”Compare prices across tools by pair index or asset id, not display name. The docs’ example: BTC/USDC in the app is UBTC/USDC on HyperCore, the name the explorer’s token details page shows.
Deriving ids in code
Section titled “Deriving ids in code”// Inputs come from meta, spotMeta, perpDexs and outcomeMeta, read per network.const perpAsset = (indexInMeta: number) => indexInMeta;const spotAsset = (pairIndex: number) => 10_000 + pairIndex; // spotMeta.universe[].indexconst hip3Asset = (perpDexIndex: number, indexInMeta: number) => 100_000 + perpDexIndex * 10_000 + indexInMeta; // perpDexIndex is 1 or more
const encoding = (outcome: number, side: 0 | 1) => 10 * outcome + side;const outcomeAsset = (outcome: number, side: 0 | 1) => 100_000_000 + encoding(outcome, side);const outcomeCoin = (outcome: number, side: 0 | 1) => `#${encoding(outcome, side)}`; // info, WS, fillsconst outcomeToken = (outcome: number, side: 0 | 1) => `+${encoding(outcome, side)}`; // spot balancesBuild the tables per network, keyed by the index field, not array position: on mainnet @367 points at token 479 in a 464-entry tokens array. Outcome asset ids start at 100,000,000, beyond a 16-bit field: store asset ids in at least 32 bits.
Mistakes that reach the wrong market
Section titled “Mistakes that reach the wrong market”- Outcomes are never
@<outcomeId>, which names an unrelated spot pair. One SDK made this mistake. - Do not map sides by name. Labelled outcomes do not call their sides Yes and No; use the
sideSpecsposition. Reject unparseable side input: silently falling back to side 0 is a known bug class. - Do not prefix HIP-3 names twice.
xyz:xyz:MUmatches nothing. - Ids are per network, HIP-3 dexes included. A cache keyed by coin alone serves testnet ids to mainnet orders.
For these rules on one card, with system addresses, see Asset encoding cheat sheet. For where the asset id goes, see Orders.