# Шлюз оракулов

Сеть Oracle Gateway предоставляет нативные для Solana ценовые фиды (Pyth Network, Switchboard V3) через интерфейс Chainlink `AggregatorV3Interface`. Протоколы Ethereum, переходящие на Rome, могут использовать существующий код интеграции оракула без изменений.

## Проблема

Протоколы Ethereum DeFi ожидают интерфейс Chainlink `AggregatorV3Interface`:

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

В Solana используются другие провайдеры оракулов (Pyth, Switchboard) с иными форматами данных. Без адаптации каждому протоколу Ethereum потребовалась бы собственная интеграция оракула.

## Решение

Oracle Gateway V2 разворачивает легковесные контрактные адаптеры, которые:

1. Читают ценовые данные из аккаунтов Pyth или Switchboard в Solana через CPI
2. Разбирают данные в цепочке, закодированные в формате Borsh
3. Нормализуют цены до 8 знаков после запятой
4. Предоставляют стандартный интерфейс Chainlink `AggregatorV3Interface`

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

// Тот же интерфейс, что и у Chainlink в Ethereum
IAggregatorV3 priceFeed = IAggregatorV3(ORACLE_ADAPTER_ADDRESS);
(, int256 price,,,) = priceFeed.latestRoundData();
// price = SOL/USD с 8 знаками после запятой (например, 15000000000 = $150.00)
```

## Архитектура

### OracleAdapterFactory

Разворачивает и управляет адаптерами оракулов:

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

// Развернуть адаптер ценового фида Pyth
address adapter = factory.createPythFeed(
    pythAccountPubkey,    // Ценовой аккаунт Pyth в Solana
    "SOL/USD",            // описание
    60                    // максимальная допустимая устарелость в секундах
);

// Развернуть адаптер ценового фида Switchboard
address adapter = factory.createSwitchboardFeed(
    sbAccountPubkey,      // агрегатор Switchboard в Solana
    "SOL/USD",
    60
);
```

Перед развертыванием фабрика проверяет, что аккаунт действительно принадлежит программе Pyth/Switchboard.

### Типы адаптеров

**PythPullAdapter** — Читает Pyth `PriceUpdateV2` аккаунты. Поддерживает цену, доверительный интервал, EMA-цену и время публикации.

**SwitchboardV3Adapter** — Читает Switchboard `AggregatorAccountData` аккаунты. Поддерживает цену и временную метку. EMA недоступна.

Оба адаптера используют **минимальные прокси-клоны EIP-1167** для экономичного по газу развертывания.

## Интерфейсы

### Стандартный интерфейс Chainlink

```solidity
interface IAggregatorV3Interface {
    function decimals() external view returns (uint8);          // Всегда 8
    function description() external view returns (string memory);
    function version() external view returns (uint256);
    function latestRoundData() external view returns (
        uint80 roundId,
        int256 answer,        // Цена, нормализованная до 8 знаков после запятой
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );
}
```

### Расширенный интерфейс

```solidity
interface IExtendedOracleAdapter {
    function latestPriceData() external view returns (
        int64 price, uint64 conf, int32 expo, uint64 publishTime
    );
    function latestEMAData() external view returns (        // Только Pyth
        int64 emaPrice, uint64 emaConf, int32 expo, uint64 publishTime
    );
    function priceStatus() external view returns (uint8);   // 0=Торгуется, 1=Устарело, 2=Приостановлено
    function maxStaleness() external view returns (uint256);
    function oracleType() external view returns (uint8);    // 0=PythPull, 1=Switchboard
}
```

### Пакетный считыватель

Читать несколько фидов за один вызов:

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

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

// Возвращает массив (адаптер, answer, updatedAt, success)
// Один устаревший фид не откатывает весь пакет
reader.getLatestPrices(adapters);
```

## Защита от устаревания

Адаптеры применяют параметр `maxStaleness` . Если `block.timestamp - publishTime > maxStaleness`, вызов завершается с ошибкой `StalePriceFeed()`. По умолчанию: 60 секунд.

Владелец фабрики может настраивать устаревание для каждого адаптера отдельно или глобально:

```solidity
factory.setDefaultMaxStaleness(120); // 2 минуты
```

## Развернутые адреса (Devnet)

| Контракт                    | Адрес                                        |
| --------------------------- | -------------------------------------------- |
| OracleAdapterFactory        | `0xa4647955a16b72d15f13b51b5277036755d297be` |
| PythPullAdapter (impl)      | `0x4fd11aed44ee5f71df22fb804cfcbb4c50535db9` |
| SwitchboardV3Adapter (impl) | `0xb57e3589b880aa3f6b66ce2df6aa42cd9c36925e` |
| BatchReader                 | `0x70da375e5680f84032f5b15d35ba0e6f9871d3fd` |
| SOL/USD (Switchboard)       | `0xF0864572019c295407CF2ed46e6FD3615e10E19d` |

См. [Адреса контрактов](/ru/spravochnik/contract-addresses.md) полный список.

## Ограничения

* **Нет исторических данных по раундам** — `getRoundData(roundId)` завершается с ошибкой `HistoricalRoundsNotSupported()`
* **EMA Switchboard не поддерживается** — `latestEMAData()` завершается ошибкой в адаптерах Switchboard
* **Смещения парсера эмпирически проверены** — перед повторным развертыванием с новыми версиями Pyth/Switchboard необходимо повторно выполнить проверку с помощью скриптов валидации
* **Нормализация цены** — цены Pyth нормализуются как `price * 10^(expo - (-8))`; Switchboard — как `(mantissa * 10^8) / 10^scale`

## Статус

**Версия 1 выпущена** (2026-04-01) — V2 в разработке с защитой от устаревания, пакетным чтением, адаптером Switchboard, клонами EIP-1167.

## Что дальше

* [Адреса контрактов](/ru/spravochnik/contract-addresses.md) — все развернутые адреса оракулов
* [Развернуть Solidity](/ru/rukovodstva-dlya-razrabotchikov/deploy-solidity.md) — развертывать контракты, которые используют фиды оракулов


---

# 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/ru/produkty/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.
