11 KiB
Chain 138 Snap Pricing Requirements
This note traces what is required to make Chain 138 pricing "MetaMask-Snap-grade" end to end for both:
- current valuation on EOA and token detail surfaces
- transfer-time locked valuation on transaction detail surfaces
It is based on the current live API contract and the current Snap implementation in this repo.
Current state
The Snap already supports:
- network config via
get_networksandget_chain138_config - token list via
get_token_list - current market summary via
get_market_summary - swap and bridge helper RPCs
The token-aggregation API already supports:
- current token summaries via
GET /api/v1/tokens - token detail via
GET /api/v1/tokens/:address - OHLCV candles via
GET /api/v1/tokens/:address/ohlcv - historical point lookup via
GET /api/v1/tokens/:address/price-at
The gap is that the Snap only consumes current market summary, while transfer-time pricing still depends on OHLCV coverage that is not yet reliably backfilled.
What the Snap calls today
Current Snap RPC implementation:
get_market_summarycallsGET {apiBaseUrl}/api/v1/tokens?chainId={chainId}&limit=50get_oraclescallsGET {apiBaseUrl}/api/v1/config?chainId={chainId}get_networkscallsGET {apiBaseUrl}/api/v1/networks
Relevant implementation:
metamask-integration/chain138-snap/packages/snap/src/index.tsxsmom-dbis-138/services/token-aggregation/src/api/routes/tokens.ts
Verified live payloads
1. Networks
Request:
GET /token-aggregation/api/v1/networks
Live shape:
{
"source": "built-in",
"version": "1.0.0",
"networks": [
{
"chainId": "0x8a",
"chainIdDecimal": 138,
"chainName": "DeFi Oracle Meta Mainnet",
"rpcUrls": ["..."],
"blockExplorerUrls": ["https://explorer.d-bis.org"],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"iconUrls": ["..."],
"oracles": [
{
"name": "ETH/USD",
"address": "0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6",
"decimals": 8
}
]
}
]
}
2. Oracles config
Request:
GET /token-aggregation/api/v1/config?chainId=138
Live shape:
{
"source": "built-in",
"version": "1.0.0",
"chainId": 138,
"oracles": [
{
"name": "ETH/USD",
"address": "0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6",
"decimals": 8
}
]
}
3. Current market summary
Request:
GET /token-aggregation/api/v1/tokens?chainId=138&limit=2
Live shape:
{
"source": "db",
"pagination": {
"limit": 2,
"offset": 0,
"count": 2
},
"tokens": [
{
"address": "0x...",
"symbol": "USDT",
"name": "Tether USD (Chain 138)",
"market": {
"chainId": 138,
"tokenAddress": "0x...",
"priceUsd": 1,
"volume24h": 0,
"volume7d": 0,
"volume30d": 0,
"liquidityUsd": 12104786.72586392,
"holdersCount": 0,
"transfers24h": 0,
"lastUpdated": "2026-04-26T03:31:01.926Z"
},
"pricing": {
"priceUsd": 1,
"sourceLayer": "indexer_market",
"precedenceRank": 1,
"stale": false,
"maxAgeSeconds": 900,
"asOf": "2026-04-26T03:31:01.926Z",
"ageSeconds": 3
},
"explorer": {
"chainId": 138,
"explorerBaseUrl": "https://explorer.d-bis.org",
"addressUrl": "https://explorer.d-bis.org/address/0x...",
"tokenUrl": "https://explorer.d-bis.org/address/0x..."
}
}
]
}
4. Historical point lookup
Request:
GET /token-aggregation/api/v1/tokens/0xc02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/price-at?chainId=138×tamp=2026-04-26T01:33:02.000Z
Live shape today:
{
"chainId": 138,
"tokenAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"requestedTimestamp": "2026-04-26T01:33:02.000Z",
"effectiveTimestamp": "2026-04-26T03:31:01.988Z",
"priceUsd": 2490,
"source": "current_market_fallback"
}
This proves the endpoint contract exists, but also proves that the current result is not yet a locked historical candle for this timestamp.
Why transfer-time pricing is not fully locked yet
1. The Snap does not call historical pricing yet
Current Snap market RPCs only call:
GET /api/v1/tokens
They do not call:
GET /api/v1/tokens/:address/price-atGET /api/v1/tokens/:address/ohlcv
So the Snap is current-price compatible, but not transfer-time-price aware.
2. The indexer only rolls OHLCV for the last 7 days
Current indexing flow:
- discovers pools
- indexes tokens
- updates current market data
- generates OHLCV for
5m,1h,24h - only for
now - 7 daysthroughnow
That means a historical valuation request can miss if:
swap_eventswere never backfilled for the requested token or time- the requested timestamp is older than the rolling backfill window
- the token had sparse or no swap coverage in the indexed pool set
3. Historical lookup deliberately falls back
The current price-at route tries:
5mOHLCV near the timestamp- broader
15m,1h,4h,24hwindows - current market data fallback
- canonical fallback
This is correct defensive behavior for explorer UX, but it is not sufficient for wallet-grade "locked at transfer time" semantics unless the caller can distinguish a true historical hit from a fallback. The source field already exposes that distinction.
What is required
A. Backfill OHLCV history
Minimum requirement:
- backfill
swap_eventsandtoken_ohlcvfor the token universe the Snap will price - include native-wrapped asset pairs for WETH9/WETH10 and key stables
- preserve enough history to cover transaction lookback expectations
Required data sources:
- on-chain swap event replay into
swap_events - optional external pair OHLCV seeding where on-chain coverage is missing, using the existing CMC pair OHLCV adapter
Implementation requirements:
- add an explicit backfill job, not just rolling indexer generation
- support
fromBlock/toBlockorfromTimestamp/toTimestamp - generate
5m,15m,1h,4h,24hcandles, not only5m,1h,24h - seed historical candles before enabling wallet-grade transfer-time valuation
Operational acceptance criteria:
price-atfor known transaction timestamps returnssource: ohlcv_*, notcurrent_market_fallback- the requested timestamp and effective timestamp are within the expected candle tolerance
- historical coverage exists across the curated Chain 138 token set
B. Expose a Snap-ready pricing method
The Snap needs a wallet-facing RPC for pricing, instead of overloading get_market_summary.
Recommended new Snap RPC methods:
get_current_priceget_historical_priceget_pricing_context
Recommended behavior:
get_current_price
Request params:
{
"apiBaseUrl": "https://explorer.d-bis.org/token-aggregation",
"chainId": 138,
"address": "0x..."
}
Recommended response:
{
"chainId": 138,
"address": "0x...",
"priceUsd": 1,
"asOf": "2026-04-26T03:31:01.926Z",
"sourceLayer": "indexer_market",
"stale": false
}
This can be implemented by calling GET /api/v1/tokens/:address?chainId=138 and projecting token.pricing plus selected token.market fields.
get_historical_price
Request params:
{
"apiBaseUrl": "https://explorer.d-bis.org/token-aggregation",
"chainId": 138,
"address": "0x...",
"timestamp": "2026-04-26T01:33:02.000Z"
}
Recommended response:
{
"chainId": 138,
"address": "0x...",
"requestedTimestamp": "2026-04-26T01:33:02.000Z",
"effectiveTimestamp": "2026-04-26T01:30:00.000Z",
"priceUsd": 2490,
"source": "ohlcv_5m",
"historical": true
}
Important rule:
- if
sourceiscurrent_market_fallbackorcanonical_fallback, the response should includehistorical: false - callers must not treat fallback data as transfer-locked valuation
get_pricing_context
This is the most Snap-friendly single call.
Request params:
{
"apiBaseUrl": "https://explorer.d-bis.org/token-aggregation",
"chainId": 138,
"address": "0x...",
"timestamp": "2026-04-26T01:33:02.000Z"
}
Recommended response:
{
"chainId": 138,
"address": "0x...",
"current": {
"priceUsd": 2490,
"asOf": "2026-04-26T03:31:01.988Z",
"sourceLayer": "indexer_market",
"stale": false
},
"historical": {
"requestedTimestamp": "2026-04-26T01:33:02.000Z",
"effectiveTimestamp": "2026-04-26T01:30:00.000Z",
"priceUsd": 2488.42,
"source": "ohlcv_5m",
"locked": true
}
}
This gives the Snap everything it needs for:
- current wallet balance valuation
- transaction review valuation
- explicit distinction between live and transfer-time price
C. Exact payload shape the Snap/provider should call
If we do not add a new backend endpoint immediately, the Snap/provider should call these existing routes:
Current valuation
Use:
GET /api/v1/tokens/:address?chainId=138
Read:
token.market.priceUsdtoken.market.lastUpdatedtoken.pricing.priceUsdtoken.pricing.asOftoken.pricing.sourceLayertoken.pricing.stale
Historical valuation
Use:
GET /api/v1/tokens/:address/price-at?chainId=138×tamp={ISO_8601}
Read:
chainIdtokenAddressrequestedTimestampeffectiveTimestamppriceUsdsource
Caller rule:
- only treat
sourcevalues starting withohlcv_as locked historical valuation - treat
current_market_fallbackandcanonical_fallbackas non-historical fallback data
Optional charting
Use:
GET /api/v1/tokens/:address/ohlcv?chainId=138&interval=1h&from={ISO_8601}&to={ISO_8601}
Read:
chainIdtokenAddressintervaldata[]withtimestamp,open,high,low,close,volume,volumeUsd
Recommended implementation order
- Add a backfill job for
swap_eventsandtoken_ohlcv. - Expand candle generation to include
15mand4hin the indexer, not only the API fallback reader. - Add a single Snap-oriented API response, preferably
GET /api/v1/tokens/:address/pricing-context. - Add new Snap RPC methods for current and historical pricing.
- Update the companion site and provider examples to call the new pricing RPCs.
- Add release checks that fail if curated assets return fallback instead of
ohlcv_*for known test timestamps.
Practical definition of "MetaMask-Snap-grade"
The pricing path is Snap-grade only when all of the following are true:
- current price is available from the API for curated assets
- historical price is available for transaction timestamps from OHLCV, not fallback
- the Snap exposes current and historical valuation as distinct methods or a clearly typed combined method
- the caller can programmatically distinguish
locked historicalfrombest-effort fallback - docs and examples show the exact request and response contract