OracleLens

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/Lens/OracleLens.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import {Utils} from "./Utils.sol";
import {SnapshotRegistry} from "../SnapshotRegistry/SnapshotRegistry.sol";
import {IPriceOracle} from "euler-price-oracle/interfaces/IPriceOracle.sol";
import {Errors} from "euler-price-oracle/lib/Errors.sol";
import "./LensTypes.sol";

interface IOracle is IPriceOracle {
    function base() external view returns (address);
    function quote() external view returns (address);
    function cross() external view returns (address);
    function oracleBaseCross() external view returns (address);
    function oracleCrossQuote() external view returns (address);
    function feed() external view returns (address);
    function pyth() external view returns (address);
    function WETH() external view returns (address);
    function STETH() external view returns (address);
    function WSTETH() external view returns (address);
    function tokenA() external view returns (address);
    function tokenB() external view returns (address);
    function pool() external view returns (address);
    function governor() external view returns (address);
    function maxStaleness() external view returns (uint256);
    function maxConfWidth() external view returns (uint256);
    function twapWindow() external view returns (uint32);
    function fee() external view returns (uint24);
    function feedDecimals() external view returns (uint8);
    function feedId() external view returns (bytes32);
    function fallbackOracle() external view returns (address);
    function resolvedVaults(address) external view returns (address);
    function cache() external view returns (uint208, uint48);
    function rate() external view returns (uint256);
    function rateProvider() external view returns (address);
    function rwaOracle() external view returns (address);
    function resolveOracle(uint256 inAmount, address base, address quote)
        external
        view
        returns (uint256, address, address, address);
    function getConfiguredOracle(address base, address quote) external view returns (address);
    function description() external view returns (string memory);
    function pendleMarket() external view returns (address);
    function safeguardPool() external view returns (address);
    function poolId() external view returns (bytes32);
    function priceOracleIndex() external view returns (uint256);
}

contract OracleLens is Utils {
    SnapshotRegistry public immutable adapterRegistry;

    constructor(address _adapterRegistry) {
        adapterRegistry = SnapshotRegistry(_adapterRegistry);
    }

    function getOracleInfo(address oracleAddress, address[] memory bases, address[] memory quotes)
        public
        view
        returns (OracleDetailedInfo memory)
    {
        string memory name;
        bytes memory oracleInfo;

        {
            bool success;
            bytes memory result;

            if (oracleAddress != address(0)) {
                (success, result) = oracleAddress.staticcall(abi.encodeCall(IPriceOracle.name, ()));
            }

            if (success && result.length >= 32) {
                name = abi.decode(result, (string));
            } else {
                return OracleDetailedInfo({oracle: oracleAddress, name: "", oracleInfo: ""});
            }
        }

        if (_strEq(name, "ChainlinkOracle")) {
            string memory feedDescription;
            try IOracle(IOracle(oracleAddress).feed()).description() returns (string memory desc) {
                feedDescription = desc;
            } catch {
                // feedDescription remains empty
            }
            
            oracleInfo = abi.encode(
                ChainlinkOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    feed: IOracle(oracleAddress).feed(),
                    feedDescription: feedDescription,
                    maxStaleness: IOracle(oracleAddress).maxStaleness()
                })
            );
        } else if (_strEq(name, "ChainlinkInfrequentOracle")) {
            string memory feedDescription;
            try IOracle(IOracle(oracleAddress).feed()).description() returns (string memory desc) {
                feedDescription = desc;
            } catch {
                // feedDescription remains empty
            }
            
            oracleInfo = abi.encode(
                ChainlinkInfrequentOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    feed: IOracle(oracleAddress).feed(),
                    feedDescription: feedDescription,
                    maxStaleness: IOracle(oracleAddress).maxStaleness()
                })
            );
        } else if (_strEq(name, "ChronicleOracle")) {
            oracleInfo = abi.encode(
                ChronicleOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    feed: IOracle(oracleAddress).feed(),
                    maxStaleness: IOracle(oracleAddress).maxStaleness()
                })
            );
        } else if (_strEq(name, "LidoOracle")) {
            oracleInfo = abi.encode(
                LidoOracleInfo({base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH()})
            );
        } else if (_strEq(name, "LidoFundamentalOracle")) {
            oracleInfo = abi.encode(
                LidoFundamentalOracleInfo({base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).WETH()})
            );
        } else if (_strEq(name, "PythOracle")) {
            oracleInfo = abi.encode(
                PythOracleInfo({
                    pyth: IOracle(oracleAddress).pyth(),
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    feedId: IOracle(oracleAddress).feedId(),
                    maxStaleness: IOracle(oracleAddress).maxStaleness(),
                    maxConfWidth: IOracle(oracleAddress).maxConfWidth()
                })
            );
        } else if (_strEq(name, "RedstoneCoreOracle")) {
            (uint208 cachePrice, uint48 cachePriceTimestamp) = IOracle(oracleAddress).cache();
            oracleInfo = abi.encode(
                RedstoneCoreOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    feedId: IOracle(oracleAddress).feedId(),
                    maxStaleness: IOracle(oracleAddress).maxStaleness(),
                    feedDecimals: IOracle(oracleAddress).feedDecimals(),
                    cachePrice: cachePrice,
                    cachePriceTimestamp: cachePriceTimestamp
                })
            );
        } else if (_strEq(name, "UniswapV3Oracle")) {
            oracleInfo = abi.encode(
                UniswapV3OracleInfo({
                    tokenA: IOracle(oracleAddress).tokenA(),
                    tokenB: IOracle(oracleAddress).tokenB(),
                    pool: IOracle(oracleAddress).pool(),
                    fee: IOracle(oracleAddress).fee(),
                    twapWindow: IOracle(oracleAddress).twapWindow()
                })
            );
        } else if (_strEq(name, "FixedRateOracle")) {
            oracleInfo = abi.encode(
                FixedRateOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    rate: IOracle(oracleAddress).rate()
                })
            );
        } else if (_strEq(name, "RateProviderOracle")) {
            oracleInfo = abi.encode(
                RateProviderOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    rateProvider: IOracle(oracleAddress).rateProvider()
                })
            );
        } else if (_strEq(name, "OndoOracle")) {
            oracleInfo = abi.encode(
                OndoOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    rwaOracle: IOracle(oracleAddress).rwaOracle()
                })
            );
        } else if (_strEq(name, "PendleOracle")) {
            oracleInfo = abi.encode(
                PendleProviderOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    pendleMarket: IOracle(oracleAddress).pendleMarket(),
                    twapWindow: IOracle(oracleAddress).twapWindow()
                })
            );
        } else if (_strEq(name, "PendleUniversalOracle")) {
            oracleInfo = abi.encode(
                PendleUniversalOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    pendleMarket: IOracle(oracleAddress).pendleMarket(),
                    twapWindow: IOracle(oracleAddress).twapWindow()
                })
            );
        } else if (_strEq(name, "CurveEMAOracle")) {
            oracleInfo = abi.encode(
                CurveEMAOracleInfo({
                    base: IOracle(oracleAddress).base(),
                    quote: IOracle(oracleAddress).quote(),
                    pool: IOracle(oracleAddress).pool(),
                    priceOracleIndex: IOracle(oracleAddress).priceOracleIndex()
                })
            );
        } else if (_strEq(name, "SwaapSafeguardOracle")) {
            oracleInfo = abi.encode(
                SwaapSafeguardProviderOracleInfo({
                    base: IOracle(oracleAddress).safeguardPool(),
                    quote: IOracle(oracleAddress).quote(),
                    poolId: IOracle(oracleAddress).poolId()
                })
            );
        } else if (_strEq(name, "CrossAdapter")) {
            address oracleBaseCross = IOracle(oracleAddress).oracleBaseCross();
            address oracleCrossQuote = IOracle(oracleAddress).oracleCrossQuote();
            OracleDetailedInfo memory oracleBaseCrossInfo = getOracleInfo(oracleBaseCross, bases, quotes);
            OracleDetailedInfo memory oracleCrossQuoteInfo = getOracleInfo(oracleCrossQuote, bases, quotes);
            oracleInfo = abi.encode(
                CrossAdapterInfo({
                    base: IOracle(oracleAddress).base(),
                    cross: IOracle(oracleAddress).cross(),
                    quote: IOracle(oracleAddress).quote(),
                    oracleBaseCross: oracleBaseCross,
                    oracleCrossQuote: oracleCrossQuote,
                    oracleBaseCrossInfo: oracleBaseCrossInfo,
                    oracleCrossQuoteInfo: oracleCrossQuoteInfo
                })
            );
        } else if (_strEq(name, "EulerRouter")) {
            require(bases.length == quotes.length, "OracleLens: invalid input");

            address[][] memory resolvedAssets = new address[][](bases.length);
            address[] memory resolvedOracles = new address[](bases.length);
            OracleDetailedInfo[] memory resolvedOraclesInfo = new OracleDetailedInfo[](bases.length);

            for (uint256 i = 0; i < bases.length; ++i) {
                (resolvedAssets[i], resolvedOracles[i], resolvedOraclesInfo[i]) =
                    _routerResolve(oracleAddress, resolvedAssets[i], bases[i], quotes[i]);
            }

            address fallbackOracle = IOracle(oracleAddress).fallbackOracle();

            oracleInfo = abi.encode(
                EulerRouterInfo({
                    governor: IOracle(oracleAddress).governor(),
                    fallbackOracle: fallbackOracle,
                    fallbackOracleInfo: getOracleInfo(fallbackOracle, bases, quotes),
                    bases: bases,
                    quotes: quotes,
                    resolvedAssets: resolvedAssets,
                    resolvedOracles: resolvedOracles,
                    resolvedOraclesInfo: resolvedOraclesInfo
                })
            );
        }

        return OracleDetailedInfo({oracle: oracleAddress, name: name, oracleInfo: oracleInfo});
    }

    function isStalePullOracle(address oracleAddress, bytes calldata failureReason) public view returns (bool) {
        bytes4 failureReasonSelector = bytes4(failureReason);
        return _isStalePythOracle(oracleAddress, failureReasonSelector)
            || _isStaleRedstoneOracle(oracleAddress, failureReasonSelector)
            || _isStaleCrossAdapter(oracleAddress, failureReasonSelector);
    }

    function getValidAdapters(address base, address quote) public view returns (address[] memory) {
        return adapterRegistry.getValidAddresses(base, quote, block.timestamp);
    }

    function _routerResolve(
        address oracleAddress,
        address[] memory currentlyResolvedAssets,
        address base,
        address quote
    )
        internal
        view
        returns (address[] memory resolvedAssets, address resolvedOracle, OracleDetailedInfo memory resolvedOracleInfo)
    {
        if (base == quote) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);

        (bool success, bytes memory result) =
            oracleAddress.staticcall(abi.encodeCall(IOracle.getConfiguredOracle, (base, quote)));

        if (!success || result.length < 32) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);

        resolvedOracle = abi.decode(result, (address));

        if (resolvedOracle != address(0)) {
            address[] memory bases = new address[](1);
            address[] memory quotes = new address[](1);
            bases[0] = base;
            quotes[0] = quote;
            resolvedOracleInfo = getOracleInfo(resolvedOracle, bases, quotes);
            return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
        }

        (success, result) = oracleAddress.staticcall(abi.encodeCall(IOracle.resolvedVaults, (base)));

        if (!success || result.length < 32) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);

        address baseAsset = abi.decode(result, (address));

        if (baseAsset != address(0)) {
            resolvedAssets = new address[](currentlyResolvedAssets.length + 1);
            for (uint256 i = 0; i < currentlyResolvedAssets.length; ++i) {
                resolvedAssets[i] = currentlyResolvedAssets[i];
            }
            resolvedAssets[resolvedAssets.length - 1] = baseAsset;
            return _routerResolve(oracleAddress, resolvedAssets, baseAsset, quote);
        }

        (success, result) = oracleAddress.staticcall(abi.encodeCall(IOracle.fallbackOracle, ()));

        if (!success || result.length < 32) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);

        resolvedOracle = abi.decode(result, (address));

        if (resolvedOracle != address(0)) {
            address[] memory bases = new address[](1);
            address[] memory quotes = new address[](1);
            bases[0] = base;
            quotes[0] = quote;
            resolvedOracleInfo = getOracleInfo(resolvedOracle, bases, quotes);
            return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
        }

        return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
    }

    function _isStalePythOracle(address oracle, bytes4 failureSelector) internal view returns (bool) {
        if (oracle == address(0)) return false;

        (bool success, bytes memory result) = oracle.staticcall(abi.encodeCall(IPriceOracle.name, ()));

        if (success && result.length >= 32) {
            string memory name = abi.decode(result, (string));
            return _strEq(name, "PythOracle") && failureSelector == Errors.PriceOracle_InvalidAnswer.selector;
        }

        return false;
    }

    function _isStaleRedstoneOracle(address oracle, bytes4 failureSelector) internal view returns (bool) {
        if (oracle == address(0)) return false;

        (bool success, bytes memory result) = oracle.staticcall(abi.encodeCall(IPriceOracle.name, ()));

        if (success && result.length >= 32) {
            string memory name = abi.decode(result, (string));
            return _strEq(name, "RedstoneCoreOracle") && failureSelector == Errors.PriceOracle_TooStale.selector;
        }

        return false;
    }

    function _isStaleCrossAdapter(address oracle, bytes4 failureSelector) internal view returns (bool) {
        if (oracle == address(0)) return false;

        (bool success, bytes memory result) = oracle.staticcall(abi.encodeCall(IPriceOracle.name, ()));

        if (success && result.length >= 32) {
            string memory name = abi.decode(result, (string));
            if (!_strEq(name, "CrossAdapter")) return false;
        } else {
            return false;
        }

        address oracleBaseCross = IOracle(oracle).oracleBaseCross();
        address oracleCrossQuote = IOracle(oracle).oracleCrossQuote();

        return _isStalePythOracle(oracleBaseCross, failureSelector)
            || _isStaleRedstoneOracle(oracleBaseCross, failureSelector)
            || _isStalePythOracle(oracleCrossQuote, failureSelector)
            || _isStaleRedstoneOracle(oracleCrossQuote, failureSelector)
            || _isStaleCrossAdapter(oracleBaseCross, failureSelector)
            || _isStaleCrossAdapter(oracleCrossQuote, failureSelector);
    }
}
"
    },
    "src/Lens/Utils.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import {IEVault} from "evk/EVault/IEVault.sol";
import {RPow} from "evk/EVault/shared/lib/RPow.sol";

abstract contract Utils {
    uint256 internal constant SECONDS_PER_YEAR = 365.2425 * 86400;
    uint256 internal constant ONE = 1e27;
    uint256 internal constant CONFIG_SCALE = 1e4;
    uint256 internal constant TTL_HS_ACCURACY = ONE / 1e4;
    int256 internal constant TTL_COMPUTATION_MIN = 0;
    int256 internal constant TTL_COMPUTATION_MAX = 400 * 1 days;
    int256 public constant TTL_INFINITY = type(int256).max;
    int256 public constant TTL_MORE_THAN_ONE_YEAR = type(int256).max - 1;
    int256 public constant TTL_LIQUIDATION = -1;
    int256 public constant TTL_ERROR = -2;

    function getWETHAddress() internal view returns (address) {
        if (block.chainid == 1) {
            return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
        } else if (
            block.chainid == 10 || block.chainid == 130 || block.chainid == 8453 || block.chainid == 1923
                || block.chainid == 480 || block.chainid == 57073 || block.chainid == 60808
        ) {
            return 0x4200000000000000000000000000000000000006;
        } else if (block.chainid == 56) {
            return 0x2170Ed0880ac9A755fd29B2688956BD959F933F8;
        } else if (block.chainid == 100) {
            return 0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1;
        } else if (block.chainid == 137) {
            return 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619;
        } else if (block.chainid == 146) {
            return 0x50c42dEAcD8Fc9773493ED674b675bE577f2634b;
        } else if (block.chainid == 42161) {
            return 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
        } else if (block.chainid == 43114) {
            return 0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB;
        } else if (block.chainid == 80094) {
            return 0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590;
        } else {
            // bitcoin-specific and test networks
            if (
                block.chainid == 30 || block.chainid == 21000000 || block.chainid == 10143 || block.chainid == 80084
                    || block.chainid == 2390
            ) {
                return address(0);
            }
            // hyperEVM
            if (block.chainid == 999) {
                return address(0);
            }

            // TAC
            if (block.chainid == 239) {
                return address(0);
            }
        }

        revert("getWETHAddress: Unsupported chain");
    }

    function _strEq(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }

    /// @dev for tokens like MKR which return bytes32 on name() or symbol()
    function _getStringOrBytes32(address contractAddress, bytes4 selector) internal view returns (string memory) {
        (bool success, bytes memory result) = contractAddress.staticcall(abi.encodeWithSelector(selector));

        return (success && result.length != 0)
            ? result.length == 32 ? string(abi.encodePacked(result)) : abi.decode(result, (string))
            : "";
    }

    function _getDecimals(address contractAddress) internal view returns (uint8) {
        (bool success, bytes memory data) =
            contractAddress.staticcall(abi.encodeCall(IEVault(contractAddress).decimals, ()));

        return success && data.length >= 32 ? abi.decode(data, (uint8)) : 18;
    }

    function _computeAPYs(uint256 borrowSPY, uint256 cash, uint256 borrows, uint256 interestFee)
        internal
        pure
        returns (uint256 borrowAPY, uint256 supplyAPY)
    {
        uint256 totalAssets = cash + borrows;
        bool overflow;

        (borrowAPY, overflow) = RPow.rpow(borrowSPY + ONE, SECONDS_PER_YEAR, ONE);

        if (overflow) return (0, 0);

        borrowAPY -= ONE;
        supplyAPY =
            totalAssets == 0 ? 0 : borrowAPY * borrows * (CONFIG_SCALE - interestFee) / totalAssets / CONFIG_SCALE;
    }

    struct CollateralInfo {
        uint256 borrowSPY;
        uint256 borrows;
        uint256 totalAssets;
        uint256 interestFee;
        uint256 borrowInterest;
    }

    function _calculateTimeToLiquidation(
        address liabilityVault,
        uint256 liabilityValue,
        address[] memory collaterals,
        uint256[] memory collateralValues
    ) internal view returns (int256) {
        // if there's no liability, time to liquidation is infinite
        if (liabilityValue == 0) return TTL_INFINITY;

        // get borrow interest rate
        uint256 liabilitySPY;
        {
            (bool success, bytes memory data) =
                liabilityVault.staticcall(abi.encodeCall(IEVault(liabilityVault).interestRate, ()));

            if (success && data.length >= 32) {
                liabilitySPY = abi.decode(data, (uint256));
            }
        }

        // get individual collateral interest rates and total collateral value
        CollateralInfo[] memory collateralInfos = new CollateralInfo[](collaterals.length);
        uint256 collateralValue;
        for (uint256 i = 0; i < collaterals.length; ++i) {
            address collateral = collaterals[i];

            (bool success, bytes memory data) =
                collateral.staticcall(abi.encodeCall(IEVault(collateral).interestRate, ()));

            if (success && data.length >= 32) {
                collateralInfos[i].borrowSPY = abi.decode(data, (uint256));
            }

            (success, data) = collateral.staticcall(abi.encodeCall(IEVault(collateral).totalBorrows, ()));

            if (success && data.length >= 32) {
                collateralInfos[i].borrows = abi.decode(data, (uint256));
            }

            (success, data) = collateral.staticcall(abi.encodeCall(IEVault(collateral).cash, ()));

            if (success && data.length >= 32) {
                collateralInfos[i].totalAssets = abi.decode(data, (uint256)) + collateralInfos[i].borrows;
            }

            (success, data) = collateral.staticcall(abi.encodeCall(IEVault(collateral).interestFee, ()));

            if (success && data.length >= 32) {
                collateralInfos[i].interestFee = abi.decode(data, (uint256));
            }

            collateralValue += collateralValues[i];
        }

        // if liability is greater than or equal to collateral, the account is eligible for liquidation right away
        if (liabilityValue >= collateralValue) return TTL_LIQUIDATION;

        // if there's no borrow interest rate, time to liquidation is infinite
        if (liabilitySPY == 0) return TTL_INFINITY;

        int256 minTTL = TTL_COMPUTATION_MIN;
        int256 maxTTL = TTL_COMPUTATION_MAX;
        int256 ttl;

        // calculate time to liquidation using binary search
        while (true) {
            ttl = minTTL + (maxTTL - minTTL) / 2;

            // break if the search range is too small
            if (maxTTL <= minTTL + 1 days) break;
            if (ttl < 1 days) break;

            // calculate the liability interest accrued
            uint256 liabilityInterest;
            if (liabilitySPY > 0) {
                (uint256 multiplier, bool overflow) = RPow.rpow(liabilitySPY + ONE, uint256(ttl), ONE);

                if (overflow) return TTL_ERROR;

                liabilityInterest = liabilityValue * multiplier / ONE - liabilityValue;
            }

            // calculate the collaterals interest accrued
            uint256 collateralInterest;
            for (uint256 i = 0; i < collaterals.length; ++i) {
                if (collateralInfos[i].borrowSPY == 0 || collateralInfos[i].totalAssets == 0) continue;

                (uint256 multiplier, bool overflow) = RPow.rpow(collateralInfos[i].borrowSPY + ONE, uint256(ttl), ONE);

                if (overflow) return TTL_ERROR;

                collateralInfos[i].borrowInterest = collateralValues[i] * multiplier / ONE - collateralValues[i];

                collateralInterest += collateralInfos[i].borrowInterest * collateralInfos[i].borrows
                    * (CONFIG_SCALE - collateralInfos[i].interestFee) / collateralInfos[i].totalAssets / CONFIG_SCALE;
            }

            // calculate the health factor
            uint256 hs = (collateralValue + collateralInterest) * ONE / (liabilityValue + liabilityInterest);

            // if the collateral interest accrues fater than the liability interest, the account should never be
            // liquidated
            if (collateralInterest >= liabilityInterest) return TTL_INFINITY;

            // if the health factor is within the acceptable range, return the time to liquidation
            if (hs >= ONE && hs - ONE <= TTL_HS_ACCURACY) break;
            if (hs < ONE && ONE - hs <= TTL_HS_ACCURACY) break;

            // adjust the search range
            if (hs >= ONE) minTTL = ttl + 1 days;
            else maxTTL = ttl - 1 days;
        }

        return ttl > int256(SECONDS_PER_YEAR) ? TTL_MORE_THAN_ONE_YEAR : int256(ttl) / 1 days;
    }
}
"
    },
    "src/SnapshotRegistry/SnapshotRegistry.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import {Context} from "openzeppelin-contracts/utils/Context.sol";
import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol";

/// @title SnapshotRegistry
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Revokeable append-only registry of addresses.
contract SnapshotRegistry is EVCUtil, Ownable {
    struct Entry {
        /// @notice The timestamp when the address was added.
        uint128 addedAt;
        /// @notice The timestamp when the address was revoked.
        uint128 revokedAt;
    }

    /// @notice List of addresses by their base and quote asset.
    /// @dev The keys are lexicographically sorted (asset0 < asset1).
    mapping(address asset0 => mapping(address asset1 => address[])) internal map;

    /// @notice Addresses added to the registry.
    mapping(address => Entry) public entries;

    /// @notice An address was added to the registry.
    /// @param element The address added.
    /// @param asset0 The smaller address out of (base, quote).
    /// @param asset1 The larger address out of (base, quote).
    /// @param addedAt The timestamp when the address was added.
    event Added(address indexed element, address indexed asset0, address indexed asset1, uint256 addedAt);
    /// @notice An address was revoked from the registry.
    /// @param element The address revoked.
    /// @param revokedAt The timestamp when the address was revoked.
    event Revoked(address indexed element, uint256 revokedAt);

    /// @notice The address cannot be added because it already exists in the registry.
    error Registry_AlreadyAdded();
    /// @notice The address cannot be revoked because it does not exist in the registry.
    error Registry_NotAdded();
    /// @notice The address cannot be revoked because it was already revoked from the registry.
    error Registry_AlreadyRevoked();

    /// @notice Deploy SnapshotRegistry.
    /// @param _evc The address of the EVC.
    /// @param _owner The address of the owner.
    constructor(address _evc, address _owner) EVCUtil(_evc) Ownable(_owner) {}

    /// @notice Adds an address to the registry.
    /// @param element The address to add.
    /// @param base The corresponding base asset.
    /// @param quote The corresponding quote asset.
    /// @dev Only callable by the owner.
    function add(address element, address base, address quote) external onlyEVCAccountOwner onlyOwner {
        Entry storage entry = entries[element];
        if (entry.addedAt != 0) revert Registry_AlreadyAdded();
        entry.addedAt = uint128(block.timestamp);

        (address asset0, address asset1) = _sort(base, quote);
        map[asset0][asset1].push(element);

        emit Added(element, asset0, asset1, block.timestamp);
    }

    /// @notice Revokes an address from the registry.
    /// @param element The address to revoke.
    /// @dev Only callable by the owner.
    function revoke(address element) external onlyEVCAccountOwner onlyOwner {
        Entry storage entry = entries[element];
        if (entry.addedAt == 0) revert Registry_NotAdded();
        if (entry.revokedAt != 0) revert Registry_AlreadyRevoked();
        entry.revokedAt = uint128(block.timestamp);
        emit Revoked(element, block.timestamp);
    }

    /// @notice Returns the all valid addresses for a given base and quote.
    /// @param base The address of the base asset.
    /// @param quote The address of the quote asset.
    /// @param snapshotTime The timestamp to check.
    /// @dev Order of base and quote does not matter.
    /// @return All addresses for base and quote valid at `snapshotTime`.
    function getValidAddresses(address base, address quote, uint256 snapshotTime)
        external
        view
        returns (address[] memory)
    {
        (address asset0, address asset1) = _sort(base, quote);
        address[] memory elements = map[asset0][asset1];
        address[] memory validElements = new address[](elements.length);

        uint256 numValid = 0;
        for (uint256 i = 0; i < elements.length; ++i) {
            address element = elements[i];
            if (isValid(element, snapshotTime)) {
                validElements[numValid++] = element;
            }
        }

        /// @solidity memory-safe-assembly
        assembly {
            // update the length
            mstore(validElements, numValid)
        }
        return validElements;
    }

    /// @notice Returns whether an address was valid at a point in time.
    /// @param element The address to check.
    /// @param snapshotTime The timestamp to check.
    /// @dev Returns false if:
    /// - address was never added,
    /// - address was added after the timestamp,
    /// - address was revoked before or at the timestamp.
    /// @return Whether `element` was valid at `snapshotTime`.
    function isValid(address element, uint256 snapshotTime) public view returns (bool) {
        uint256 addedAt = entries[element].addedAt;
        uint256 revokedAt = entries[element].revokedAt;

        if (addedAt == 0 || addedAt > snapshotTime) return false;
        if (revokedAt != 0 && revokedAt <= snapshotTime) return false;
        return true;
    }

    /// @notice Lexicographically sort two addresses.
    /// @param assetA One of the assets in the pair.
    /// @param assetB The other asset in the pair.
    /// @return The address first in lexicographic order.
    /// @return The address second in lexicographic order.
    function _sort(address assetA, address assetB) internal pure returns (address, address) {
        return assetA < assetB ? (assetA, assetB) : (assetB, assetA);
    }

    /// @dev Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be
    /// called by the current owner.
    /// NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is
    /// only available to the owner.
    function renounceOwnership() public virtual override onlyEVCAccountOwner {
        super.renounceOwnership();
    }

    /// @dev Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.
    function transferOwnership(address newOwner) public virtual override onlyEVCAccountOwner {
        super.transferOwnership(newOwner);
    }

    /// @notice Retrieves the message sender in the context of the EVC.
    /// @dev This function returns the account on behalf of which the current operation is being performed, which is
    /// either msg.sender or the account authenticated by the EVC.
    /// @return The address of the message sender.
    function _msgSender() internal view override (Context, EVCUtil) returns (address) {
        return EVCUtil._msgSender();
    }
}
"
    },
    "lib/euler-price-oracle/src/interfaces/IPriceOracle.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

/// @title IPriceOracle
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Common PriceOracle interface.
interface IPriceOracle {
    /// @notice Get the name of the oracle.
    /// @return The name of the oracle.
    function name() external view returns (string memory);

    /// @notice One-sided price: How much quote token you would get for inAmount of base token, assuming no price spread.
    /// @param inAmount The amount of `base` to convert.
    /// @param base The token that is being priced.
    /// @param quote The token that is the unit of account.
    /// @return outAmount The amount of `quote` that is equivalent to `inAmount` of `base`.
    function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256 outAmount);

    /// @notice Two-sided price: How much quote token you would get/spend for selling/buying inAmount of base token.
    /// @param inAmount The amount of `base` to convert.
    /// @param base The token that is being priced.
    /// @param quote The token that is the unit of account.
    /// @return bidOutAmount The amount of `quote` you would get for selling `inAmount` of `base`.
    /// @return askOutAmount The amount of `quote` you would spend for buying `inAmount` of `base`.
    function getQuotes(uint256 inAmount, address base, address quote)
        external
        view
        returns (uint256 bidOutAmount, uint256 askOutAmount);
}
"
    },
    "lib/euler-price-oracle/src/lib/Errors.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title Errors
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Collects common errors in PriceOracles.
library Errors {
    /// @notice The external feed returned an invalid answer.
    error PriceOracle_InvalidAnswer();
    /// @notice The configuration parameters for the PriceOracle are invalid.
    error PriceOracle_InvalidConfiguration();
    /// @notice The base/quote path is not supported.
    /// @param base The address of the base asset.
    /// @param quote The address of the quote asset.
    error PriceOracle_NotSupported(address base, address quote);
    /// @notice The quote cannot be completed due to overflow.
    error PriceOracle_Overflow();
    /// @notice The price is too stale.
    /// @param staleness The time elapsed since the price was updated.
    /// @param maxStaleness The maximum time elapsed since the last price update.
    error PriceOracle_TooStale(uint256 staleness, uint256 maxStaleness);
    /// @notice The method can only be called by the governor.
    error Governance_CallerNotGovernor();
}
"
    },
    "src/Lens/LensTypes.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

struct AccountInfo {
    EVCAccountInfo evcAccountInfo;
    VaultAccountInfo vaultAccountInfo;
    AccountRewardInfo accountRewardInfo;
}

struct AccountMultipleVaultsInfo {
    EVCAccountInfo evcAccountInfo;
    VaultAccountInfo[] vaultAccountInfo;
    AccountRewardInfo[] accountRewardInfo;
}

struct EVCAccountInfo {
    uint256 timestamp;
    address evc;
    address account;
    bytes19 addressPrefix;
    address owner;
    bool isLockdownMode;
    bool isPermitDisabledMode;
    uint256 lastAccountStatusCheckTimestamp;
    address[] enabledControllers;
    address[] enabledCollaterals;
}

struct VaultAccountInfo {
    uint256 timestamp;
    address account;
    address vault;
    address asset;
    uint256 assetsAccount;
    uint256 shares;
    uint256 assets;
    uint256 borrowed;
    uint256 assetAllowanceVault;
    uint256 assetAllowanceVaultPermit2;
    uint256 assetAllowanceExpirationVaultPermit2;
    uint256 assetAllowancePermit2;
    bool balanceForwarderEnabled;
    bool isController;
    bool isCollateral;
    AccountLiquidityInfo liquidityInfo;
}

struct AccountLiquidityInfo {
    bool queryFailure;
    bytes queryFailureReason;
    int256 timeToLiquidation;
    uint256 liabilityValue;
    uint256 collateralValueBorrowing;
    uint256 collateralValueLiquidation;
    uint256 collateralValueRaw;
    CollateralLiquidityInfo[] collateralLiquidityBorrowingInfo;
    CollateralLiquidityInfo[] collateralLiquidityLiquidationInfo;
    CollateralLiquidityInfo[] collateralLiquidityRawInfo;
}

struct CollateralLiquidityInfo {
    address collateral;
    uint256 collateralValue;
}

struct VaultInfoERC4626 {
    uint256 timestamp;
    address vault;
    string vaultName;
    string vaultSymbol;
    uint256 vaultDecimals;
    address asset;
    string assetName;
    string assetSymbol;
    uint256 assetDecimals;
    uint256 totalShares;
    uint256 totalAssets;
    bool isEVault;
}

struct VaultInfoFull {
    uint256 timestamp;
    address vault;
    string vaultName;
    string vaultSymbol;
    uint256 vaultDecimals;
    address asset;
    string assetName;
    string assetSymbol;
    uint256 assetDecimals;
    address unitOfAccount;
    string unitOfAccountName;
    string unitOfAccountSymbol;
    uint256 unitOfAccountDecimals;
    uint256 totalShares;
    uint256 totalCash;
    uint256 totalBorrowed;
    uint256 totalAssets;
    uint256 accumulatedFeesShares;
    uint256 accumulatedFeesAssets;
    address governorFeeReceiver;
    address protocolFeeReceiver;
    uint256 protocolFeeShare;
    uint256 interestFee;
    uint256 hookedOperations;
    uint256 configFlags;
    uint256 supplyCap;
    uint256 borrowCap;
    uint256 maxLiquidationDiscount;
    uint256 liquidationCoolOffTime;
    address dToken;
    address oracle;
    address interestRateModel;
    address hookTarget;
    address evc;
    address protocolConfig;
    address balanceTracker;
    address permit2;
    address creator;
    address governorAdmin;
    VaultInterestRateModelInfo irmInfo;
    LTVInfo[] collateralLTVInfo;
    AssetPriceInfo liabilityPriceInfo;
    AssetPriceInfo[] collateralPriceInfo;
    OracleDetailedInfo oracleInfo;
    AssetPriceInfo backupAssetPriceInfo;
    OracleDetailedInfo backupAssetOracleInfo;
}

struct LTVInfo {
    address collateral;
    uint256 borrowLTV;
    uint256 liquidationLTV;
    uint256 initialLiquidationLTV;
    uint256 targetTimestamp;
    uint256 rampDuration;
}

struct AssetPriceInfo {
    bool queryFailure;
    bytes queryFailureReason;
    uint256 timestamp;
    address oracle;
    address asset;
    address unitOfAccount;
    uint256 amountIn;
    uint256 amountOutMid;
    uint256 amountOutBid;
    uint256 amountOutAsk;
}

struct VaultInterestRateModelInfo {
    bool queryFailure;
    bytes queryFailureReason;
    address vault;
    address interestRateModel;
    InterestRateInfo[] interestRateInfo;
    InterestRateModelDetailedInfo interestRateModelInfo;
}

struct InterestRateInfo {
    uint256 cash;
    uint256 borrows;
    uint256 borrowSPY;
    uint256 borrowAPY;
    uint256 supplyAPY;
}

enum InterestRateModelType {
    UNKNOWN,
    KINK,
    ADAPTIVE_CURVE,
    KINKY,
    FIXED_CYCLICAL_BINARY
}

struct InterestRateModelDetailedInfo {
    address interestRateModel;
    InterestRateModelType interestRateModelType;
    bytes interestRateModelParams;
}

struct KinkIRMInfo {
    uint256 baseRate;
    uint256 slope1;
    uint256 slope2;
    uint256 kink;
}

struct AdaptiveCurveIRMInfo {
    int256 targetUtilization;
    int256 initialRateAtTarget;
    int256 minRateAtTarget;
    int256 maxRateAtTarget;
    int256 curveSteepness;
    int256 adjustmentSpeed;
}

struct KinkyIRMInfo {
    uint256 baseRate;
    uint256 slope;
    uint256 shape;
    uint256 kink;
    uint256 cutoff;
}

struct FixedCyclicalBinaryIRMInfo {
    uint256 primaryRate;
    uint256 secondaryRate;
    uint256 primaryDuration;
    uint256 secondaryDuration;
    uint256 startTimestamp;
}

struct AccountRewardInfo {
    uint256 timestamp;
    address account;
    address vault;
    address balanceTracker;
    bool balanceForwarderEnabled;
    uint256 balance;
    EnabledRewardInfo[] enabledRewardsInfo;
}

struct EnabledRewardInfo {
    address reward;
    uint256 earnedReward;
    uint256 earnedRewardRecentIgnored;
}

struct VaultRewardInfo {
    uint256 timestamp;
    address vault;
    address reward;
    string rewardName;
    string rewardSymbol;
    uint8 rewardDecimals;
    address balanceTracker;
    uint256 epochDuration;
    uint256 currentEpoch;
    uint256 totalRewardedEligible;
    uint256 totalRewardRegistered;
    uint256 totalRewardClaimed;
    RewardAmountInfo[] epochInfoPrevious;
    RewardAmountInfo[] epochInfoUpcoming;
}

struct RewardAmountInfo {
    uint256 epoch;
    uint256 epochStart;
    uint256 epochEnd;
    uint256 rewardAmount;
}

struct OracleDetailedInfo {
    address oracle;
    string name;
    bytes oracleInfo;
}

struct EulerRouterInfo {
    address governor;
    address fallbackOracle;
    OracleDetailedInfo fallbackOracleInfo;
    address[] bases;
    address[] quotes;
    address[][] resolvedAssets;
    address[] resolvedOracles;
    OracleDetailedInfo[] resolvedOraclesInfo;
}

struct ChainlinkOracleInfo {
    address base;
    address quote;
    address feed;
    string feedDescription;
    uint256 maxStaleness;
}

struct ChainlinkInfrequentOracleInfo {
    address base;
    address quote;
    address feed;
    string feedDescription;
    uint256 maxStaleness;
}

struct ChronicleOracleInfo {
    address base;
    address quote;
    address feed;
    uint256 maxStaleness;
}

struct LidoOracleInfo {
    address base;
    address quote;
}

struct LidoFundamentalOracleInfo {
    address base;
    address quote;
}

struct PythOracleInfo {
    address pyth;
    address base;
    address quote;
    bytes32 feedId;
    uint256 maxStaleness;
    uint256 maxConfWidth;
}

struct RedstoneCoreOracleInfo {
    address base;
    address quote;
    bytes32 feedId;
    uint8 feedDecimals;
    uint256 maxStaleness;
    uint208 cachePrice;
    uint48 cachePriceTimestamp;
}

struct UniswapV3OracleInfo {
    address tokenA;
    address tokenB;
    address pool;
    uint24 fee;
    uint32 twapWindow;
}

struct FixedRateOracleInfo {
    address base;
    address quote;
    uint256 rate;
}

struct RateProviderOracleInfo {
    address base;
    address quote;
    address rateProvider;
}

struct OndoOracleInfo {
    address base;
    address quote;
    address rwaOracle;
}

struct PendleProviderOracleInfo {
    address base;
    address quote;
    address pendleMarket;
    uint32 twapWindow;
}

struct PendleUniversalOracleInfo {
    address base;
    address quote;
    address pendleMarket;
    uint32 twapWindow;
}

struct CurveEMAOracleInfo {
    address base;
    address quote;
    address pool;
    uint256 priceOracleIndex;
}

struct SwaapSafeguardProviderOracleInfo {
    address base;
    address quote;
    bytes32 poolId;
}

struct CrossAdapterInfo {
    address base;
    address cross;
    address quote;
    address oracleBaseCross;
    address oracleCrossQuote;
    OracleDetailedInfo oracleBaseCrossInfo;
    OracleDetailedInfo oracleCrossQuoteInfo;
}

struct EulerEarnVaultInfoFull {
    uint256 timestamp;
    address vault;
    string vaultName;
    string vaultSymbol;
    uint256 vaultDecimals;
    address asset;
    string assetName;
    string assetSymbol;
    uint256 assetDecimals;
    uint256 totalShares;
    uint256 totalAssets;
    uint256 lostAssets;
    uint256 availableAssets;
    uint256 timelock;
    uint256 performanceFee;
    address feeReceiver;
    address owner;
    address creator;
    address curator;
    address guardian;
    address evc;
    address permit2;
    uint256 pendingTimelock;
    uint256 pendingTimelockValidAt;
    address pendingGuardian;
    uint256 pendingGuardianValidAt;
    address[] supplyQueue;
    EulerEarnVaultStrategyInfo[] strategies;
}

struct EulerEarnVaultStrategyInfo {
    address strategy;
    uint256 allocatedAssets;
    uint256 availableAssets;
    uint256 currentAllocationCap;
    uint256 pendingAllocationCap;
    uint256 pendingAllocationCapValidAt;
    uint256 removableAt;
    VaultInfoERC4626 info;
}
"
    },
    "lib/euler-vault-kit/src/EVault/IEVault.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.8.0;

import {IVault as IEVCVault} from "ethereum-vault-connector/interfaces/IVault.sol";

// Full interface of EVault and all it's modules

/// @title IInitialize
/// @notice Interface of the initialization module of EVault
interface IInitialize {
    /// @notice Initialization of the newly deployed proxy contract
    /// @param proxyCreator Account which created the proxy or should be the initial governor
    function initialize(address proxyCreator) external;
}

/// @title IERC20
/// @notice Interface of the EVault's Initialize module
interface IERC20 {
    /// @notice Vault share token (eToken) name, ie "Euler Vault: DAI"
    /// @return The name of the eToken
    function name() external view returns (string memory);

    /// @notice Vault share token (eToken) symbol, ie "eDAI"
    /// @return The symbol of the eToken
    function symbol() external view returns (string memory);

    /// @notice Decimals, the same as the asset's or 18 if the asset doesn't implement `decimals()`
    /// @return The decimals of the eToken
    function decimals() external view returns (uint8);

    /// @notice Sum of all eToken balances
    /// @return The total supply of the eToken
    function totalSupply() external view returns (uint256);

    /// @notice Balance of a particular account, in eTokens
    /// @param account Address to query
    /// @return The balance of the account
    function balanceOf(address account) external view returns (uint256);

    /// @notice Retrieve the current allowance
    /// @param holder The account holding the eTokens
    /// @param spender Trusted address
    /// @return The allowance from holder for spender
    function allowance(address holder, address spender) external view returns (uint256);

    /// @notice Transfer eTokens to another address
    /// @param to Recipient account
    /// @param amount In shares.
    /// @return True if transfer succeeded
    function transfer(address to, uint256 amount) external returns (bool);

    /// @notice Transfer eTokens from one address to another
    /// @param from This address must've approved the to address
    /// @param to Recipient account
    /// @param amount In shares
    /// @return True if transfer succeeded
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    /// @notice Allow spender to access an amount of your eTokens
    /// @param spender Trusted address
    /// @param amount Use max uint for "infinite" allowance
    /// @return True if approval succeeded
    function approve(address spender, uint256 amount) external returns (bool);
}

/// @title IToken
/// @notice Interface of the EVault's Token module
interface IToken is IERC20 {
    /// @notice Transfer the full eToken balance of an address to another
    /// @param from This address must've approved the to address
    /// @param to Recipient account
    /// @return True if transfer succeeded
    function transferFromMax(address from, address to) external returns (bool);
}

/// @title IERC4626
/// @notice Interface of an ERC4626 vault
interface IERC4626 {
    /// @notice Vault's underlying asset
    /// @return The vault's underlying asset
    function asset() external view returns (address);

    /// @notice Total amount of managed assets, cash and borrows
    /// @return The total amount of assets
    function totalAssets() external view returns (uint256);

    /// @notice Calculate amount of assets corresponding to the requested shares amount
    /// @param shares Amount of shares to convert
    /// @return The amount of assets
    function convertToAssets(uint256 shares) external view returns (uint256);

    /// @notice Calculate amount of shares corresponding to the requested assets amount
    /// @param assets Amount of assets to convert
    /// @return The amount of shares
    function convertToShares(uint256 assets) external view returns (uint256);

    /// @notice Fetch the maximum amount of assets a user can deposit
    /// @param account Address to query
    /// @return The max amount of assets the account can deposit
    function maxDeposit(address account) external view returns (uint256);

    /// @notice Calculate an amount of shares that would be created by depositing assets
    /// @param assets Amount of assets deposited
    /// @return Amount of shares received
    function previewDeposit(uint256 assets) external view returns (uint256);

    /// @notice Fetch the maximum amount of shares a user can mint
    /// @param account Address to query
    /// @return The max amount of shares the account can mint
    function maxMint(address account) external view returns (uint256);

    /// @notice Calculate an amount of assets that would be required to mint requested amount of shares
    /// @param shares Amount of shares to be minted
    /// @return Required amount of assets
    function previewMint(uint256 shares) external view returns (uint256);

    /// @notice Fetch the maximum amount of assets a user is allowed to withdraw
    /// @param owner Account holding the shares
    /// @return The maximum amount of assets the owner is allowed to withdraw
    function maxWithdraw(address owner) external view returns (uint256);

    /// @notice Calculate the amount of shares that will be burned when withdrawing requested amount of assets
    /// @param assets Amount of assets withdrawn
    /// @return Amount of shares burned
    function previewWithdraw(uint256 assets) external view returns (uint256);

    /// @notice Fetch the maximum amount of shares a user is allowed to redeem for assets
    /// @param owner Account holding the shares
    /// @return The maximum amount of shares the owner is allowed to redeem
    function maxRedeem(address owner) external view returns (uint256);

    /// @notice Calculate the amount of assets that will be transferred when redeeming requested amount of shares
    /// @param shares Amount of shares redeemed
    /// @return Amount of assets transferred
    function previewRedeem(uint256 shares) external view returns (uint256);

    /// @notice Transfer requested amount of underlying tokens from sender to the vault pool in return for shares
    /// @param amount Amount of assets to deposit (use max uint256 for full underlying token balance)
    /// @param receiver An account to receive the shares
    /// @return Amount of shares minted
    /// @dev Deposit will round down the amount of assets that are converted to shares. To prevent losses consider using
    /// mint instead.
    function deposit(uint256 amount, address receiver) external returns (uint256);

    /// @notice Transfer underlying tokens from sender to the vault pool in return for requested amount of shares
    /// @param amount Amount of shares to be minted
    /// @param receiver An account to receive the shares
    /// @return Amount of assets deposited
    function mint(uint256 amount, address receiver) external returns (uint256);

    /// @notice Transfer requested amount of underlying tokens from the vault and decrease account's shares balance
    /// @param amount Amount of assets to withdraw
    /// @param receiver Account to receive the withdrawn assets
    /// @param owner Account holding the shares to burn
    /// @return Amount of shares burned
    function withdraw(uint256 amount, address receiver, address owner) external returns (uint256);

    /// @notice Burn requested shares and transfer corresponding underlying tokens from the vault to the receiver
    /// @param amount Amount of shares to burn (use max uint256 to burn full owner balance)
    /// @param receiver Account to receive the withdrawn assets
    /// @param owner Account holding the shares to burn.
    /// @return Amount of assets transferred
    function redeem(uint256 amount, address receiver, address owner) external returns (uint256);
}

/// @title IVault
/// @notice Interface of the EVault's Vault module
interface IVault is IERC4626 {
    /// @notice Balance of the fees accumulator, in shares
    /// @return The accumulated fees in shares
    function accumulatedFees() external view returns (uint256);

    /// @notice Balance of the fees accumulator, in underlying units
    /// @return The accumulated fees in asset units
    function accumulatedFeesAssets() external view returns (uint256);

    /// @notice Address of the original vault creator
    /// @return The address of the creator
    function creator() external view returns (address);

    /// @notice Creates shares for the receiver, from excess asset balances of the vault (not accounted for in `cash`)
    /// @param amount Amount of assets to claim (use max uint256 to claim all available assets)
    /// @param receiver An account to receive the shares
    /// @return Amount of shares minted
    /// @dev Could be used as an alternative deposit flow in certain scenarios. E.g. swap directly to the vault, call
    /// `skim` to claim deposit.
    function skim(uint256 amount, address receiver) external returns (uint256);
}

/// @title IBorrowing
/// @notice Interface of the EVault's Borrowing module
interface IBorrowing {
    /// @notice Sum of all outstanding debts, in underlying units (increases as interest is accrued)
    /// @return The total borrows in asset units
    function totalBorrows() external view returns (uint256);

    /// @notice Sum of all outstanding debts, in underlying units scaled up by shifting
    /// INTERNAL_DEBT_PRECISION_SHIFT bits
    /// @return The total borrows in internal debt precision
    function totalBorrowsExact() external view returns (uint256);

    /// @notice Balance of vault assets as tracked by deposits/withdrawals and borrows/repays
    /// @return The amount of assets the vault tracks as current direct holdings
    function cash() external view returns (uint256);

    /// @notice Debt owed by a particular account, in underlying units
    /// @param account Address to query
    /// @return The debt of the account in asset units
    function debtOf(address account) external view returns (uint256);

    /// @notice Debt owed by a particular account, in underlying units scaled up by shifting
    /// INTERNAL_DEBT_PRECISION_SHIFT bits
    /// @param account Address to query
    /// @return The debt of the account in internal precision
    function debtOfExact(address account) external view returns (uint256);

    /// @notice Retrieves the current interest rate for an asset
    /// @return The interest rate in yield-per-second, scaled by 10**27
    function interestRate() external view returns (uint256);

    /// @notice Retrieves the current interest rate accumulator for an asset
    /// @return An opaque accumulator that increases as interest is accrued
    function interestAccumulator() external view returns (uint256);

    /// @notice Returns an address of the sidecar DToken
    /// @return The address of the DToken
    function dToken() external view returns (address);

    /// @notice Transfer underlying tokens from the vault to the sender, and increase sender's debt
    /// @param amount Amount of assets to borrow (use max uint256 for all available tokens)
    /// @param receiver Account receiving the borrowed tokens
    /// @return Amount of assets borrowed
    function borrow(uint256 amount, address receiver) external returns (uint256);

    /// @notice Transfer underlying tokens from the sender to the vault, and decrease receiver's debt
    /// @param amount Amount of debt to repay in assets (use max uint256 for full debt)
    /// @param receiver Account holding the debt to be repaid
    /// @return Amount of assets repaid
    function repay(uint256 amount, address receiver) external returns (uint256);

    /// @notice Pay off liability with shares ("self-repay")
    /// @param amount In asset units (use max uint256 to repay the debt in full or up to the available deposit)
    /// @param receiver Account to remove debt from by burning sender's shares
    /// @return shares Amount of shares burned
    /// @return debt Amount of debt removed in assets
    /// @dev Equivalent to withdrawing and repaying, but no assets are needed to be present in the vault
    /// @dev Contrary to a regular `repay`, if account is unhealthy, the repay amount must bring the account back to
    /// health, or the operation will revert during account status check
    function repayWithShares(uint256 amount, address receiver) external returns (uint256 shares, uint256 debt);

    /// @notice Take over debt from another account
    /// @param amount Amount of debt in asset units (use max uint256 for all the account's debt)
    /// @param from Account to pull the debt from
    /// @dev Due to internal debt precision accounting, the liability reported on either or both accounts after
    /// calling `pullDebt` may not match the `amount` requested precisely
    function pullDebt(uint256 amount, address from) external;

    /// @notice Request a flash-loan. A onFlashLoan() callback in msg.sender will be invoked, which must repay the loan
    /// to the main Euler address prior to returning.
    /// @param amount In asset units
    /// @param data Passed through to the onFlashLoan() callback, so contracts don't need to store transient data in
    /// storage
    function flashLoan(uint256 amount, bytes calldata data) external;

    /// @notice Updates interest accumulator and totalBorrows, credits reserves, re-targets interest rate, and logs
    /// vault status
    function touch() external;
}

/// @title ILiquidation
/// @notice Interface of the EVault's Liquidation module
interface ILiquidation {
    /// @notice Checks to see if a liquidation would be profitable, without actually doing anything
    /// @param liquidator Address that will initiate the liquidation
    /// @param violator Address that may be in collateral violation
    /// @param collateral Collateral which is to be seized
    /// @return maxRepay Max amount of debt that can be repaid, in asset units
    /// @return maxYield Yield in collateral corresponding to max allowed amount of debt to be repaid, in collateral
    /// balance (shares for vaults)
    function checkLiquidation(address liquidator, address violator, address collateral)
        external
        view
        returns (uint256 maxRepay, uint256 maxYield);

    /// @notice Attempts to perform a liquidation
    /// @param violator Address that may be in collateral violation
    /// @param collateral Collateral which is to be seized
    /// @param repayAssets The amount of underlying debt to be transferred from violator to sender, in asset units (use
    /// max uint256 to repay the maximum possible amount). Meant as slippage check together with `minYieldBalance`
    /// @param minYieldBalance The minimum acceptable amount of collateral to be transferred from violator to sender, in
    /// collateral balance units (shares for vaults).  Meant as slippage check together with `repayAssets`
    /// @dev If `repayAssets` is set to max uint256 it is assumed the caller will perform their own slippage checks to
    /// make sure they are not taking on too much debt. This option is mainly meant for smart contract liquidators
    function liquidate(address violator, address collateral, uint256 repayAssets, uint256 minYieldBalance) external;
}

/// @title IRiskManager
/// @notice Interface of the EVault's RiskManager module
interface IRiskManager is IEVCVault {
    /// @notice Retrieve account's total liquidity
    /// @param account Account holding debt in this vault
    /// @param liquidation Flag to indicate if the calculation should be performed in liquidation vs account status
    /// check mode, where different LTV values might apply.
    /// @return collateralValue Total risk adjusted value of all collaterals in unit of account
    /// @return liabilityValue Value of debt in unit of account
    function accountLiquidity(address account, bool liquidation)
        external
        view
        returns (uint256 collateralValue, uint256 liabilityValue);

    /// @notice Retrieve account's liquidity per collateral
    /// @param account Account holding debt in this vault
    /// @param liquidation Flag to indicate if the calculation should be performed in liquidation vs account status
    /// check mode, where different LTV values might apply.
    /// @return collaterals Array of collaterals enabled
    /// @return collateralValues Array of risk adjusted collateral values corresponding to items in collaterals array.
    /// In unit of account
    /// @return liabilityValue Value of debt in unit of account
    function accountLiquidityFull(address account, bool liquidation)
        external
        view
        returns (address[] memory collaterals, uint256[] memory collateralValues, uint256 liabilityValue);

    /// @notice Release control of the account on EVC if no outstanding debt is present
    function disableController() external;

    /// @notice Checks the status of an account and reverts if account is not healthy
    /// @param account The address of the account to be checked
    /// @return magicValue Must return the bytes4 magic value 0xb168c58f (which is a selector of this function) when
    /// account status is valid, or revert otherwise.
    /// @dev Only callable by EVC during status checks
    function checkAccountStatus(address account, address[] calldata collaterals) external view returns (bytes4);

    /// @notice Checks the status of the vault and reverts if caps are exceeded
    /// @return magicValue Must return the bytes4 magic value 0x4b3d1223 (which is a selector of this fun

Tags:
ERC20, Multisig, Mintable, Burnable, Swap, Liquidity, Yield, Upgradeable, Multi-Signature, Factory, Oracle|addr:0xced1a496deebdaf785487218568ad8dd8a85be32|verified:true|block:23452759|tx:0x4c0e2a852fc3b23068d0c863c016ed95d3997c8b758ce1d9b617976c381a37bf|first_check:1758967927

Submitted on: 2025-09-27 12:12:08

Comments

Log in to comment.

No comments yet.