@kinetiq-research/markets-assets
Version:
Asset metadata (descriptions, oracle references) for Kinetiq markets
85 lines (83 loc) • 4.27 kB
text/typescript
/**
* The listings whose canonical url KEEPS its dex prefix, lowercased.
*
* SanDisk is listed live on BOTH `xyz` and `io`, so `/trade/sndk` names two
* markets. The bare url stays with `xyz` — it is the deeper market and the one
* already indexed and shared — and the `io` listing takes `/trade/io:sndk`
* rather than being unreachable behind whichever listing `getPerpsAsset`
* happened to rank first. Both keep the ticker they actually trade under; only
* the url disambiguates, because a display name is the exchange's to set and a
* renamed SanDisk would be wrong on every surface, not just this one.
*
* Keys are the FULL `dex:symbol` name, which is also the value this returns —
* that is what keeps the function idempotent for a prefixed listing:
* re-applying it finds `io:sndk` in here and hands it straight back.
*/
const PREFIXED_URL_SYMBOLS: ReadonlySet<string> = new Set(['io:sndk'])
/**
* The canonical name `/trade/[...urlSymbol]` resolves WITHOUT a redirect: the
* market's DISPLAY name, lowercased, with no dex prefix at all.
*
* This is the single definition of that rule, and it exists as its own export
* for one reason: every place that needed the rule used to restate it. Call it
* rather than interpolating a symbol into a path — `ROUTES.TRADE_SYMBOL` does,
* so most callers get it for free.
*
* WHY NO DEX PREFIX. Urls used to carry one for external dexes (`xyz:PLTR`),
* because a ticker could in principle name a listing on more than one dex. In
* practice the dexes we surface (main Hyperliquid, our `mkts`, and `xyz`) share
* no live ticker, so the prefix bought nothing and cost every reader, every
* share link and every bot a piece of Hyperliquid trivia. If a real collision
* ever ships, re-introduce the prefix HERE for that one listing — not as a
* blanket rule.
*
* ONE COLLISION HAS SINCE SHIPPED, and it is handled exactly that way — see
* `PREFIXED_URL_SYMBOLS`. Everything else still resolves bare.
*
* Two things that follow from the shape, both of which have already shipped
* bugs in the prefixed version of this rule:
*
* 1. IT IS IDEMPOTENT, AND IT ACCEPTS RAW HYPERLIQUID NAMES. `hyperliquidSymbol`
* is prefixed for every HIP-3 dex INCLUDING our own (`mkts:US500`), so
* passing one is the common case at the call sites that only have the raw
* name to hand; it is stripped here rather than at each of them.
*
* Idempotence is REQUIRED, not incidental: `resolveCanonicalRedirect`
* compares this output against the url it is already on and redirects when
* they differ, so an output this function would change again is a url that
* redirects forever. That is why the split is on the LAST colon and not the
* first — the dex is what precedes the first one, but taking that split
* leaves any remaining colon in the result, and a second pass would strip
* more. Splitting last is the same answer for every real name (they carry
* at most one colon) and is the only one that cannot move twice.
* 2. THE URL IS THE DISPLAY NAME, NOT THE SYMBOL. The listing whose symbol is
* `CL` displays as `WTIOIL`, so its canonical url is `/trade/wtioil`.
* `/trade/cl` still resolves — `getPerpsAsset` matches the raw symbol as a
* last resort — but only through a canonical redirect.
*/
export const toTradeUrlSymbol = ({
dex,
symbol,
}: {
/**
* The dex the listing trades on (`''` for main Hyperliquid). Only consulted
* to spot a `PREFIXED_URL_SYMBOLS` entry, so callers holding an
* already-canonical `tradeUrlSymbol` can leave it off.
*/
dex?: string
/**
* The DISPLAY name (override, then live annotation, then clean symbol), or a
* raw `dex:`-prefixed Hyperliquid name — the prefix is stripped either way.
*/
symbol: string
}): string => {
const colon = symbol.lastIndexOf(':')
const bare = symbol.slice(colon + 1).toLowerCase()
// The dex the caller named, else the one already carried by `symbol` — which
// is what makes a second pass over `io:sndk` land on the same answer.
const prefix = (
dex ?? (colon === -1 ? '' : symbol.slice(0, colon))
).toLowerCase()
const prefixed = `${prefix}:${bare}`
return PREFIXED_URL_SYMBOLS.has(prefixed) ? prefixed : bare
}