# Overview

Source: [https://docs.curve.finance/developer/crvusd/oracles/overview](https://docs.curve.finance/developer/crvusd/oracles/overview)

As crvUSD markets use internal oracles, they utilize in-house liquidity pools to aggregate the price of collateral. But there is a possibility to use Chainlink oracle prices as safety limits.

`CryptoWithStablePrice*.vy`

Each market has its own oracle contract. Source code is available on [GitHub](https://github.com/curvefi/curve-stablecoin/tree/master/curve_stablecoin/price_oracles). Relevant deployments can be found [here](https://docs.curve.finance/developer/deployments.md).

warning

Every market has its own price oracle contract, which can be fetched by calling `price_oracle_contract` within the controller of the market. The [wstETH oracle](https://etherscan.io/address/0xc1793A29609ffFF81f10139fa0A7A444c9e106Ad#code) will be used for the purpose of this documentation. Please be aware that oracle contracts can vary based on the collateral token.

tip

The formulas below use slightly different terminologies than the code to make them easier to read. For abbreviations, see [here](https://docs.curve.finance/developer/crvusd/oracles/overview.md#terminology-used-in-code).

<a id="cryptowithstableprice-variants"></a>

## CryptoWithStablePrice\* Variants

The `CryptoWithStablePrice` oracle family is specifically designed for **crvUSD mint markets**. Each variant is tailored to a particular collateral type — the wstETH variant shown on this page is the most complex, using TVL-weighted tricrypto pools, staked ETH pricing, and optional Chainlink safety limits. Other variants are simpler, but all share the same core pattern: **read price oracles from Curve pools, apply collateral-specific adjustments, and optionally bound with Chainlink**.

| Variant | Collateral | Vyper | Pools | TVL Weighting |
| --- | --- | --- | --- | --- |
| [`CryptoWithStablePrice`](https://github.com/curvefi/curve-stablecoin/blob/master/curve_stablecoin/price_oracles/CryptoWithStablePrice.vy) | sfrxETH | `0.3.10` | 2 tricrypto + 2 stableswap | Yes |
| [`CryptoWithStablePriceTBTC`](https://github.com/curvefi/curve-stablecoin/blob/master/curve_stablecoin/price_oracles/CryptoWithStablePriceTBTC.vy) | tBTC | `0.3.10` | 2 tricrypto + 2 stableswap | Yes |
| [`CryptoWithStablePriceWstethN`](https://github.com/curvefi/curve-stablecoin/blob/master/curve_stablecoin/price_oracles/CryptoWithStablePriceWstethN.vy) | wstETH | `0.3.10` | 2 tricrypto + 2 stableswap + staked swap | Yes |
| [`CryptoWithStablePriceWBTC`](https://github.com/curvefi/curve-stablecoin/blob/master/curve_stablecoin/price_oracles/CryptoWithStablePriceWBTC.vy) | WBTC | `0.3.10` | 2 tricrypto + 2 stableswap | Yes |
| [`CryptoWithStablePriceAndChainlink`](https://github.com/curvefi/curve-stablecoin/blob/master/curve_stablecoin/price_oracles/CryptoWithStablePriceAndChainlink.vy) | ETH | `0.3.10` | 1 tricrypto + 1 stableswap | No |
| [`CryptoWithStablePriceFrxethN`](https://github.com/curvefi/curve-stablecoin/blob/master/curve_stablecoin/price_oracles/CryptoWithStablePriceFrxethN.vy) | sfrxETH v2 | `0.3.10` | 2 tricrypto + 2 stableswap + staked swap | Yes |

Not all crvUSD markets use `CryptoWithStablePrice*` oracles. Some markets use oracle contracts from the `CryptoFromPool*` family, which are shared with the lending system:

-   **[CryptoFromPoolVaultWAgg](https://docs.curve.finance/developer/crvusd/oracles/crypto-from-pool-vault-w-agg.md)** — for ERC-4626 vault token collateral (e.g., sFRAX)
-   **[CryptoFromPoolsRateWAgg](https://docs.curve.finance/developer/crvusd/oracles/crypto-from-pools-rate-w-agg.md)** — for collateral requiring multi-pool price chaining with rate adjustments

<a id="ema-of-tvl"></a>

## EMA of TVL

`_ema_tvl()` calculates the *exponential moving average* (EMA) of the *total value locked* (TVL) for `TRICRYPTO` pools.

This value is subsequently used in the internal function `_raw_price()` to compute the *weighted price of ETH*.

**▶\`\_ema\_tvl() -> uint256\[N\_POOLS\]:\`▼**

```vyper
last_timestamp: public(uint256)
last_tvl: public(uint256[N_POOLS])
TVL_MA_TIME: public(constant(uint256)) = 50000  # s

@internal
@view
def _ema_tvl() -> uint256[N_POOLS]:
    last_timestamp: uint256 = self.last_timestamp
    last_tvl: uint256[N_POOLS] = self.last_tvl

    if last_timestamp < block.timestamp:
        alpha: uint256 = self.exp(- convert((block.timestamp - last_timestamp) * 10**18 / TVL_MA_TIME, int256))
        # alpha = 1.0 when dt = 0
        # alpha = 0.0 when dt = inf
        for i in range(N_POOLS):
            tvl: uint256 = TRICRYPTO[i].totalSupply() * TRICRYPTO[i].virtual_price() / 10**18
            last_tvl[i] = (tvl * (10**18 - alpha) + last_tvl[i] * alpha) / 10**18

    return last_tvl
```

$tvl_{i} = \frac{TS_i \cdot VP_i}{10^{18}}$

$\text{last\_tvl}_i = \frac{tvl_i \cdot (10^{18} - \alpha) + \text{last\_tvl}_i \cdot \alpha}{10^{18}}$

$tvl_i = \text{TVL of i-th pool}$ in `TRICRYPTO[N_POOLS]`  
$TS_i = \text{total supply of i-th pool}$ in `TRICRYPTO[N_POOLS]`  
$VP_i = \text{virtual price of i-th pool}$ in `TRICRYPTO[N_POOLS]` $\text{last\_tvl}_i = \text{smoothed TVL of i-th pool}$ in `TRICRYPTO[N_POOLS]`

<a id="ema_tvl"></a>

### `ema_tvl`

`Oracle.ema_tvl() -> uint256[N_POOLS]: view`

Function to calculate the Total-Value-Locked (TVL) Exponential-Moving-Average (EMA) of the `TRICRYPTO` pools.

Returns: `last_tvl` (`uint256[N_POOLS]`).

**<>Source code▼**

```vyper
@external
@view
def ema_tvl() -> uint256[N_POOLS]:
    return self._ema_tvl()

@internal
@view
def _ema_tvl() -> uint256[N_POOLS]:
    last_timestamp: uint256 = self.last_timestamp
    last_tvl: uint256[N_POOLS] = self.last_tvl

    if last_timestamp < block.timestamp:
        alpha: uint256 = self.exp(- convert((block.timestamp - last_timestamp) * 10**18 / TVL_MA_TIME, int256))
        # alpha = 1.0 when dt = 0
        # alpha = 0.0 when dt = inf
        for i in range(N_POOLS):
            tvl: uint256 = TRICRYPTO[i].totalSupply() * TRICRYPTO[i].virtual_price() / 10**18
            last_tvl[i] = (tvl * (10**18 - alpha) + last_tvl[i] * alpha) / 10**18

    return last_tvl
```

**▶Example▼**

```shell
>>> Oracle.ema_tvl()
38652775551183170655949, 40849321168337010409906
```

<a id="last_tvl"></a>

### `last_tvl`

`Oracle.last_tvl(arg0: uint256) -> uint256: view`

Getter for the `last_tvl` of the tricrypto pool at index `arg0`.

| Input | Type | Description |
| --- | --- | --- |
| `arg0` | `uint256` | Index |

Returns: last tvl value (`uint256`).

**<>Source code▼**

```vyper
last_tvl: public(uint256[N_POOLS])
```

**▶Example▼**

```shell
>>> Oracle.last_tvl(0)
38650114241563018578505
```

<a id="calculate-raw-price"></a>

## Calculate Raw Price

The internal `_raw_price()` function calculates the *raw price of the collateral token*.

**▶\`\_raw\_price(tvls: uint256\[N\_POOLS\], agg\_price: uint256) -> uint256:\`▼**

```vyper
@internal
@view
def _raw_price(tvls: uint256[N_POOLS], agg_price: uint256) -> uint256:
    weighted_price: uint256 = 0
    weights: uint256 = 0
    for i in range(N_POOLS):
        p_crypto_r: uint256 = TRICRYPTO[i].price_oracle(TRICRYPTO_IX[i])   # d_usdt/d_eth
        p_stable_r: uint256 = STABLESWAP[i].price_oracle()                 # d_usdt/d_st
        p_stable_agg: uint256 = agg_price                                  # d_usd/d_st
        if IS_INVERSE[i]:
            p_stable_r = 10**36 / p_stable_r
        weight: uint256 = tvls[i]
        # Prices are already EMA but weights - not so much
        weights += weight
        weighted_price += p_crypto_r * p_stable_agg / p_stable_r * weight     # d_usd/d_eth
    crv_p: uint256 = weighted_price / weights

    use_chainlink: bool = self.use_chainlink

    # Limit ETH price
    if use_chainlink:
        chainlink_lrd: ChainlinkAnswer = CHAINLINK_AGGREGATOR_ETH.latestRoundData()
        if block.timestamp - min(chainlink_lrd.updated_at, block.timestamp) <= CHAINLINK_STALE_THRESHOLD:
            chainlink_p: uint256 = convert(chainlink_lrd.answer, uint256) * 10**18 / CHAINLINK_PRICE_PRECISION_ETH
            lower: uint256 = chainlink_p * (10**18 - BOUND_SIZE) / 10**18
            upper: uint256 = chainlink_p * (10**18 + BOUND_SIZE) / 10**18
            crv_p = min(max(crv_p, lower), upper)

    p_staked: uint256 = STAKEDSWAP.price_oracle()  # d_eth / d_steth

    # Limit STETH price
    if use_chainlink:
        chainlink_lrd: ChainlinkAnswer = CHAINLINK_AGGREGATOR_STETH.latestRoundData()
        if block.timestamp - min(chainlink_lrd.updated_at, block.timestamp) <= CHAINLINK_STALE_THRESHOLD:
            chainlink_p: uint256 = convert(chainlink_lrd.answer, uint256) * 10**18 / CHAINLINK_PRICE_PRECISION_STETH
            lower: uint256 = chainlink_p * (10**18 - BOUND_SIZE) / 10**18
            upper: uint256 = chainlink_p * (10**18 + BOUND_SIZE) / 10**18
            p_staked = min(max(p_staked, lower), upper)

    p_staked = min(p_staked, 10**18) * WSTETH.stEthPerToken() / 10**18  # d_eth / d_wsteth

    return p_staked * crv_p / 10**18
```

$price_{weighted} = \frac{price_{eth} \cdot price_{crvusd}}{price_{usd}} \cdot weight$

$totalPrice_{weighted} = \frac{\sum{price_{weighted}}}{\sum{weight}}$

$price_{stETH} = \min(price_{stETH}, 10^{18}) \cdot \frac{rate_{wstETH}}{10^{18}}$

$price = price_{stETH} \cdot totalPrice_{weighted}$

$price_{weighted} =$ weighted price of ETH  
$totalPrice_{weighted} =$ total weighted price of ETH  
$price_{eth} =$ price oracle of eth in the tricrypto pools w.r.t usdc/usdt  
$price_{usd} =$ price oracle of stableswap pool  
$price_{crvusd} =$ price oracle of crvusd  
$price_{stETH} =$ price of stETH w.r.t ETH  
$rate_{wstETH} =$ amount of stETH for 1 wstETH

<a id="raw_price"></a>

### `raw_price`

`Oracle.raw_price() -> uint256: view`

Function to calculate the raw price.

Returns: raw price (`uint256`).

**<>Source code▼**

```vyper
@external
@view
def raw_price() -> uint256:
    return self._raw_price()

@internal
@view
def _raw_price(tvls: uint256[N_POOLS], agg_price: uint256) -> uint256:
    weighted_price: uint256 = 0
    weights: uint256 = 0
    for i in range(N_POOLS):
        p_crypto_r: uint256 = TRICRYPTO[i].price_oracle(TRICRYPTO_IX[i])   # d_usdt/d_eth
        p_stable_r: uint256 = STABLESWAP[i].price_oracle()                 # d_usdt/d_st
        p_stable_agg: uint256 = agg_price                                  # d_usd/d_st
        if IS_INVERSE[i]:   
            p_stable_r = 10**36 / p_stable_r
        weight: uint256 = tvls[i]
        # Prices are already EMA but weights - not so much
        weights += weight
        weighted_price += p_crypto_r * p_stable_agg / p_stable_r * weight     # d_usd/d_eth
    crv_p: uint256 = weighted_price / weights

    use_chainlink: bool = self.use_chainlink

    # Limit ETH price
    if use_chainlink:
        chainlink_lrd: ChainlinkAnswer = CHAINLINK_AGGREGATOR_ETH.latestRoundData()
        if block.timestamp - min(chainlink_lrd.updated_at, block.timestamp) <= CHAINLINK_STALE_THRESHOLD:
            chainlink_p: uint256 = convert(chainlink_lrd.answer, uint256) * 10**18 / CHAINLINK_PRICE_PRECISION_ETH
            lower: uint256 = chainlink_p * (10**18 - BOUND_SIZE) / 10**18
            upper: uint256 = chainlink_p * (10**18 + BOUND_SIZE) / 10**18
            crv_p = min(max(crv_p, lower), upper)

    p_staked: uint256 = STAKEDSWAP.price_oracle()  # d_eth / d_steth

    # Limit STETH price
    if use_chainlink:
        chainlink_lrd: ChainlinkAnswer = CHAINLINK_AGGREGATOR_STETH.latestRoundData()
        if block.timestamp - min(chainlink_lrd.updated_at, block.timestamp) <= CHAINLINK_STALE_THRESHOLD:
            chainlink_p: uint256 = convert(chainlink_lrd.answer, uint256) * 10**18 / CHAINLINK_PRICE_PRECISION_STETH
            lower: uint256 = chainlink_p * (10**18 - BOUND_SIZE) / 10**18
            upper: uint256 = chainlink_p * (10**18 + BOUND_SIZE) / 10**18
            p_staked = min(max(p_staked, lower), upper)

    p_staked = min(p_staked, 10**18) * WSTETH.stEthPerToken() / 10**18  # d_eth / d_wsteth

    return p_staked * crv_p / 10**18
```

**▶Example▼**

```shell
>>> Oracle.raw_price()
1970446024043370547236
```

<a id="chainlink-limits"></a>

## Chainlink Limits

The oracle contracts have the option to utilize Chainlink prices, which serve as safety limits. When enabled, these limits are triggered if the Chainlink price deviates by more than 1.5% (represented by `BOUND_SIZE`) from the internal price oracles.

Chainlink limits can be turned on and off by calling `set_use_chainlink(do_it: bool)`, which can only be done by the admin of the Factory contract.

![](https://docs.curve.finance/assets/images/oracle_chainlink_vs_internal-841b3a80c058e155f34a4c16d7f31167.png)

Chainlink vs Internal Oracle

<a id="use_chainlink"></a>

### `use_chainlink`

`Oracle.use_chainlink() -> bool: view`

Getter method to check if chainlink oracles are turned on or off.

Returns: True or False (`bool`).

**<>Source code▼**

```vyper
use_chainlink: public(bool)
```

**▶Example▼**

```shell
>>> Oracle.use_chainlink()
'False'
```

<a id="set_use_chainlink"></a>

### `set_use_chainlink`

`Oracle.set_use_chainlink(do_it: bool)`

Guarded Method

This function is only callable by the `admin` of the Factory contract.

Function to toggle the usage of chainlink limits.

| Input | Type | Description |
| --- | --- | --- |
| `do_it` | `bool` | Bool to toggle the usage of chainlink oracles |

**<>Source code▼**

```vyper
use_chainlink: public(bool)

@external
def set_use_chainlink(do_it: bool):
    assert msg.sender == FACTORY.admin()
    self.use_chainlink = do_it
```

**▶Example▼**

```shell
>>> Oracle.set_use_chainlink('False')
```

<a id="terminology-used-in-code"></a>

## Terminology used in Code

| terminology used in code |  |
| --- | --- |
| $\alpha$ | `alpha` |
| $\exp$ | `exp(power: int256) -> uint256:` |
| $TS_i$ | `TRICRYPTO[i].totalSupply()` |
| $VP_i$ | `TRICRYPTO[i].virtual_price()` |
| $price_{eth}$ | `p_crypto_r` |
| $price_{usd}$ | `p_stable_agg` |
| $price_{crvusd}$ | `p_stable_r` |
| $price_{weighted}$ | `weighted_price` |
| $totalETH_{price}$ | `crv_p` |

<a id="contract-info-methods"></a>

## Contract Info Methods

<a id="n_pools"></a>

### `N_POOLS`

`Oracle.N_POOLS() -> uint256: view`

Getter for the number of external pools used by the oracle.

Returns: number of pools (`uint256`).

**<>Source code▼**

```vyper
N_POOLS: public(constant(uint256)) = 2
```

**▶Example▼**

```shell
>>> Oracle.N_POOLS()
2
```

<a id="tricrypto"></a>

### `TRICRYPTO`

`Oracle.TRICRYPTO(arg0: uint256) -> address: view`

Getter for the tricrypto pool at index `arg0`.

Returns: tricrypto pool address (`address`).

| Input | Type | Description |
| --- | --- | --- |
| `arg0` | `uint256` | Index |

**<>Source code▼**

```vyper
TRICRYPTO: public(immutable(Tricrypto[N_POOLS]))
```

**▶Example▼**

```shell
>>> Oracle.TRICRYPTO(0)
'0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B'
```

<a id="tricrypto_ix"></a>

### `TRICRYPTO_IX`

`Oracle.TRICRYPTO_IX(arg0: uint256) -> uint256: view`

Getter for the index of ETH in the tricrypto pool w.r.t the coin at index 0.

Returns: Index of ETH price oracle in the tricrypto pool (`uint256`).

tip

Returns 1, as ETH price oracle index in the tricrypto pool is 1. If the same index would be 0, it would return the price oracle of ETH. Their prices are all w.r.t the coin at index 0 (USDC or USDT).

| Input | Type | Description |
| --- | --- | --- |
| `arg0` | `uint256` | Index of `TRICRYPTO` |

**<>Source code▼**

```vyper
TRICRYPTO_IX: public(immutable(uint256[N_POOLS]))
```

**▶Example▼**

```shell
>>> Oracle.TRICRYPTO_IX(0)
1
```

<a id="stableswap_aggregator"></a>

### `STABLESWAP_AGGREGATOR`

`Oracle.STABLESWAP_AGGREGATOR() -> address: view`

Getter for contract of the crvusd price aggregator.

Returns: contract (`address`).

**<>Source code▼**

```vyper
STABLESWAP_AGGREGATOR: public(immutable(StableAggregator))
```

**▶Example▼**

```shell
>>> Oracle.STABLESWAP_AGGREGATOR()
'0x18672b1b0c623a30089A280Ed9256379fb0E4E62'
```

<a id="stableswap"></a>

### `STABLESWAP`

`Oracle.STABLESWAP(arg0: uint256) -> address: view`

Getter for the stableswap pool at index `arg0`.

Returns: stableswap pool (`address`).

| Input | Type | Description |
| --- | --- | --- |
| `arg0` | `uint256` | Index of `STABLESWAP` |

**<>Source code▼**

```vyper
STABLESWAP: public(immutable(Stableswap[N_POOLS]))
```

**▶Example▼**

```shell
>>> Oracle.STABLESWAP(0)
'0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E'
```

<a id="stablecoin"></a>

### `STABLECOIN`

`Oracle.STABLECOIN() -> address: view`

Getter for the contract address of crvUSD.

Returns: crvUSD contract (`address`).

**<>Source code▼**

```vyper
STABLECOIN: public(immutable(address))
```

**▶Example▼**

```shell
>>> Oracle.STABLECOIN()
'0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E'
```

<a id="factory"></a>

### `FACTORY`

`Oracle.FACTORY() -> address: view`

Getter for the contract address of the Factory.

Returns: factory contract (`address`).

**<>Source code▼**

```vyper
FACTORY: public(immutable(ControllerFactory))
```

**▶Example▼**

```shell
>>> Oracle.FACTORY()
'0xC9332fdCB1C491Dcc683bAe86Fe3cb70360738BC'
```

<a id="bound_size"></a>

### `BOUND_SIZE`

`Oracle.BOUND_SIZE() -> uint256: view`

Getter for the bound size of the chainlink oracle limits. This essentially is the size of the safety limits.

Returns: bound size (`uint256`).

**<>Source code▼**

```vyper
BOUND_SIZE: public(immutable(uint256))
```

**▶Example▼**

```shell
>>> Oracle.BOUND_SIZE()
15000000000000000
```

<a id="stakedswap"></a>

### `STAKEDSWAP`

`Oracle.STAKEDSWAP() -> address: view`

Getter for the stETH/ETH stableswap pool.

Returns: pool contract (`address`).

**<>Source code▼**

```vyper
STAKEDSWAP: public(immutable(Stableswap))
```

**▶Example▼**

```shell
>>> Oracle.STAKEDSWAP()
'0x21E27a5E5513D6e65C4f830167390997aA84843a'
```

<a id="wsteth"></a>

### `WSTETH`

`Oracle.WSTETH() -> address: view`

Getter for the wstETH contract address.

Returns: wstETH contract (`address`).

**<>Source code▼**

```vyper
WSTETH: public(immutable(wstETH))
```

**▶Example▼**

```shell
>>> Oracle.WSTETH()
'0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'
```

<a id="last_timestamp"></a>

### `last_timestamp`

`Oracle.last_timestamp() -> uint256: view`

Getter for the last timestamp when `price_w()` was called.

Returns: timestamp (`uint256`).

**<>Source code▼**

```vyper
last_timestamp: public(uint256)
```

**▶Example▼**

```shell
>>> Oracle.last_timestamp()
1692613703
```

<a id="tvl_ma_time"></a>

### `TVL_MA_TIME`

`Oracle.TVL_MA_TIME() -> uint256: view`

Getter for the Exponential-Moving-Average time.

Returns: ema time (`uint256`).

**<>Source code▼**

```vyper
TVL_MA_TIME: public(constant(uint256)) = 50000  # s
```

**▶Example▼**

```shell
>>> Oracle.TVL_MA_TIME()
50000
```

<a id="price"></a>

### `price`

`Oracle.price() -> uint256: view`

Function to calculate the raw price of the collateral token.

Returns: raw price (`uint256`).

**<>Source code▼**

```vyper
@external
@view
def price() -> uint256:
    return self._raw_price(self._ema_tvl(), STABLESWAP_AGGREGATOR.price())

@internal
@view
def _raw_price(tvls: uint256[N_POOLS], agg_price: uint256) -> uint256:
    weighted_price: uint256 = 0
    weights: uint256 = 0
    for i in range(N_POOLS):
        p_crypto_r: uint256 = TRICRYPTO[i].price_oracle(TRICRYPTO_IX[i])   # d_usdt/d_eth
        p_stable_r: uint256 = STABLESWAP[i].price_oracle()                 # d_usdt/d_st
        p_stable_agg: uint256 = agg_price                                  # d_usd/d_st
        if IS_INVERSE[i]:   
            p_stable_r = 10**36 / p_stable_r
        weight: uint256 = tvls[i]
        # Prices are already EMA but weights - not so much
        weights += weight
        weighted_price += p_crypto_r * p_stable_agg / p_stable_r * weight     # d_usd/d_eth
    crv_p: uint256 = weighted_price / weights

    use_chainlink: bool = self.use_chainlink

    # Limit ETH price
    if use_chainlink:
        chainlink_lrd: ChainlinkAnswer = CHAINLINK_AGGREGATOR_ETH.latestRoundData()
        if block.timestamp - min(chainlink_lrd.updated_at, block.timestamp) <= CHAINLINK_STALE_THRESHOLD:
            chainlink_p: uint256 = convert(chainlink_lrd.answer, uint256) * 10**18 / CHAINLINK_PRICE_PRECISION_ETH
            lower: uint256 = chainlink_p * (10**18 - BOUND_SIZE) / 10**18
            upper: uint256 = chainlink_p * (10**18 + BOUND_SIZE) / 10**18
            crv_p = min(max(crv_p, lower), upper)

    p_staked: uint256 = STAKEDSWAP.price_oracle()  # d_eth / d_steth

    # Limit STETH price
    if use_chainlink:
        chainlink_lrd: ChainlinkAnswer = CHAINLINK_AGGREGATOR_STETH.latestRoundData()
        if block.timestamp - min(chainlink_lrd.updated_at, block.timestamp) <= CHAINLINK_STALE_THRESHOLD:
            chainlink_p: uint256 = convert(chainlink_lrd.answer, uint256) * 10**18 / CHAINLINK_PRICE_PRECISION_STETH
            lower: uint256 = chainlink_p * (10**18 - BOUND_SIZE) / 10**18
            upper: uint256 = chainlink_p * (10**18 + BOUND_SIZE) / 10**18
            p_staked = min(max(p_staked, lower), upper)

    p_staked = min(p_staked, 10**18) * WSTETH.stEthPerToken() / 10**18  # d_eth / d_wsteth

    return p_staked * crv_p / 10**18
```

**▶Example▼**

```shell
>>> Oracle.price()
1970446024043370547236
```

<a id="price_w"></a>

### `price_w`

`Oracle.price_w() -> uint256`

Function to obtain the oracle price of the collateral token and update `last_tvl` and `last_timestamp`. This function is used in the AMM.

Returns: oracle price of the collateral token (`uint256`).

**<>Source code▼**

```vyper
@external
def price_w() -> uint256:
    tvls: uint256[N_POOLS] = self._ema_tvl()
    if self.last_timestamp < block.timestamp:
        self.last_timestamp = block.timestamp
        self.last_tvl = tvls
    return self._raw_price(tvls, STABLESWAP_AGGREGATOR.price_w())
```

**▶Example▼**

```shell
>>> Oracle.price_w()
```
