Skip to main content

Using Lens Contracts

This guide is for developers, analysts, and integrators who want to query protocol data efficiently and make sense of the results. We'll walk through practical examples and explain the key data types you'll encounter.

The contract ABIs and deployment addresses for lens contracts are available in the euler-interfaces repository. Be sure to use the correct address for your target network.

Connecting to a Lens Contract

To interact with a lens contract, you'll typically use a web3 library like ethers.js. All lens contracts are read-only, so you can call them from any off-chain context (scripts, dashboards, bots, etc.).

Example: Connecting to AccountLens

const { ethers } = require("ethers");
const provider = new ethers.JsonRpcProvider(RPC_URL);
const accountLens = new ethers.Contract(ACCOUNT_LENS_ADDRESS, AccountLensABI, provider);

Querying Account Data: getAccountInfo

The getAccountInfo(account, vault) function returns a comprehensive snapshot of a user's position in a vault. The result is an AccountInfo struct, which contains several nested types:

  • EVCAccountInfo: General info about the EVC sub-account (owner, enabled controllers/collaterals, status flags)
  • VaultAccountInfo: Position data for the vault (balances, shares, borrowings, collateral/controller status, liquidity info)
  • AccountRewardInfo: On-chain reward and incentive data (balances, earned rewards, reward streams)

If you want to query the same data for all enabled collaterals and controllers of an account in one call, use getAccountEnabledVaultsInfo(evc, account). This function returns arrays of the same types for every enabled vault, making it efficient to fetch a user's full protocol exposure. Note that this function only returns data for vaults that are explicitly enabled as collateral or controller in the EVC - it won't return information about deposits in vaults that aren't enabled as collateral.

Example:

const account = "0x...";
const vault = "0x...";
const info = await accountLens.getAccountInfo(account, vault);

// Accessing nested data:
console.log("Owner:", info.evcAccountInfo.owner);
console.log("Vault shares:", info.vaultAccountInfo.shares);
console.log("Borrowed:", info.vaultAccountInfo.borrowed);
console.log("Is Controller:", info.vaultAccountInfo.isController);
console.log("Earned rewards:", info.accountRewardInfo.enabledRewardsInfo);

Understanding the Types

  • AccountInfo: The top-level struct, grouping all relevant data for a user/vault pair.
  • EVCAccountInfo: Includes the EVC address, owner, enabled controllers/collaterals, and status flags (e.g., lockdown mode).
  • VaultAccountInfo: Contains balances, shares, borrowings, allowances, collateral/controller status, and liquidity info (including time to liquidation and collateral values).
  • AccountRewardInfo: Shows reward balances and details for any enabled reward streams.

Tip: Many fields are nested structs or arrays. Use dot notation to access them (e.g., info.vaultAccountInfo.liquidityInfo.timeToLiquidation).

Position Health, Collateral Value, and Health Score

When analyzing your account's risk and health, it's important to understand how the protocol evaluates your positions. Here are some key concepts and how to extract them using the lens contracts:

  • Health Score (Health Rate):

    • The health score is a measure of how safe your borrow position is. It is calculated as:

      healthScore = collateralValueLiquidation / liabilityValue

      where both values are found in VaultAccountInfo.liquidityInfo.

    • To get the health score for a borrow position, you must query the vault from which you borrowed (the controller vault). In the context of getAccountEnabledVaultsInfo, this will be the vault where isController is true.

  • Risk-Adjusted Collateral Value:

    • The protocol uses different collateral values for borrowing and for liquidation:
      • collateralValueBorrowing: The value of your enabled collaterals as seen for borrowing purposes.
      • collateralValueLiquidation: The value of your enabled collaterals as seen for liquidation purposes (usually more conservative).
    • Both are available in VaultAccountInfo.liquidityInfo.
    • These values are aggregated across all enabled collaterals for the position, but you can also see the breakdown per collateral in the collateralLiquidityBorrowingInfo and collateralLiquidityLiquidationInfo arrays.
  • Collateral Market Value (Raw):

    • The raw market value of your collaterals, as seen by the controller vault, is given by collateralValueRaw in VaultAccountInfo.liquidityInfo.
    • The breakdown per collateral is available in the collateralLiquidityRawInfo array.
  • Off-Chain Collateral Market Value:

    • If you want to compute the market value of your collateral using off-chain prices, multiply your collateral asset balance (not shares) by the current market price of the asset. For example:

      offChainCollateralValue = assetsAccount * assetPrice

      where assetsAccount is the asset balance from VaultAccountInfo.assetsAccount and assetPrice is the off-chain price per unit of the asset.

    • Note: For some assets, you may need to use your own price source if the endpoint does not return a value.

Tip: The getAccountEnabledVaultsInfo function returns an AccountMultipleVaultsInfo struct, which contains an array of VaultAccountInfo for each enabled collateral and controller. For borrow positions, focus on the vault where isController is true to get the health and risk data for your position.

Querying Vault Data: getVaultInfoFull

The getVaultInfoFull(vault) function (from VaultLens) returns a VaultInfoFull struct, which is a detailed snapshot of a vault's configuration and state.

Example:

const vaultLens = new ethers.Contract(VAULT_LENS_ADDRESS, VaultLensABI, provider);
const vaultInfo = await vaultLens.getVaultInfoFull(vault);

console.log("Vault name:", vaultInfo.vaultName);
console.log("Total assets:", vaultInfo.totalAssets);
console.log("Interest rate model:", vaultInfo.interestRateModel);
console.log("Supply cap:", vaultInfo.supplyCap);
console.log("Recognized collaterals:", vaultInfo.collateralLTVInfo);

Key Types in VaultInfoFull

  • VaultInfoFull: The main struct, with fields for vault configuration, totals, caps, fees, IRM, oracles, hooks, and more.
  • LTVInfo[]: An array of collateral types and their LTV (Loan-to-Value) parameters. Each LTVInfo includes the collateral address, borrow and liquidation LTVs, and ramping info.
  • VaultInterestRateModelInfo: Details about the vault's interest rate model, including type and parameters.
  • AssetPriceInfo: Price and oracle data for assets and collaterals.

Tip: Arrays like collateralLTVInfo are append-only, so not all entries may be active collaterals. Always check the LTV values - a collateral with zero borrowLTV is no longer accepted as collateral. Only iterate through entries with non-zero LTVs to display currently supported collaterals and their risk parameters.

Tip:
If a vault is ramping down its liquidation LTV, you can calculate the current liquidation LTV for a collateral using the following formula, based on the fields in the LTVInfo struct returned by the lens:

// LTVInfo fields:
// - liquidationLTV: target value (uint256)
// - initialLiquidationLTV: starting value at ramp start (uint256)
// - targetTimestamp: when ramping ends (uint256, unix time)
// - rampDuration: total ramp duration (uint256, seconds)

function getCurrentLiquidationLTV(ltvInfo) {
const now = Math.floor(Date.now() / 1000); // current unix timestamp
if (
now >= ltvInfo.targetTimestamp ||
ltvInfo.liquidationLTV >= ltvInfo.initialLiquidationLTV
) {
return ltvInfo.liquidationLTV;
}
const timeRemaining = ltvInfo.targetTimestamp - now;
return (
ltvInfo.liquidationLTV +
((ltvInfo.initialLiquidationLTV - ltvInfo.liquidationLTV) * timeRemaining) /
ltvInfo.rampDuration
);
}

This matches the on-chain logic: the liquidation LTV linearly ramps from initialLiquidationLTV to liquidationLTV over the period ending at targetTimestamp. If ramping is not active, just use liquidationLTV.

Querying APYs for a Vault

To quickly fetch the current borrow and supply APYs for a vault, use the getAPYs(vault) function from the UtilsLens contract. This function returns the annualized borrow and supply rates, computed based on the vault's current interest rate model and utilization.

Example:

const utilsLens = new ethers.Contract(UTILS_LENS_ADDRESS, UtilsLensABI, provider);
const [borrowAPY, supplyAPY] = await utilsLens.getAPYs(vault);

console.log("Borrow APY:", borrowAPY);
console.log("Supply APY:", supplyAPY);

The returned values are typically expressed in ray units (1e27), so you may need to convert them to a human-readable percentage (e.g., Number(borrowAPY) / 1e25 gives the APY as a percent with two decimals).

Note: The APYs returned here only include the Euler rates from lending and borrowing activity within the protocol. They do not include any intrinsic APY from the underlying asset (for example, the staking yield of wstETH) or any additional rewards. To account for those, you must supplement with external data sources.

Where to Find Type Definitions and More Resources

The full definitions of all structs and types used by lens contracts can be found in the LensTypes.sol file in the EVK Periphery repository.