Skip to main content
Version: 0.4.3

Yearn Lens

Yearn Lens is a series of smart contracts that aggregate and format Yearn family protocol data into standardized interfaces.

Architecture#

Block Diagram#

Chart

Key Concepts#

  • Lens
    • The lens contract acts as the primary data aggregator
    • Registry adapters can be added or removed from the lens contract
    • The lens contract supports many of the same methods as the registry adapters, but returns aggregated views across asset types
  • Registry Adapters
    • The purpose of registry adapters is to read data from various registries and return data in a standardized format
    • Currently registry adapters exist for:
      • v1 Vaults
      • v2 Vaults
      • Earn
      • Iron Bank
      • veCrv
    • All registry adapters must implement a standardized set of methods (details below)
    • Registry adapters have the ability to return metadata specific to an asset type (for example for vaults: pricePerShare, controller, etc.)
  • Oracle
    • The oracle contract is responsible for fetching price information from various sources
    • The oracle is intended for non-critical off-chain calculations
      • TVL calculations
      • Token and asset balance normalizations
      • Not intended to be used with strategies or other contracts
    • Prices are returned in USDC
    • Supports adding, removing and upgrading price calculations
      • Currently supported calculations:
        • Sushiswap market price (based on getAmountsOut)
        • Uniswap market price (based on getAmountsOut)
        • Sushiswap/Uniswap LP token prices (based on getReserves)
        • Iron Bank market price (based on exchangeRateStored)
        • Curve LP token price (based on virtualPrice and base underlying token price)
    • The oracle contract itself is very lightweight
      • A cascading fallback mechanism is utilized to fetch the most appropriate price for a given asset
        • This means the majority of logic lives on calculation contracts
        • This also means the oracle contract gets direct access to all underlying calculation contract helper methods

Key Features#

  • Obtain all Yearn family asset data in a standardized interface
  • Obtain all user asset and token balances/allowances
    • Ability to return USDC normalized balances as well as base asset balances
  • Obtain various TVL calculations for Yearn
    • Total TVL
    • TVL per asset type
    • TVL per asset
  • Integration with all Yearn family protocols
    • v1/v2 vaults
    • Iron Bank
    • Earn
    • VeCrv (base contract and pJar)

Contracts#

Registry Adapters#

Schema#

Standardized Interfaces#

All registry adapters are required to implement the following interfaces.

AdapterMetadata#
struct AdapterMetadata {    string typeId;    string categoryId;    string subcategoryId;}
Asset#
struct Asset {    address id;    string typeId;    string name;    string version;    uint256 balance;    uint256 balanceUsdc; // Asset TVL == balance * token.priceUsdc    Token token;    AssetMetadata metadata;}
AssetStatic (static) (not connected)#
struct AssetStatic {    address id;    string typeId;    string name;    string version;    Token token;}
Token (static) (not connected)#
struct Token {    address id;    string name;    string symbol;    uint8 decimals;}
assetsStatic():[{  id: "0x123...",  typeId: "v2Vault",  name: "YFI Vault",  version: "0.3.2",  tokenId: "0x234..."  token: {    id: "0x234...",    name: "yearn.finance",    symbol: "YFI",    decimals: 18  }}]
AssetDynamic (dynamic) (not connected)#
struct AssetDynamic {    address assetId;    address tokenId;    AssetMetadata metadata;    TokenAmount underlyingTokenBalance; // Amount of underlying token in the asset}
TokenAmount (dynamic)#
struct TokenAmount {    uint256 amount;    uint256 amountUsdc;}
assetsDynamic():[{  assetId: "0x123",  tokenId: "0x456",  metadata: {    pricePerShare: "101000022394340034000"  },  underlyingTokenBalance: {    amount: "53233222334444334444", // vault.totalAssets()    amountUsdc: "3422233333445"  }}]
Position (dynamic) (connected)#
struct Position {    address assetId;    string typeId;    address tokenId;    uint256 balance; // asset.balanceOf(account) - shares owned by user    TokenPostion underlyingTokenBalance; // Amount of underlying token in the asset that a user owns    TokenPosition accountTokenBalance; // Amount of underlying token a user owns    Allowance[] tokenAllowances;     Allowance[] assetAllowances;}
positionsOf(account):[{  assetId: "0x123",  typeId: "deposit",  tokenId: "0x545",  balance: "105344343435553", // vault.balanceOf(account)  underlyingTokenBalance: {    amount: "53233222334444334444", // vault.balanceOf(account) * pricePerShare    amountUsdc: "3422233333445"  },  accountTokenBalance: {    amount: "4424424000238", // token.balanceOf(account)    amountUsdc: "23323"  },  tokenAllowances: [{    owner: "0x4800", // Account    spender: "0x123", // Asset address    amount: "115335543535353535235325325325235235325235425235"  }],  assetAllowances: [{    owner: "0x123", // Asset address    spender: "0x456", // Trusted migrator    amount: "115335543535353535235325325325235235325235425235"  }]}]
Position#
struct Position {    address assetId;    uint256 balance;    uint256 balanceUsdc;    TokenPosition tokenPosition;    Allowance[] allowances;}
Token#
struct Token {    address id;    string name;    string symbol;    uint8 decimals;    uint256 priceUsdc;}
TokenPosition#
struct TokenPosition {    address tokenId;    uint256 balance;    uint256 balanceUsdc;    Allowance[] allowances;}
struct Allowance {    address owner;    address spender;    uint256 allowance;}
Adapter-specific Interfaces#

Each registry adapter can export asset metadata that is specific to the asset type.

Vault#
struct AssetMetadata {    string symbol;    uint256 pricePerShare;    bool migrationAvailable;    address latestVaultAddress;    uint256 depositLimit;    bool emergencyShutdown;}
Earn#

TBD

Iron Bank#

TBD

veCrv#

TBD

Methods#

All registry adapters are required to implement the following methods.

registryAddress#

Get the registry address associated with the adapter. The adapter pulls most information from the registry. registryAddress is defined in the adapter consturctor.

address public registryAddress;
assetsLength#

Get the number of assets the registry adapter is capable of returning.

function assetsLength() public view returns (uint256);

RETURN Number of registry adapter assets

Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);uint256 assetsLength = registryAdapter.assetsLength();
Example Response#
32
positionSpenderAddresses#
address[] public positionSpenderAddresses;
setPositionSpenderAddresses#
function setPositionSpenderAddresses(address addresses)
assetsAddresses#

Get a list of asset addresses from the asset adapter's associated registry.

function assetsAddresses() public view returns (address[] memory);

RETURN Array of asset addresses

Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);address[] assetAddresses = registryAdapter.assetsAddresses();
Example Response#
['0xE14d13d8B3b85aF791b2AADD661cDBd5E6097Db1', '0xdCD90C7f6324cfa40d7169ef80b12031770B4325', '0x986b4AFF588a109c09B50A03f42E4110E29D353F', '0xcB550A6D4C8e3517A939BC79d0c7093eb7cF56B5']
assetTvl#

Get TVL for a specific asset (in USDC).

function assetTvl(address assetAddress) public view returns (uint256);
Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);address assetAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;uint256 assetTvl = registryAdapter.assetTvl(assetAddress);
Example Response#

1637032292

assetsTvl#

Get aggregated TVL for all assets in the adapter's registry.

function assetsTvl() external view returns (uint256);

RETURN Aggregated TVL scoped to the adapter's assets in USDC

Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);uint256 assetTvl = registryAdapter.assetsTvl();
Example Response#

443923433354832

asset#

Get a specific asset including metadata specific to the asset type. The response extends the standardized Asset interface.

function asset(address assetAddress) public view returns (Asset memory);

assetAddress The address of the asset to fetch RETURN An asset struct containing information about the asset

Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);address assetAddress = 0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b;registryAdapter.asset(assetAddress);
Example Response#
{  name: 'WTFTM Vault',  id: 0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b,  version: '0.3.2',  totalAssets: 129999966466476313000000,  totalAssetsUsdc: 14355444934422, // TVL  metadata: {    controller: 0x19D3364A399d251E894aC732651be8B0E4e85001,    pricePerShare: 142004300000000000    ...  }}
assets#

Get all assets for a registry adapter

function assets() external view returns (Asset[] memory);

RETURN An array of asset structs containing information about the assets

Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);registryAdapter.assets();
Example Response#
[  {    name: 'WFTM Vault',    id: 0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b, // vault address    version: '0.3.2',    totalAssets: 129999966466476313000000,    totalAssetsUsdc: 14355444934422, // TVL    metadata: {      controller: 0x19D3364A399d251E894aC732651be8B0E4e85001,      pricePerShare: 142004300000000000      ...    }  },  {    name: 'fUSD Vault',    id: 0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9,    version: '0.3.2',    totalAssets: 4593326846642963130309078,    totalAssetsUsdc: 45444930943854422, // TVL    metadata: {      controller: 0x19D3364A399d251E894aC732651be8B0E4e85001,      pricePerShare: 101003300000000000      ...    }  }]
positionOf#

Get the position of an account for a specific asset address.

function positionOf(address accountAddress, address assetAddress)    public    view    returns (Position memory);
Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);address accountAddress = 0x481140F916a4e64559694DB4d56D692CadC0326c;address assetAddress = 0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b;registryAdapter.positionForAsset(accountAddress, assetAddress);
Example Response#
{  assetId: 0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b, // vault address  depositedBalance: 10422000000000000000,  depositedBalanceUsdc: 10422000,  tokenBalance: 2110000000000000000,  tokenBalanceUsdc: 2110000,  tokenAllowance, 1157343987545498574545495749587452... // max uint256}
positionsOf#

Get all positions for an account for every adapter asset.

function positionsOf(address accountAddress)        external        view        returns (Position[] memory);
Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);address accountAddress = 0x481140F916a4e64559694DB4d56D692CadC0326c;registryAdapter.positionsOf(accountAddress);
Example Response#
[  {    assetId: 0xe2F6b9773BF3A015E2aA70741Bde1498bdB9425b, // vault address    depositedBalance: 10422000000000000000,    depositedBalanceUsdc: 10422000,    tokenBalance: 2110000000000000000,    tokenBalanceUsdc: 2110000,    tokenAllowance, 1157343987545498574545495749587452... // max uint256  },  {    assetId: 0x19D3364A399d251E894aC732651be8B0E4e85001, // vault address    depositedBalance: 10422000000000000000,    depositedBalanceUsdc: 10422000,    tokenBalance: 0,    tokenBalanceUsdc: 0,    tokenAllowance, 0  }]
tokens#

Get unique tokens for the adapter.

function tokens()        external        view        returns (Token[] memory);
Solidity#
RegistryAdapter registryAdapter = RegistryAdapter(0xABCD...);registryAdapter.tokens();
Example Response#
[  {    id: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48, // token address    name: 'USD Coin',    symbol: 'USDC',    decimals: 18,    priceUsdc: 100000  },  ...]

Oracle#

Methods#

setCalculations#

Set oracle calculation contract addresses. Each calculation contract must implement getPriceUsdc(). The order of calculation contracts matters as it determines the order preference in the cascading fallback mechanism.

function setCalculations(address[] memory calculationAddresses)        public        onlyManagers;

calculationAddresses An array of addresses for underlying calculation contracts

calculations#

View the calculation contract addresses currently associated with the oracle.

function calculations() external view returns (address[] memory);

RETURN An array of calculation contract addresses associated with the oracle

Example Response#
[   '0xfC714174E5c8bd056a45a5337E7b402CC4af7BF3',   '0x55e9B18fefFF7E00548d54480373Fc8843De8eA4',   '0x88dE7d7F7b9597C86b8cD195374FbF602934F334']
getPriceUsdcRecommended#

Get the currently recommended price given a token address.

function getPriceUsdcRecommended(address tokenAddress)        public        view        returns (uint256);

tokenAddress The token address for which to obtain a price recommendation RETURN Recommended price in USDC (6 decimals)

Example Response#

103000

getNormalizedValueUsdc#

Calculate normalized USDC value given a token address and an amount.

function getNormalizedValueUsdc(address tokenAddress, uint256 amount)        external        view        returns (uint256);

tokenAddress The token address amount The amount of value to convert (in token decimals) RETURN Recommended price in USDC (6 decimals)

Example Response#

3442238822

tokenAliases#

Given a token address fetch a token alias address. This is necessary for certain wrapped or special case tokens that do not have a token price available in the oracle.

mapping(address => address) public tokenAliases;
addTokenAlias#

Add a new token alias mapping.

function addTokenAlias(address tokenAddress, address tokenAliasAddress)        public        onlyManagers;

tokenAddress The token address that will receive an alias tokenAliasAddress The new token alias address

addTokenAliases#

Batch add new token alias mappingings.

    function addTokenAliases(TokenAlias[] memory tokenAliases)        public        onlyManagers

tokenAliases An array of TokenAlias structs ([[tokenAddress, tokenAliasAddress]])

removeTokenAlias#

Remove a token alias mapping.

function addTokenAlias(address tokenAddress, address tokenAliasAddress)        public        onlyManagers;

tokenAddress The token address whose alias will be removed

Calculation#

Standardized methods#

All calculation contracts must implement the following methods.

getPriceUsdc#

Fetch the recommended price given a token address. Reverts if no relevant price is found.

function getPriceUsdc(address tokenAddress) public view returns (uint256)
Example Response#

103000

Calculation specific methods#

Helper utilities for various calculations. These methods are indirectly exposed to the oracle via the oracle's cascading fallback mechanism. All of these methods can be called via the oracle contract by generating a custom ABI with the desired methods. Since these helper methods do not represent the primary use case of the oracle contract (the primary use case is fetching price) determining the details of each method implementation is left to the user.

Sushiswap#
function getPriceFromRouter(address token0Address, address token1Address)        public        view        returns (uint256);        function getPriceFromRouterUsdc(address tokenAddress)        public        view        returns (uint256);        function isLpToken(address tokenAddress) public view returns (bool);
function getRouterForLpToken(address tokenAddress)        public        view        returns (PriceRouter);        function getLpTokenTotalLiquidityUsdc(address tokenAddress)        public        view        returns (uint256);        function getLpTokenPriceUsdc(address tokenAddress)        public        view        returns (uint256);
Curve#
function getBasePrice(address curveLpTokenAddress)        public        view        returns (uint256);
function getVirtualPrice(address curveLpTokenAddress)        public        view        returns (uint256);        function isCurveLpToken(address tokenAddress) public view returns (bool);
function getFirstUnderlyingCoinFromPool(address poolAddress)        public        view        returns (address);function getCurvePriceUsdc(address curveLpTokenAddress)        public        view        returns (uint256);
IronBank#
function isIronBankMarket(address tokenAddress) public view returns (bool);
function getIronBankMarkets() public view returns (address[] memory);
function getIronBankMarketPriceUsdc(address tokenAddress)        public        view        returns (uint256);

Lens#

Methods#

addAdapter#

Add a registry adapter. The registry adapter must conform to the standardized registry adapter interface.

function addAdapter(address adapterAddress) public onlyManager;

adapterAddress Address of the adapter to add

Solidity#
Lens lens = Lens(0x9b8b9F6146B29CC32208f42b995E70F0Eb2807F3);address adapterAddress = 0xe11ba472F74869176652C35D30dB89854b5ae84D;lens.addAdapter(adapterAddress);
removeAdapter#

Remove a registry adapter.

function removeAdapter(address adapterAddress) public onlyManager;

adapterAddress Address of the adapter to remove

Solidity#
Lens lens = Lens(0x9b8b9F6146B29CC32208f42b995E70F0Eb2807F3);address adapterAddress = 0xe11ba472F74869176652C35D30dB89854b5ae84D;lens.removeAdapter(adapterAddress);
adapters#

Fetch a list of registry adapter addresses.

function adapters() external view returns (address[] memory);
Solidity#
Lens lens = Lens(0x9b8b9F6146B29CC32208f42b995E70F0Eb2807F3);address[] memory = lens.adapters();
Example Response#
['0xE14d13d8B3b85aF791b2AADD661cDBd5E6097Db1', '0xdCD90C7f6324cfa40d7169ef80b12031770B4325', '0x986b4AFF588a109c09B50A03f42E4110E29D353F', '0xcB550A6D4C8e3517A939BC79d0c7093eb7cF56B5']
assetsFromAdapter#
function assetsFromAdapter(RegistryAdapter registryAdapterAddress)        external        view        returns (RegistryAdapter.Asset[] memory)

See: registryAdapter.assets

assets#

Fetch all assets for all supported protocols.

function assets()        external        view        returns (RegistryAdapter.Asset[] memory)

See: registryAdapter.assets

positionsFromAdapter#

Fetch positions for an account for a specific adapter.

function positionsFromAdapter(        address account,        RegistryAdapter registryAdapterAddress    ) external view returns (RegistryAdapter.Position[] memory)

See: registryAdapter.positionsOf

positionsOf#

Fetch all positions for an account within the ecosystem.

function positionsOf(address account)        external        view        returns (RegistryAdapter.Position[] memory)

See: registryAdapter.positionsOf

assetsLength#
function assetsLength() public view returns (uint256);

Get the total number of assets for all Yearn family protocols See: registryAdapter.assetsLength

assetsAddresses#
function assetsAddresses() public view returns (address[] memory);

Get all addresses for all Yearn family assets See: registryAdapter.assetsAddresses

allowances#

Batch fetch allowances given an owner, tokens and spender. This is a helper utility for fetching large amounts of token allowances for a specific set of contracts (zapper contract, for example)

    function allowances(        address owner,        address[] memory tokens,        address[] memory spenders    ) external view returns (uint256[] memory)