# Price Oracle Middleware

## Purpose and scope

The Price Oracle Middleware system provides standardized asset valuation and conversion for the PlasmaVault ecosystem. It is centered around the `PriceOracleMiddlewareWithRoles` contract, which acts as a centralized price hub, and the `PriceOracleMiddlewareManager`, which provides a vault-specific interface for price queries and validation.

The system is responsible for:

* Providing asset prices in a unified quote currency (USD) with 18 decimals [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol42-46](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L42-L46)
* Managing custom price feed sources (e.g., Pendle PT, Curve, ERC4626) [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol125-135](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L125-L135)
* Falling back to the Chainlink Feed Registry when custom sources are not defined [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol19-21](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L19-L21)
* Implementing price change validation to protect vaults from extreme volatility or oracle manipulation [contracts/managers/price/PriceOracleMiddlewareManagerLib.sol43-48](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/managers/price/PriceOracleMiddlewareManagerLib.sol#L43-L48)

## System architecture

The architecture separates global price discovery from vault-specific price management and validation.

### Logic flow and code entities

<figure><img src="/files/2p6cbzWHHuc1B7THR46E" alt=""><figcaption></figcaption></figure>

**Architecture description**:

1. **PlasmaVault** and its **Balance Fuses** interact with the `PriceOracleMiddlewareManager` assigned to the vault [contracts/vaults/PlasmaVault.sol75](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/vaults/PlasmaVault.sol#L75-L75)
2. The **PriceOracleMiddlewareManager** handles vault-specific configuration, such as custom asset sources and price validation logic stored via `PriceOracleMiddlewareManagerLib` [contracts/managers/price/PriceOracleMiddlewareManagerLib.sol64-75](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/managers/price/PriceOracleMiddlewareManagerLib.sol#L64-L75)
3. **PriceOracleMiddlewareWithRoles** serves as the protocol-wide price aggregator, managing specialized feeds like **PtPriceFeed** for Pendle tokens [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol140-150](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L140-L150)

## Core components

### 1. PriceOracleMiddlewareWithRoles

This contract provides the "Source of Truth" for asset prices. It normalizes all outputs to 18 decimals (WAD) [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol76-77](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L76-L77)

* **Quote Currency**: Hardcoded to the Chainlink USD address `0x...0348` [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol42](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L42-L42)
* **Custom Sources**: Allows administrators to map specific assets to custom `IPriceFeed` implementations [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol112-114](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L112-L114)
* **Pendle Integration**: Features specialized logic to deploy and manage `PtPriceFeed` instances for Pendle Principal Tokens [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol140-160](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L140-L160)

### 2. PriceOracleMiddlewareManager

A per-vault manager that wraps the global middleware with validation and vault-specific overrides.

* **getAssetPrice**: The primary entry point. It checks for a vault-specific source in `PriceOracleMiddlewareManagerLib` before falling back to the global middleware [contracts/managers/price/PriceOracleMiddlewareManager.sol103-118](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/managers/price/PriceOracleMiddlewareManager.sol#L103-L118)
* **Validation**: Implements `validatePriceChange` which compares the current price against a `lastValidatedPrice`. If the delta exceeds `maxPriceDelta`, the transaction reverts [contracts/managers/price/PriceOracleMiddlewareManagerLib.sol43-48](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/managers/price/PriceOracleMiddlewareManagerLib.sol#L43-L48)

## Specialized price feeds

The system supports various specialized feeds to handle complex DeFi assets.

### Pendle PT Price Feed (`PtPriceFeed`)

Calculates the price of Pendle Principal Tokens using Pendle's TWAP oracle and the price of the underlying asset from the middleware [contracts/price\_oracle/price\_feed/PtPriceFeed.sol12-18](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/price_feed/PtPriceFeed.sol#L12-L18)

| Feature     | Implementation Detail                                                                                                                                                                                                                 |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TWAP Window | Minimum 5 minutes, recommended 15 minutes [contracts/price\_oracle/price\_feed/PtPriceFeed.sol23](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/price_feed/PtPriceFeed.sol#L23-L23)                   |
| Calculation | `(PtToAssetRate * UnderlyingAssetPrice) / scalingFactor` [contracts/price\_oracle/price\_feed/PtPriceFeed.sol128](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/price_feed/PtPriceFeed.sol#L128-L128) |
| Metadata    | Returns Chainlink-compatible `latestRoundData` [contracts/price\_oracle/price\_feed/PtPriceFeed.sol109-113](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/price_feed/PtPriceFeed.sol#L109-L113)       |

### Feed factory pattern

Factories like `PtPriceFeedFactory` and `CurveStableSwapNGPriceFeedFactory` are used to deploy standardized feed instances that the middleware can then consume [contracts/factory/price\_feed/PtPriceFeedFactory.sol6-10](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/factory/price_feed/PtPriceFeedFactory.sol#L6-L10)

## Price validation mechanism

The validation system prevents the vault from transacting at "stale" or manipulated prices by enforcing a maximum allowed deviation.

<figure><img src="/files/aV2Fvlvn5vOkkIUfUXuD" alt=""><figcaption></figcaption></figure>

* **Configuration**: Managed via `updatePriceValidation` which sets the `maxPriceDelta` for an asset [contracts/managers/price/PriceOracleMiddlewareManagerLib.sol139-152](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/managers/price/PriceOracleMiddlewareManagerLib.sol#L139-L152)
* **Execution**: Usually triggered via a Pre-Hook (`ValidateAllAssetsPricesPreHook`) before vault actions like `execute` or `deposit` [contracts/handlers/pre\_hooks/pre\_hooks/ValidateAllAssetsPricesPreHook.sol18-23](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/handlers/pre_hooks/pre_hooks/ValidateAllAssetsPricesPreHook.sol#L18-L23)

## Access control and roles

The system utilizes a hierarchy of roles defined in `Roles.sol` to secure configuration.

| Role                                   | Entity                           | Permission                                                                                                                                                                                                                      |
| -------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ADMIN_ROLE`                           | `AccessManager`                  | Highest level; manages all roles [contracts/libraries/Roles.sol11-13](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/libraries/Roles.sol#L11-L13)                                                             |
| `ATOMIST_ROLE`                         | `PlasmaVault`                    | Can update the `priceOracleMiddleware` address [contracts/libraries/Roles.sol44-45](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/libraries/Roles.sol#L44-L45)                                               |
| `PRICE_ORACLE_MIDDLEWARE_MANAGER_ROLE` | `PriceOracleMiddlewareManager`   | Manages asset price sources and validation deltas [contracts/libraries/Roles.sol102-105](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/libraries/Roles.sol#L102-L105)                                        |
| `SET_ASSETS_PRICES_SOURCES`            | `PriceOracleMiddlewareWithRoles` | Global permission to set price sources [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol27](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L27-L27) |
| `ADD_PT_TOKEN_PRICE`                   | `PriceOracleMiddlewareWithRoles` | Permission to deploy Pendle PT feeds [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol28](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L28-L28)   |

## Data normalization

All prices returned by the middleware system are normalized to 18 decimals (WAD) to ensure consistency across the IPOR Fusion protocol.

* **Normalization Formula**: If a feed has $$N$$ decimals, the price is scaled by $$10^{(18-N)}$$ [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol76-77](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L76-L77)
* **Batch Processing**: `getAssetsPrices` allows fetching multiple asset prices in a single call, returning arrays of prices all in 18-decimal format [contracts/price\_oracle/PriceOracleMiddlewareWithRoles.sol92-107](https://github.com/IPOR-Labs/ipor-fusion/blob/c26a0a9d/contracts/price_oracle/PriceOracleMiddlewareWithRoles.sol#L92-L107)


---

# 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.ipor.io/build-on-fusion/developer-guide/price-oracle-middleware.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.
