> For the complete documentation index, see [llms.txt](https://etherfi.gitbook.io/etherfi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://etherfi.gitbook.io/etherfi/products/borrow/price-feeds.md).

# Price Feeds

{% hint style="info" %}
This feature is coming soon.
{% endhint %}

## What a price feed is, and why Borrow needs one

Borrow lets you post assets as collateral and take out a loan against them. To do that, the Lending Protocol has to answer one question continuously: **what is your collateral worth in US dollars right now?**

That number decides three things:

* **How much you can borrow.** Your borrowing power is the USD value of your collateral multiplied by each asset's collateral factor.
* **Whether you are safe.** Your health factor is a comparison of what your collateral is worth against what you owe.
* **When you get liquidated.** If your collateral's value falls far enough relative to your debt, a liquidator can repay part of your loan and take some of your collateral.

A smart contract cannot look up a price by itself. It has no internet connection and no view of any exchange. So the price has to be delivered on-chain by an **oracle** — a service that publishes prices to a contract that anyone can read. The contract we read for a given asset is that asset's **price feed**.

Every price in the Lending Protocol is reported in **US dollars with 8 decimal places**, so a raw on-chain reading of `100000000` means $1.00.

{% hint style="warning" %}
The price feed is the single most safety-critical input to a lending market. If a feed reports a price that is too high, someone can borrow more than their collateral is worth and walk away with the difference. If it reports a price that is too low, healthy users get liquidated for no reason. Everything below exists to make both of those hard.
{% endhint %}

## Who publishes the prices

We do not invent prices. Every price starts life at an independent third-party publisher, and different assets need different kinds of publisher.

### Chainlink

[Chainlink](https://chain.link) is the most widely used oracle network in DeFi and the source for most of our major assets.

It works like this: a network of independent node operators each fetch the price of an asset from many exchanges and data providers. They report their answers on-chain, and the network aggregates them into a single published price. No single operator can move the result, and a price that only exists on one exchange cannot drag the aggregate with it.

Chainlink publishes a new price on either of two triggers:

* **Deviation** — the price has moved more than a set percentage since the last publish.
* **Heartbeat** — a maximum amount of time has passed with no publish, so the feed proves it is still alive even in a flat market.

Both thresholds are Chainlink's, published per feed on their own documentation, and differ from asset to asset: a heavily-traded major pair updates far more often than a thinly-traded one.

Chainlink also publishes **exchange-rate feeds** rather than dollar prices, which is what we use for weETH: a feed that reports how much ETH one weETH is worth. We turn that into a dollar price ourselves — see [composition](#composed-prices-rate-x-underlying) below.

### Veda accountants

Some collateral is a **receipt token** from an ether.fi Liquid vault, such as liquidETH or liquidUSD. These do not trade on the open market in any meaningful volume, so an exchange price would be the wrong thing to use even if one existed.

Instead, the price comes from the vault's own **Accountant** contract, which is the on-chain record of what one vault share is worth in the vault's base asset. Read more in [Veda Vault Architecture](/etherfi/products/liquid/veda-vault.md).

So a liquidETH price is built in two steps: the Accountant says one liquidETH is worth some amount of ETH, and Chainlink says what ETH is worth in dollars.

### Midas

The same idea applies to the Midas-issued receipt tokens. Midas publishes a rate for each token through its own on-chain price proxy, which we read the same way. See [Midas Vault Architecture](/etherfi/products/liquid/midas-vault.md). These publish less often than a market feed does, and we allow for that in the staleness bounds below.

### The OracleSink (tokenized equities)

For the tokenized equity assets, the authoritative price lives on Ethereum mainnet, not on Optimism where the Lending Protocol runs. A relay reads the mainnet price and delivers it across to an Optimism contract called the **OracleSink** using [LayerZero](https://layerzero.network). Our feed reads the sink and checks how old the underlying mainnet reading was when it was taken, so a slow delivery cannot pass off an old price as a fresh one.

## How a price actually gets read

There are three layers between a publisher and a borrowing decision. Each one does exactly one job.

```
  Chainlink aggregator / Veda accountant / Midas proxy / OracleSink
        │   the raw published number
        ▼
  ether.fi price feed
        │   rejects stale, zero, or negative readings
        │   composes rate x underlying, normalises decimals
        ▼
  price cap adapter
        │   caps how fast a yield-bearing asset's value may grow
        ▼
  Lending Protocol oracle  →  the Lending Protocol
```

### Layer 1 — the ether.fi price feed

We deploy one small feed contract per asset. Its job is to read the publisher and refuse to answer if anything looks wrong. It **fails closed**: rather than returning a bad number, it reverts, and the transaction that needed the price fails.

It rejects a reading when:

* **The price is zero or negative.** A publisher that has broken or is reporting nothing at all should never be treated as "this asset is worth nothing."
* **The price is stale.** Every feed has a hard maximum age. If the publisher's last update is older than that, the feed refuses to answer.
* **The source reverts.** Any failure propagates instead of being swallowed.

For assets pegged to the US dollar, the feed also snaps the price to exactly $1.00 when it is within a narrow band of it. This stops ordinary market noise around the peg from moving borrowing power around. The band is fixed in the feed contract.

These feed contracts were audited by [Paladin](https://paladinsec.co).

#### Staleness bounds

Every feed carries a maximum age, set from how often that particular publisher actually updates. A market feed that publishes many times a day gets a tight bound measured in hours; a vault accountant or a Midas proxy that publishes on a slower cycle gets a correspondingly looser one, because holding it to a market-feed bound would make the asset unusable for no safety gain.

The bound is fixed at deployment and cannot be changed afterwards. The live value for any feed can be read on-chain with `rateMaxStaleness()` (or `maxStaleness()`, depending on the feed type).

#### Composed prices (rate x underlying)

Many of these assets are not quoted in dollars at source. A feed can therefore run in two modes:

* **Direct** — the source is already a dollar price. Scale it to 8 decimals and return it.
* **Composed** — the source is a rate in some other asset. Multiply it by that asset's dollar price, which is itself another ether.fi feed with its own staleness check.

So `liquidETH / USD` is the Veda accountant's liquidETH-per-ETH rate multiplied by the `ETH / USD` feed. If either leg is stale, the whole thing fails. This is why the feed descriptions read like `Capped liquidETH / ETH / USD` — that is the full chain, right to left.

### Layer 2 — the price cap adapter

Most of our collateral is **yield-bearing**: one liquidETH buys slightly more ETH each day, one weETH buys slightly more ETH each day. That growth is real, but it is also a place an attacker would like to lie. If someone could make an Accountant report that a share is suddenly worth twice as much, they could borrow against that inflated value and never come back.

So on top of the feed we use a standard, battle-tested **price cap adapter**, unmodified and already in production use on major lending markets elsewhere in DeFi. It enforces a simple rule:

> This asset's exchange rate is allowed to grow by at most **X% per year**, measured from a fixed snapshot taken at a known past date. If the reported rate is above that ceiling, use the ceiling instead.

Normal yield sits comfortably under the ceiling and passes through untouched. A sudden jump — from a bug, a manipulated vault, or a compromised publisher — gets clipped. The attacker cannot borrow against a number the protocol will not accept.

Worth being precise about what this does and does not do:

* It only caps the price **upward**. A genuine fall in value passes through immediately and in full, because under-reporting a fall is what creates bad debt.
* It is a **ceiling, not a smoother**. Day-to-day price movement is not dampened at all.
* If real yield ever outran the ceiling for a sustained period, the asset would price slightly below its true value, making it conservative collateral. That is the intended trade.

The yearly growth ceiling is set per asset by risk review, sized above the yield the asset can plausibly earn but far below the jump an attack would need. A conservative, slow-growing asset gets a tight ceiling; a higher-yielding strategy gets a looser one. The live ceiling for any asset can be read from its adapter with `getMaxYearlyGrowthRatePercent()`.

For the dollar-pegged assets the cap is a flat price ceiling slightly above $1.00 rather than a growth rate, on the reasoning that a dollar stable trading meaningfully above its peg is a signal of something wrong rather than of genuine appreciation. Euro-pegged assets are capped the same way, as a small multiple of the EUR/USD price. These are readable with `getPriceCap()`.

{% hint style="success" %}
**These caps cannot be changed.** The adapter allows a risk admin to re-set the cap parameters, and it looks that permission up on an access-control contract. We pass it our instance's access manager, which does not implement the two functions the adapter asks for (`isRiskAdmin`, `isPoolAdmin`). Those calls revert, so the check can never pass and the setter is permanently unreachable — for us, for our multisig, for anyone. The caps are fixed at deployment.
{% endhint %}

### Layer 3 — the Lending Protocol oracle

The Lending Protocol's oracle contract is its single point of reference for prices. It maps each listed asset to its price feed and is what the protocol calls when it needs to value a position. It requires every feed to report 8 decimals, and it rejects a price of zero.

Only the Spoke contract can change which feed an asset points to, and that change is held on the configurator's domain-admin role — an **Owner Safe multisig transaction**, not something an automated risk process can do.

## How each asset class is priced

Which publisher an asset uses follows from what kind of asset it is, not from a case-by-case decision. All contracts are on **Optimism**.

| Asset class                            | Price chain                   | Publisher                                |
| -------------------------------------- | ----------------------------- | ---------------------------------------- |
| Major crypto assets and dollar stables | direct USD price              | Chainlink                                |
| Liquid staking receipt tokens          | rate × underlying USD         | Chainlink rate feed + Chainlink USD feed |
| Veda vault receipt tokens              | vault rate × underlying USD   | Veda accountant + Chainlink              |
| Midas receipt tokens                   | proxy rate × underlying USD   | Midas proxy + Chainlink                  |
| Tokenized equities                     | relayed rate × underlying USD | OracleSink relay + Chainlink             |

Dollar-pegged assets carry a flat price ceiling; yield-bearing receipt tokens carry a yearly growth ceiling; assets that are neither are uncapped, since there is no exchange rate for an attacker to inflate.

The authoritative, current list of what is listed and which feed each asset uses is on-chain, not in this document. Read it from the oracle: `getReserveSource(reserveId)` gives the feed address for a reserve, and `getReservePrice(reserveId)` gives the price it currently reports. Each feed's `description()` names its full composition chain — for example `Capped liquidETH / ETH / USD`.

### Contract addresses

<table><thead><tr><th width="200">Contract</th><th>Address</th></tr></thead><tbody><tr><td>Oracle</td><td><code>0xe8cbd37210bF1E29436dAe183d7b9fe45E886fA8</code></td></tr><tr><td>Spoke</td><td><code>0xdffcC3536D932eb51Df51a7F5FA407c4270d5308</code></td></tr><tr><td>Hub</td><td><code>0x66753c4e3fC84f1eD0e3C267C927284E9d90C572</code></td></tr></tbody></table>

For the current collateral factors and liquidation settings per asset, see [Lending Market Parameters](/etherfi/products/borrow/lending-market-parameters.md).

## A worked example: weETH

weETH is the clearest illustration, because it uses every layer.

1. **Chainlink publishes the weETH/ETH exchange rate.** This is a rate, not a dollar price — it says how much ETH one weETH is worth. It sits a little above 1 and rises slowly as staking rewards accrue.
2. **Chainlink separately publishes ETH/USD.**
3. **Our `ETH / USD` feed** reads the ETH/USD aggregator and refuses to answer if it is older than its staleness bound.
4. **Our `weETH / ETH rate` feed** reads the rate aggregator under its own bound.
5. **The cap adapter** takes the rate, compares it against a ceiling that grows at a fixed maximum rate from a snapshot taken at a known past date, uses whichever is lower, and multiplies by the ETH price.
6. **The oracle** returns the result to the Lending Protocol.

In normal conditions the exchange rate sits below the ceiling with room to spare, and the cap does nothing at all — it is there for the day something goes wrong, not for ordinary operation. You can check this yourself at any time: an adapter's `isCapped()` reports whether the ceiling is currently binding, and `getRatio()` against the ceiling implied by `getSnapshotRatio()`, `getSnapshotTimestamp()` and `getMaxRatioGrowthPerSecond()` shows how much headroom is left.

## What can go wrong, and what happens then

| Situation                                     | What happens                                                                                                                           |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| A publisher stops updating                    | The feed's staleness check fails. Borrowing and liquidations against that asset revert rather than using an old price.                 |
| A publisher reports zero or a negative number | Rejected outright; the feed reverts.                                                                                                   |
| A vault rate jumps implausibly high           | The cap adapter clips it to the ceiling. No inflated borrowing power.                                                                  |
| An asset genuinely falls in price             | Passed through in full and immediately. Health factors fall and liquidations become possible — this is the system working as intended. |
| One leg of a composed price is stale          | The whole composed price fails. There is no partial answer.                                                                            |

The consistent theme: when the protocol is not confident about a price, it stops rather than guessing. That can mean a borrow or a liquidation temporarily reverts, which is the deliberate trade — a paused market is recoverable, a market that acted on a wrong price is not.

## Further reading

* [Technical Documentation](/etherfi/products/borrow/technical-documentation.md) — how borrowing and lending works
* [Lending Market Parameters](/etherfi/products/borrow/lending-market-parameters.md) — collateral factors, liquidation settings, interest curves
* [Chainlink documentation](https://docs.chain.link/data-feeds)


---

# 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://etherfi.gitbook.io/etherfi/products/borrow/price-feeds.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.
