@meteorwallet/token-data-shared
v0.7.0
Published
Shared interfaces that every Meteor Wallet token data service implements and every consumer reads
Readme
@meteorwallet/token-data-shared
The shared contract for Meteor Wallet token data services: the token data types every service returns, the interfaces every service implements, the HTTP paths and response envelope every service serves — and the HTTP client the wallets call them with.
No runtime dependencies. Runs anywhere modern JavaScript does (browser, React Native, Workers).
Installation
bun add @meteorwallet/token-data-sharedCalling a service
import {
createTokenDataHttpClient,
ETokenCategory,
ETokenListSort,
ETokenSignalType,
} from "@meteorwallet/token-data-shared";
const tokenData = createTokenDataHttpClient({ baseUrl: "https://tokens.meteorwallet.app" });
const NEAR = { blockchainId: "near", genericNetworkId: "mainnet" } as const;
const trending = await tokenData.listTokens({ ...NEAR, limit: 5 });
// The Top 100's "Meme Coins": that type's slice of Trending (its top 100, in Trending order).
const memes = await tokenData.listTokens({ ...NEAR, limit: 100, category: ETokenCategory.meme });
const gainers = await tokenData.listTokens({ ...NEAR, sort: ETokenListSort.price_change_24h });
const results = await tokenData.listTokens({ ...NEAR, query: "ninu", category: ETokenCategory.meme });
const token = await tokenData.getToken({ ...NEAR, tokenId: "ninu-4.nearlytrade.near" }); // or null
// What the service knows about each of a user's holdings — tracked, blocked, or unknown.
const holdings = await tokenData.getTokens({ ...NEAR, tokenIds: ["wrap.near", "scam.near"] });
// Or let it find them: every token an account holds, with its balance, status and metadata.
const wallet = await tokenData.getAccountTokens({ ...NEAR, accountId: "alice.near" });
const overview = await tokenData.getNetworkOverview(NEAR); // "Total 24H DEX volume on NEAR"
for (const item of trending.items) {
const tag = item.signals[0]; // the most prominent reason it stands out, if any
if (tag?.type === ETokenSignalType.new_listing) {
// "NEW" — tag.value is the pair's age in hours
}
}- Every method accepts
{ signal }as a second argument (react-query passes one). - A service error rejects with a
TokenDataErrorcarrying itscode(ETokenDataErrorCode); network failures and timeouts reject withupstream_unavailable.getTokenresolvesnullfor an unknown token. fetchdefaults to the global one; pass your own in environments that need it.listTokensandgetNetworkOverviewreturnupdatedAtandstale: show "updated N min ago", and de-emphasize figures whenstaleis true.categorynarrows any list — the default Trending order, asort, or a search — to one type; leave it out for everything. Unclassified tokens (category: null) only appear without it.getTokensanswers every ID asked about, in order, with astatus:tracked(and the token's record intoken),blocked(Meteor blocked it: nothing else is said), orunknown(the service knows nothing about it — no lookup is made). The HTTP API takesTOKEN_DATA_MAX_BATCH_SIZE(100) IDs per request; the client splits longer lists and answers them as one. Treat a status you don't recognise likeunknown.getAccountTokensfinds an account's holdings itself (a chain indexer), and answers each likegetTokens, plus itsbalance(the indexer's, seconds behind the chain;nullwhen it has none on record) and itsmetadata— for an unknown token, the contract's own, read and cached by the service,nulluntil it has been (a later call fills it). At most 1,000 tokens, tracked ones first. Most of an account's unknown tokens are airdrops nobody chose: listing a holding is the wallet's call — the tracked ones, the ones the user bought, the ones a whitelist knows.
Conventions
- Decimals are strings. Prices, USD amounts and percentages are
TDecimalString("0.000001234"), never exponent notation. Meme token prices sit far below float precision — parse with a decimal library such as big.js, neverNumber(), for anything a user sees. - Raw amounts are strings in the token's smallest unit (
TRawAmountString). - Timestamps are Unix epoch milliseconds (
TTimestampMs). - Missing data is
null, never a guess. Every market figure is nullable; a service fills what its sources provide. - Networks are
{ blockchainId, genericNetworkId }— structurally compatible withIBlockchainNetworkTargetfrom@meteorwallet/core-sdk, so an existing target passes straight in.
Token fields worth knowing
| Field | Meaning |
| --- | --- |
| trendingRank | Position in the service's Trending order — the team's pinned tokens hold the first places — or null (major token, or too little liquidity, unless pinned). |
| signals | Why the token stands out (featured, new_listing, price_surge, top_volume, high_activity), most prominent first, each with the figure behind it. Ignore types you don't know. |
| riskFlags | Warn before trading: price_warning (Meteor doubts its price — even a real token's: warn before a purchase), symbol_collision (its symbol belongs to another token — a major's, or one Meteor has marked as the original), duplicate_symbol (another token uses the same symbol with more liquidity), low_liquidity. |
| isCanonical | Meteor has settled this as a real token for its symbol (a major, or the team's pick): copies of it are flagged. A symbol can have several (USDC and USDC.e; ETH's two contracts). NEAR itself, asked about as near, is too. |
| canonicalToken | With symbol_collision: the original the symbol belongs to — the first, when it has several — when the service knows it: ID, name, symbol, icon. Send the user there ("View the official PEPE"); it passes straight to getToken. null otherwise. |
| primaryPair | The pair the market figures come from: "HOOT / wNEAR", createdAt ("Listed 12h ago" — the pair's age, not the token's), url ("View on DexScreener"). |
| launchpad | The launch platform, from the contract ID. |
| category | meme or project (a project or ecosystem token) — the "Meme Coins" / "Eco Coins" switch. null until the service has classified the token: list it under "All" only. Treat a value you don't recognise like null. |
| market.txns24h | Buys and sells. traders24h has no source yet and is always null. |
Untrusted metadata
Every string in metadata — name, symbol, description, links — was written by whoever deployed
the token. Services cap lengths and strip control characters, but render them as plain text,
never as HTML, and open links as external links. metadata.icon is an https image URL on a
third-party host, or null (never a data URI); fall back to your own icon source by contract ID.
Implementing a service
import type { ITokenDataService, ITokenNetworkTarget } from "@meteorwallet/token-data-shared";
export class MyTokenDataService implements ITokenDataService {
readonly supportedNetworks: readonly ITokenNetworkTarget[] = [
{ blockchainId: "near", genericNetworkId: "mainnet" },
];
// listTokens, getToken, getTokenPriceHistory, getNetworkOverview — resolve `null` for an
// unknown token, throw a TokenDataError for anything else.
}