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.vyThe 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"}]}]
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.
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
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:
- Pool price oracle — reads the internal price oracle from the Curve pool, extracting the relative price between the collateral and borrowed assets
- Vault redemption — multiplies by
VAULT.convertToAssets(10**18)to convert from vault shares to underlying - USD normalization — multiplies by the aggregated crvUSD/USD price from
AGG
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: viewReturns 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() -> uint256Write 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: viewGetter 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: viewGetter 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: viewGetter 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: viewGetter 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: viewGetter 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: viewGetter 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: viewGetter for the crvUSD price aggregator contract (PriceAggregator).
Returns: aggregator address (address).
<>Source code▼
AGG: public(immutable(StableAggregator))
▶Example▼
>>> CryptoFromPoolVaultWAgg.AGG()
'0x...'