# Oracle Gateway

The Oracle Gateway exposes Solana-native price feeds (Pyth Network, Switchboard V3) through Chainlink's `AggregatorV3Interface`. Ethereum protocols porting to Rome can use their existing oracle integration code unchanged.

## The Problem

Ethereum DeFi protocols expect Chainlink's `AggregatorV3Interface`:

```solidity
(, int256 price,,,) = priceFeed.latestRoundData();
```

Solana has different oracle providers (Pyth, Switchboard) with different data formats. Without adaptation, every Ethereum protocol would need custom oracle integration.

## The Solution

Oracle Gateway V2 deploys lightweight adapter contracts that:

1. Read price data from Pyth or Switchboard accounts on Solana via CPI
2. Parse the on-chain Borsh-encoded data
3. Normalize prices to 8 decimal places
4. Expose the standard Chainlink `AggregatorV3Interface`

```solidity
import {IAggregatorV3Interface} from "@rome-protocol/solidity-sdk/contracts/oracle/IAggregatorV3Interface.sol";

// Same interface as Chainlink on Ethereum
IAggregatorV3 priceFeed = IAggregatorV3(ORACLE_ADAPTER_ADDRESS);
(, int256 price,,,) = priceFeed.latestRoundData();
// price = SOL/USD at 8 decimals (e.g., 15000000000 = $150.00)
```

## Architecture

### OracleAdapterFactory

Deploys and manages oracle adapters:

```solidity
OracleAdapterFactory factory = OracleAdapterFactory(0xa4647955a16b72d15f13b51b5277036755d297be);

// Deploy a Pyth price feed adapter
address adapter = factory.createPythFeed(
    pythAccountPubkey,    // Pyth price account on Solana
    "SOL/USD",            // description
    60                    // max staleness in seconds
);

// Deploy a Switchboard price feed adapter
address adapter = factory.createSwitchboardFeed(
    sbAccountPubkey,      // Switchboard aggregator on Solana
    "SOL/USD",
    60
);
```

The factory validates that the account is actually owned by the Pyth/Switchboard program before deploying.

### Adapter Types

**PythPullAdapter** — Reads Pyth `PriceUpdateV2` accounts. Supports price, confidence interval, EMA price, and publish time.

**SwitchboardV3Adapter** — Reads Switchboard `AggregatorAccountData` accounts. Supports price and timestamp. EMA not available.

Both adapters use **EIP-1167 minimal proxy clones** for gas-efficient deployment.

## Interfaces

### Standard Chainlink Interface

```solidity
interface IAggregatorV3Interface {
    function decimals() external view returns (uint8);          // Always 8
    function description() external view returns (string memory);
    function version() external view returns (uint256);
    function latestRoundData() external view returns (
        uint80 roundId,
        int256 answer,        // Price normalized to 8 decimals
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );
}
```

### Extended Interface

```solidity
interface IExtendedOracleAdapter {
    function latestPriceData() external view returns (
        int64 price, uint64 conf, int32 expo, uint64 publishTime
    );
    function latestEMAData() external view returns (        // Pyth only
        int64 emaPrice, uint64 emaConf, int32 expo, uint64 publishTime
    );
    function priceStatus() external view returns (uint8);   // 0=Trading, 1=Stale, 2=Paused
    function maxStaleness() external view returns (uint256);
    function oracleType() external view returns (uint8);    // 0=PythPull, 1=Switchboard
}
```

### Batch Reader

Read multiple feeds in one call:

```solidity
BatchReader reader = BatchReader(0x70da375e5680f84032f5b15d35ba0e6f9871d3fd);

address[] memory adapters = new address[](3);
adapters[0] = solUsdAdapter;
adapters[1] = btcUsdAdapter;
adapters[2] = ethUsdAdapter;

// Returns array of (adapter, answer, updatedAt, success)
// One stale feed doesn't revert the whole batch
reader.getLatestPrices(adapters);
```

## Staleness Protection

Adapters enforce a `maxStaleness` parameter. If `block.timestamp - publishTime > maxStaleness`, the call reverts with `StalePriceFeed()`. Default: 60 seconds.

The factory owner can adjust staleness per adapter or globally:

```solidity
factory.setDefaultMaxStaleness(120); // 2 minutes
```

## Deployed Addresses (Devnet)

| Contract                    | Address                                      |
| --------------------------- | -------------------------------------------- |
| OracleAdapterFactory        | `0xa4647955a16b72d15f13b51b5277036755d297be` |
| PythPullAdapter (impl)      | `0x4fd11aed44ee5f71df22fb804cfcbb4c50535db9` |
| SwitchboardV3Adapter (impl) | `0xb57e3589b880aa3f6b66ce2df6aa42cd9c36925e` |
| BatchReader                 | `0x70da375e5680f84032f5b15d35ba0e6f9871d3fd` |
| SOL/USD (Switchboard)       | `0xF0864572019c295407CF2ed46e6FD3615e10E19d` |

See [Contract Addresses](/reference/contract-addresses.md) for the full list.

## Constraints

* **No historical round data** — `getRoundData(roundId)` reverts with `HistoricalRoundsNotSupported()`
* **Switchboard EMA not supported** — `latestEMAData()` reverts on Switchboard adapters
* **Parser offsets empirically validated** — must re-validate with validation scripts before redeployment against new Pyth/Switchboard versions
* **Price normalization** — Pyth prices normalized as `price * 10^(expo - (-8))`; Switchboard as `(mantissa * 10^8) / 10^scale`

## Status

**V1 Shipped** (2026-04-01) — V2 in progress with staleness protection, batch reads, Switchboard adapter, EIP-1167 clones.

## What's Next

* [Contract Addresses](/reference/contract-addresses.md) — all deployed oracle addresses
* [Deploy Solidity](/developer-guides/deploy-solidity.md) — deploy contracts that use oracle feeds


---

# Agent Instructions: 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:

```
GET https://docs.rome.builders/products/oracle-gateway.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
