Skip to content

Oracle & Prices

Base URL: https://service.leverup.xyz

Price updates by position

The oracle payload required by price-sensitive contract calls. Do not fetch this from Pyth directly — this endpoint selects the correct feeds for the pair and collateral and returns the fee to attach.

http
POST /v1/oracle/price/updates/by-position
Content-Type: application/json

Request

json
{
  "pairBase": "0xcf5a6076cfa32686c0df13abada2b40dec133f1d",
  "collateral": "0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
  "blockChain": "MONAD",
  "options": {
    "includeEncodingData": true,
    "includeFee": true,
    "includePrice": true,
    "includePublishTime": false,
    "includeEncodingDataByOracleId": false,
    "includePriceSafety": false,
    "allowPartial": false
  }
}
FieldRequiredNotes
pairBaseyesMarket identifier
collateralyesThe collateral token. For native MON, pass the WMON address.
blockChainnoDefaults to MONAD
options.includeEncodingDataReturn the update payloads — required for transactions
options.includeFeeReturn updateFee and verifition_fee — required for transactions
options.includePriceAlso return current prices
options.includePublishTimeAlso return publish timestamps

Response

json
{
  "pythPriceUpdateData": ["0x..."],
  "pythProPriceUpdateData": ["0x..."],
  "updateFee": "123456789",
  "verifition_fee": "0",
  "pythCorePrice": { "0xe62d...": "100123450000000000000000" },
  "pythCorePublishTime": { "0xe62d...": 1785312000 },
  "failures": []
}
FieldNotes
pythPriceUpdateDataPass as updateData.pythPriceUpdateData
pythProPriceUpdateDataPass as updateData.pythProPriceUpdateData
updateFeeWei of native MON
verifition_feeAdditional verification fee, wei. The spelling is intentional — the field is named that way in the API.
pythCorePriceKeyed by oracle id, 1e18
failuresNon-empty when a feed could not be resolved

Attach updateFee + verifition_fee as the transaction value:

ts
const value = BigInt(data.updateFee ?? '0') + BigInt(data.verifition_fee ?? '0')

Fetch late

Payloads are short-lived. Request immediately before sending the transaction, not at the start of a long-running flow.

Not needed for 1CT

Gasless trading fetches oracle data server-side. Intents never carry payloads.

Latest pair prices

Current prices for several markets at once.

http
POST /v1/oracle/price/pairs/latest
Content-Type: application/json
json
{
  "pairBases": [
    "0xcf5a6076cfa32686c0df13abada2b40dec133f1d",
    "0xb5a30b0fdc5ea94a52fdc42e3e9760cb8449fb37"
  ],
  "blockChain": "MONAD"
}

Response

json
{
  "prices": {
    "0xcf5a6076cfa32686c0df13abada2b40dec133f1d": "100123450000000000000000",
    "0xb5a30b0fdc5ea94a52fdc42e3e9760cb8449fb37": "3456780000000000000000"
  },
  "failures": []
}

Prices are 1e18 strings, keyed by lowercase pairBase. Pairs that could not be resolved appear in failures with a reason rather than failing the whole request:

json
{ "failures": [{ "pairBase": "0xdead…", "reason": "latest oracle price not found" }] }

pairBases must not be empty. Duplicates are collapsed.

ts
const res = await fetch(`${API}/v1/oracle/price/pairs/latest`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ pairBases: [btcBase, ethBase] }),
})

const { prices } = await res.json()
const btcUsd = Number(BigInt(prices[btcBase.toLowerCase()])) / 1e18

Historical price

Price at a point in the past — used for 24h change calculations.

http
GET /v1/oracle/price/pair-24h-ago?pair_base=0x…
GET /v1/oracle/price/pair-hours-ago?pair_base=0x…&hours_ago=6
ParameterRequiredNotes
pair_baseyes
hours_agono1–24, defaults to 24. Values outside the range return 400.
block_chainnoDefaults to MONAD

Response

json
{
  "pairBase": "0xcf5a6076cfa32686c0df13abada2b40dec133f1d",
  "hoursAgo": 24,
  "blockChain": "MONAD",
  "oracleId": { "kind": "PYTH_CORE", "id": "0xe62d…", "oracle": null },
  "pricePoint": {
    "price": "98765430000000000000000",
    "publishTime": 1785225600,
    "capturedAt": 1785225605
  }
}

price is 1e18. publishTime is the oracle's timestamp; capturedAt is when LeverUp recorded it.

Returns 404 if no snapshot exists for that window.

ts
async function priceChange24h(pairBase: string) {
  const [nowRes, thenRes] = await Promise.all([
    fetch(`${API}/v1/oracle/price/pairs/latest`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ pairBases: [pairBase] }),
    }),
    fetch(`${API}/v1/oracle/price/pair-24h-ago?pair_base=${pairBase}`),
  ])

  const now = Number(BigInt((await nowRes.json()).prices[pairBase.toLowerCase()])) / 1e18
  const then = Number(BigInt((await thenRes.json()).pricePoint.price)) / 1e18

  return ((now - then) / then) * 100
}

Oracle kinds

Feeds are identified by an OracleIdInput:

json
{ "kind": "PYTH_CORE", "id": "0x…", "oracle": null }

kind is one of NONE, PYTH_CORE, PYTH_PRO, DEX_ORACLE. You rarely need to construct these — the position-based endpoint resolves them for you.

Trading perpetuals involves risk. Nothing here is financial advice.