
Inside an oracle
4 minDifficulty Checked 2026-11-10- Each price is a whole number plus a scale that says where the decimal point goes.
- One timestamp covers every pair. Pairs left out of an update lose their price.
- An oracle costs one owner reserve for up to five pairs, two for six to ten.
Open an oracle and you find a short list of pairs. Each pair has two names and a price.
The pair. A pair such as BTC/USD has a base asset and a quote asset. The price says how much of the quote asset one unit of the base asset costs. So BTC/USD is the price of one BTC in USD.
The names do not have to be tokens on the XRP Ledger. They can be a stock symbol or a bond code. The oracle describes outside markets.
The price. The ledger stores prices as whole numbers. A second number, the scale, says where the decimal point belongs. A stored 155000 with scale 6 means 0.155.
The clock. An oracle has one timestamp for the whole list. Every update must carry a time close to the current ledger time. An old price cannot be posted as if it were new.
That single timestamp has a side effect. If an update skips a pair, the ledger wipes that pair's price. The pair stays on the list with no number. This is on purpose: a missing price is safer than a stale one that looks current.
The cost. An oracle is an item its owner keeps on the ledger, so it locks a reserve. Up to five pairs lock 0.2 XRP. Six to ten pairs lock 0.4 XRP. Deleting the oracle frees it.
PriceDataSeries is an array of up to 10 PriceData objects.
PriceData field | Meaning |
|---|---|
BaseAsset | The asset being priced. Any valid identifier: currency code, stock symbol, bond CUSIP |
QuoteAsset | The asset the price is quoted in |
AssetPrice | The price as an integer, after applying Scale. Shown in hexadecimal |
Scale | Decimal shift, 0 to 10 |
Asset names use the 160-bit Currency type. A name that fits the standard currency code format shows as a string such as USD. Anything else shows as 40 hexadecimal characters.
LastUpdateTime is in seconds since the Unix epoch. Most XRPL times use the Ripple Epoch, so this field is an exception. In OracleSet it must be:
- within 300 seconds of the ledger's close time, and
- greater than the oracle's previous value.
Otherwise the result is tecINVALID_UPDATE_TIME.
OracleSet outcomes per pair:
| Pair state and fields sent | Result |
|---|---|
New pair with AssetPrice | Added. Scale defaults to 0 |
Existing pair with AssetPrice and Scale | Both updated |
Existing pair with AssetPrice only | Price updated. Scale resets to 0 |
Existing pair without AssetPrice | Pair deleted |
| Existing pair left out | Pair kept. AssetPrice and Scale cleared |
Provider and AssetClass are required when creating an oracle and optional on updates. An update with more than ten pairs is rejected.
History. The entry holds only the latest values. To read older prices, follow PreviousTxnID with the tx method, or read earlier versions of the entry with ledger_entry and PreviousTxnLgrSeq.
Reserve. One to five PriceData objects count as one item toward OwnerCount. Six to ten count as two.
OracleDelete takes OracleDocumentID. Only the owner can send it. A missing oracle returns tecNO_ENTRY.
Ordering fix. The fixPriceOracleOrder amendment, enabled on mainnet, keeps pairs in one canonical order after both creation and updates.
Related: Owner reserve.
- Oracle ledger entryRead 2026-11-10
- OracleSetRead 2026-11-10
- OracleDeleteRead 2026-11-10
- ReservesRead 2026-11-10
- Known AmendmentsRead 2026-11-10
