Skip to main content

CryptoFromPoolVaultWAgg

This oracle contract derives the price of ERC-4626 vault token collateral by reading a price oracle from a Curve liquidity pool and applying the vault's redemption rate (convertToAssets). It then multiplies by the aggregated crvUSD price to produce a USD-denominated oracle price, making it suitable for crvUSD mint markets.

CryptoFromPoolVaultWAgg.vy

The source code for the CryptoFromPoolVaultWAgg.vy contract can be found on GitHub. The contract is written in Vyper version 0.3.10.

Each crvUSD market using this oracle has its own deployment. The oracle address can be fetched by calling price_oracle_contract on the market's Controller.

{ }Contract ABI
[{"stateMutability":"view","type":"function","name":"price","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"price_w","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"POOL","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"BORROWED_IX","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"COLLATERAL_IX","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"N_COINS","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"NO_ARGUMENT","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"VAULT","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"AGG","inputs":[],"outputs":[{"name":"","type":"address"}]}]
Oracle Suitability

CryptoFromPoolVaultWAgg.vy is only suitable for vaults which cannot be affected by donation attacks (e.g., sFRAX). Vaults vulnerable to donation attacks should use a different oracle type.

Oracle Immutability

The oracle contract is fully immutable. Once deployed, it cannot change any parameters, stop price updates, or alter the pool used to calculate prices. All relevant data is passed into the __init__ function during deployment.

`__init__`
@external
def __init__(
pool: Pool,
N: uint256,
borrowed_ix: uint256,
collateral_ix: uint256,
vault: Vault,
agg: StableAggregator
):
assert borrowed_ix != collateral_ix
assert borrowed_ix < N
assert collateral_ix < N
POOL = pool
N_COINS = N
BORROWED_IX = borrowed_ix
COLLATERAL_IX = collateral_ix
VAULT = vault
AGG = agg

no_argument: bool = False
if N == 2:
success: bool = False
res: Bytes[32] = empty(Bytes[32])
success, res = raw_call(
pool.address,
_abi_encode(empty(uint256), method_id=method_id("price_oracle(uint256)")),
max_outsize=32, is_static_call=True, revert_on_failure=False)
if not success:
no_argument = True
NO_ARGUMENT = no_argument
Lending Variant

A base variant without the aggregated crvUSD price (CryptoFromPoolVault.vy) is also available. Both variants are documented together on the lending oracle page, which includes additional detail on rate limiting and side-by-side code comparisons.


How the Price is Calculated

The oracle computes the collateral price in three steps:

  1. Pool price oracle — reads the internal price oracle from the Curve pool, extracting the relative price between the collateral and borrowed assets
  2. Vault redemption — multiplies by VAULT.convertToAssets(10**18) to convert from vault shares to underlying
  3. USD normalization — multiplies by the aggregated crvUSD/USD price from AGG

price=pcollateralpborrowed×convertToAssets(1018)1018×AGG.price()1018\text{price} = \frac{p_{\text{collateral}}}{p_{\text{borrowed}}} \times \frac{\text{convertToAssets}(10^{18})}{10^{18}} \times \frac{\text{AGG.price}()}{10^{18}}

The internal _raw_price() function handles steps 1-2, while price() and price_w() apply step 3.

@internal
@view
def _raw_price() -> uint256:
p_borrowed: uint256 = 10**18
p_collateral: uint256 = 10**18

if NO_ARGUMENT:
p: uint256 = POOL.price_oracle()
if COLLATERAL_IX > 0:
p_collateral = p
else:
p_borrowed = p

else:
if BORROWED_IX > 0:
p_borrowed = POOL.price_oracle(BORROWED_IX - 1)
if COLLATERAL_IX > 0:
p_collateral = POOL.price_oracle(COLLATERAL_IX - 1)

return p_collateral * VAULT.convertToAssets(10**18) / p_borrowed

Price Functions

price

CryptoFromPoolVaultWAgg.price() -> uint256: view

Returns the current USD price of the collateral token. Reads the pool's price oracle, applies the vault redemption rate, and multiplies by the aggregated crvUSD price.

Returns: collateral price in USD (uint256).

<>Source code
@external
@view
def price() -> uint256:
return self._raw_price() * AGG.price() / 10**18

@internal
@view
def _raw_price() -> uint256:
p_borrowed: uint256 = 10**18
p_collateral: uint256 = 10**18

if NO_ARGUMENT:
p: uint256 = POOL.price_oracle()
if COLLATERAL_IX > 0:
p_collateral = p
else:
p_borrowed = p

else:
if BORROWED_IX > 0:
p_borrowed = POOL.price_oracle(BORROWED_IX - 1)
if COLLATERAL_IX > 0:
p_collateral = POOL.price_oracle(COLLATERAL_IX - 1)

return p_collateral * VAULT.convertToAssets(10**18) / p_borrowed
Example
>>> CryptoFromPoolVaultWAgg.price()
1020187011799809503

price_w

CryptoFromPoolVaultWAgg.price_w() -> uint256

Write version of price(). Calls AGG.price_w() instead of AGG.price(), which updates the aggregator's internal state (EMA of crvUSD prices). This function is called by the AMM during regular operations to keep the aggregator up to date.

Returns: collateral price in USD (uint256).

<>Source code
@external
def price_w() -> uint256:
return self._raw_price() * AGG.price_w() / 10**18

@internal
@view
def _raw_price() -> uint256:
p_borrowed: uint256 = 10**18
p_collateral: uint256 = 10**18

if NO_ARGUMENT:
p: uint256 = POOL.price_oracle()
if COLLATERAL_IX > 0:
p_collateral = p
else:
p_borrowed = p

else:
if BORROWED_IX > 0:
p_borrowed = POOL.price_oracle(BORROWED_IX - 1)
if COLLATERAL_IX > 0:
p_collateral = POOL.price_oracle(COLLATERAL_IX - 1)

return p_collateral * VAULT.convertToAssets(10**18) / p_borrowed
Example
>>> CryptoFromPoolVaultWAgg.price_w()
1020187011799809503

Contract Info Methods

POOL

CryptoFromPoolVaultWAgg.POOL() -> address: view

Getter for the Curve pool used as the price source.

Returns: pool address (address).

<>Source code
POOL: public(immutable(Pool))
Example
>>> CryptoFromPoolVaultWAgg.POOL()
'0x...'

BORROWED_IX

CryptoFromPoolVaultWAgg.BORROWED_IX() -> uint256: view

Getter for the index of the borrowed asset in the pool.

Returns: coin index (uint256).

<>Source code
BORROWED_IX: public(immutable(uint256))
Example
>>> CryptoFromPoolVaultWAgg.BORROWED_IX()
0

COLLATERAL_IX

CryptoFromPoolVaultWAgg.COLLATERAL_IX() -> uint256: view

Getter for the index of the collateral asset in the pool.

Returns: coin index (uint256).

<>Source code
COLLATERAL_IX: public(immutable(uint256))
Example
>>> CryptoFromPoolVaultWAgg.COLLATERAL_IX()
1

N_COINS

CryptoFromPoolVaultWAgg.N_COINS() -> uint256: view

Getter for the number of coins in the pool.

Returns: number of coins (uint256).

<>Source code
N_COINS: public(immutable(uint256))
Example
>>> CryptoFromPoolVaultWAgg.N_COINS()
2

NO_ARGUMENT

CryptoFromPoolVaultWAgg.NO_ARGUMENT() -> bool: view

Getter that indicates whether the pool's price_oracle() function is called without arguments (true for 2-coin pools where the no-argument variant is available) or with a coin index argument.

Returns: true if no argument needed (bool).

<>Source code
NO_ARGUMENT: public(immutable(bool))
Example
>>> CryptoFromPoolVaultWAgg.NO_ARGUMENT()
False

VAULT

CryptoFromPoolVaultWAgg.VAULT() -> address: view

Getter for the ERC-4626 vault contract whose redemption rate is applied to the price.

Returns: vault address (address).

<>Source code
VAULT: public(immutable(Vault))
Example
>>> CryptoFromPoolVaultWAgg.VAULT()
'0x...'

AGG

CryptoFromPoolVaultWAgg.AGG() -> address: view

Getter for the crvUSD price aggregator contract (PriceAggregator).

Returns: aggregator address (address).

<>Source code
AGG: public(immutable(StableAggregator))
Example
>>> CryptoFromPoolVaultWAgg.AGG()
'0x...'