> For the complete documentation index, see [llms.txt](https://docs.monday.trade/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.monday.trade/rwa-trading-apis/market-data/stock-oracle.md).

# Stock Oracle

## Contract Overview

`StockOracle` stores one latest price payload per supported `bytes32 priceId`. The same oracle proxy can serve all stock symbols on a chain; it does not deploy one feed contract per symbol.

The oracle supports:

* single and batch price reads
* freshness-checked reads
* session-aware payloads
* bid and ask values alongside the main oracle price

All price fields use `8` decimals.

## Deployment and Backend Enablement

The integration draft records the intended mainnet proxy address as the same deterministic address on Ethereum, Monad, and Base:

| Network  | Chain ID | StockOracle proxy                            |
| -------- | -------: | -------------------------------------------- |
| Ethereum |      `1` | `0x037848af338c38e1e0ab722be80bf4c2e612a1f7` |
| Monad    |    `143` | `0x037848af338c38e1e0ab722be80bf4c2e612a1f7` |
| Base     |   `8453` | `0x037848af338c38e1e0ab722be80bf4c2e612a1f7` |

The draft also records implementation address `0x8745912828473e9bef9d843ce8629bee3dcb9fec` for reference only. Consumers should integrate with the proxy address, not the implementation address.

## Price IDs

Each supported asset is identified by `bytes32 priceId`.

The standard derived ID is:

```
priceId = keccak256(uppercase(trim(symbol)))
```

For example, the backend derives `AAPL` from the uppercase symbol bytes. Deployment scripts may also accept an explicit `bytes32 priceId`; if omitted, they use the same uppercase-symbol derivation.

Before reading a price, consumers can check:

```solidity
function isSupportedPriceId(bytes32 priceId) external view returns (bool);
function hasPrice(bytes32 priceId) external view returns (bool);
function description(bytes32 priceId) external view returns (string memory);
```

`isSupportedPriceId=true` means the ID is registered. `hasPrice=true` means at least one price has been published.

## Price Payload

Oracle reads return:

```solidity
enum Session {
    UNKNOWN,
    PRE_MARKET,
    REGULAR,
    POST_MARKET,
    OVERNIGHT,
    CLOSED
}

struct PricePayload {
    int128 price;
    int128 bestBid;
    int128 bestAsk;
    uint64 feedUpdateTimestamp;
    uint64 publishedAt;
    uint80 roundId;
    Session session;
}
```

| Field                 | Meaning                                                                 |
| --------------------- | ----------------------------------------------------------------------- |
| `price`               | Main oracle price, 8 decimals. Backend currently uses bid/ask midpoint. |
| `bestBid`             | Best bid price, 8 decimals.                                             |
| `bestAsk`             | Best ask price, 8 decimals.                                             |
| `feedUpdateTimestamp` | Source quote timestamp, in Unix seconds. Use this for freshness.        |
| `publishedAt`         | On-chain publish timestamp for this oracle round, in Unix seconds.      |
| `roundId`             | Monotonic oracle update round for this `priceId`.                       |
| `session`             | Market session associated with the source quote.                        |

Consumers should use `feedUpdateTimestamp` for staleness checks. `publishedAt` only says when the payload was written on-chain.

## Read APIs

Single-asset reads:

```solidity
function latestPrice(bytes32 priceId)
    external
    view
    returns (PricePayload memory);

function latestPriceNoOlderThan(bytes32 priceId, uint64 maxAge)
    external
    view
    returns (PricePayload memory);
```

Batch reads:

```solidity
function latestPrices(bytes32[] calldata priceIds)
    external
    view
    returns (PricePayload[] memory);

function latestPricesNoOlderThan(bytes32[] calldata priceIds, uint64 maxAge)
    external
    view
    returns (PricePayload[] memory);
```

Prefer `latestPriceNoOlderThan` or `latestPricesNoOlderThan` when the consuming contract must fail closed on stale source data. `maxAge` is denominated in seconds.

Current backend feeder comments note that the source quote can be about 15 minutes delayed. With the default 10-minute heartbeat, a consumer using `latestPriceNoOlderThan(maxAge)` should choose a `maxAge` that accounts for feed delay plus heartbeat and integration-specific risk tolerance; 25 minutes / 1500 seconds is a practical lower-bound example before adding any product-specific buffer.

## Read-Side Reverts

| Error               | Meaning                                                      |
| ------------------- | ------------------------------------------------------------ |
| `PriceIdNotFound`   | The `priceId` is not registered.                             |
| `PriceNotAvailable` | The `priceId` is registered but no price has been published. |
| `PriceTooOld`       | `block.timestamp - feedUpdateTimestamp > maxAge`.            |

## Write-Side Constraints

The backend feeder and deployment scripts are expected to satisfy these constraints before publishing:

| Constraint       | Contract behavior                                                                                                                                                    |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Registering IDs  | `registerPriceId` and `batchRegisterPriceIds` require `DEFAULT_ADMIN_ROLE`.                                                                                          |
| Updating prices  | `updatePrice` and `batchUpdatePrice` require `OPERATOR_ROLE`.                                                                                                        |
| Price validity   | `price`, `bestBid`, and `bestAsk` must be positive and fit into `int128`.                                                                                            |
| Spread validity  | `bestBid` cannot exceed `bestAsk`.                                                                                                                                   |
| Source timestamp | `feedUpdateTimestamp` cannot be in the future and cannot roll back below the current on-chain value.                                                                 |
| Same timestamp   | If `feedUpdateTimestamp` equals the current on-chain timestamp, the update is allowed only for a `CLOSED` carried-forward update with unchanged price, bid, and ask. |

These details are mainly useful for debugging feeder reverts and operational incidents. Normal readers do not need write permissions.

## Session Handling

Consumers should treat `session` as part of the risk model, not just display metadata.

Regular-session prices are generally the most liquid. Pre-market, post-market, and overnight prices may have wider spreads or lower coverage. `CLOSED` means the oracle carried forward the latest on-chain price into a closed-market state; it should not be treated the same as an active quote unless the integration explicitly supports that behavior.

For lending or risk-sensitive integrations, define per-asset and per-session controls for:

* maximum accepted age
* accepted spread or spread-derived haircut
* whether `CLOSED` prices are allowed
* fallback behavior when `PriceIdNotFound`, `PriceNotAvailable`, or `PriceTooOld` occurs


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.monday.trade/rwa-trading-apis/market-data/stock-oracle.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
