VaultLens

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/VaultLens.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import {IRewardStreams} from "reward-streams/interfaces/IRewardStreams.sol";
import {IEVault} from "evk/EVault/IEVault.sol";
import {IIRM, IRMLinearKink} from "evk/InterestRateModels/IRMLinearKink.sol";
import {OracleLens} from "./OracleLens.sol";
import {UtilsLens} from "./UtilsLens.sol";
import {IRMLens} from "./IRMLens.sol";
import {Utils} from "./Utils.sol";
import "evk/EVault/shared/types/AmountCap.sol";
import "./LensTypes.sol";

contract VaultLens is Utils {
    OracleLens public immutable oracleLens;
    UtilsLens public immutable utilsLens;
    IRMLens public immutable irmLens;
    address[] internal backupUnitOfAccounts;

    constructor(address _oracleLens, address _utilsLens, address _irmLens) {
        oracleLens = OracleLens(_oracleLens);
        utilsLens = UtilsLens(_utilsLens);
        irmLens = IRMLens(_irmLens);

        address WETH = getWETHAddress();
        backupUnitOfAccounts.push(address(840));
        if (WETH != address(0)) backupUnitOfAccounts.push(WETH);
        backupUnitOfAccounts.push(0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB);
    }

    function getVaultInfoStatic(address vault) public view returns (VaultInfoStatic memory) {
        VaultInfoStatic memory result;

        result.timestamp = block.timestamp;
        result.vault = vault;

        result.vaultName = IEVault(vault).name();
        result.vaultSymbol = IEVault(vault).symbol();
        result.vaultDecimals = IEVault(vault).decimals();

        result.asset = IEVault(vault).asset();
        result.assetName = _getStringOrBytes32(result.asset, IEVault(vault).name.selector);
        result.assetSymbol = _getStringOrBytes32(result.asset, IEVault(vault).symbol.selector);
        result.assetDecimals = _getDecimals(result.asset);

        result.unitOfAccount = IEVault(vault).unitOfAccount();
        result.unitOfAccountName = _getStringOrBytes32(result.unitOfAccount, IEVault(vault).name.selector);
        result.unitOfAccountSymbol = _getStringOrBytes32(result.unitOfAccount, IEVault(vault).symbol.selector);
        result.unitOfAccountDecimals = _getDecimals(result.unitOfAccount);

        result.dToken = IEVault(vault).dToken();
        result.oracle = IEVault(vault).oracle();
        result.evc = IEVault(vault).EVC();
        result.protocolConfig = IEVault(vault).protocolConfigAddress();
        result.balanceTracker = IEVault(vault).balanceTrackerAddress();
        result.permit2 = IEVault(vault).permit2Address();
        result.creator = IEVault(vault).creator();

        return result;
    }

    function getVaultInfoDynamic(address vault) public view returns (VaultInfoDynamic memory) {
        VaultInfoDynamic memory result;

        address asset = IEVault(vault).asset();
        address unitOfAccount = IEVault(vault).unitOfAccount();
        address oracle = IEVault(vault).oracle();

        result.timestamp = block.timestamp;
        result.vault = vault;

        result.totalShares = IEVault(vault).totalSupply();
        result.totalCash = IEVault(vault).cash();
        result.totalBorrowed = IEVault(vault).totalBorrows();
        result.totalAssets = IEVault(vault).totalAssets();

        result.accumulatedFeesShares = IEVault(vault).accumulatedFees();
        result.accumulatedFeesAssets = IEVault(vault).accumulatedFeesAssets();

        result.governorFeeReceiver = IEVault(vault).feeReceiver();
        result.protocolFeeReceiver = IEVault(vault).protocolFeeReceiver();
        result.protocolFeeShare = IEVault(vault).protocolFeeShare();
        result.interestFee = IEVault(vault).interestFee();

        (result.hookTarget, result.hookedOperations) = IEVault(vault).hookConfig();
        result.configFlags = IEVault(vault).configFlags();

        result.maxLiquidationDiscount = IEVault(vault).maxLiquidationDiscount();
        result.liquidationCoolOffTime = IEVault(vault).liquidationCoolOffTime();

        (result.supplyCap, result.borrowCap) = IEVault(vault).caps();
        result.supplyCap = AmountCapLib.resolve(AmountCap.wrap(uint16(result.supplyCap)));
        result.borrowCap = AmountCapLib.resolve(AmountCap.wrap(uint16(result.borrowCap)));

        result.interestRateModel = IEVault(vault).interestRateModel();
        result.governorAdmin = IEVault(vault).governorAdmin();

        if (result.interestRateModel == address(0)) {
            result.irmInfo.queryFailure = true;
        } else {
            result.irmInfo.vault = vault;
            result.irmInfo.interestRateModel = result.interestRateModel;
            result.irmInfo.interestRateInfo = new InterestRateInfo[](1);
            result.irmInfo.interestRateInfo[0].cash = result.totalCash;
            result.irmInfo.interestRateInfo[0].borrows = result.totalBorrowed;
            result.irmInfo.interestRateInfo[0].borrowSPY = IEVault(vault).interestRate();
            (result.irmInfo.interestRateInfo[0].borrowAPY, result.irmInfo.interestRateInfo[0].supplyAPY) = _computeAPYs(
                result.irmInfo.interestRateInfo[0].borrowSPY, result.totalCash, result.totalBorrowed, result.interestFee
            );
            result.irmInfo.interestRateModelInfo = irmLens.getInterestRateModelInfo(result.interestRateModel);
        }

        result.collateralLTVInfo = getRecognizedCollateralsLTVInfo(vault);

        result.liabilityPriceInfo = utilsLens.getControllerAssetPriceInfo(vault, asset);

        result.collateralPriceInfo = new AssetPriceInfo[](result.collateralLTVInfo.length);

        address[] memory bases = new address[](result.collateralLTVInfo.length + 1);
        address[] memory quotes = new address[](result.collateralLTVInfo.length + 1);
        bases[0] = asset;
        quotes[0] = unitOfAccount;
        for (uint256 i = 0; i < result.collateralLTVInfo.length; ++i) {
            bases[i + 1] = result.collateralLTVInfo[i].collateral;
            quotes[i + 1] = unitOfAccount;
            result.collateralPriceInfo[i] =
                utilsLens.getControllerAssetPriceInfo(vault, result.collateralLTVInfo[i].collateral);
        }

        result.oracleInfo = oracleLens.getOracleInfo(oracle, bases, quotes);

        bases = new address[](1);
        quotes = new address[](1);
        if (oracle == address(0)) {
            for (uint256 i = 0; i < backupUnitOfAccounts.length + 1; ++i) {
                bases[0] = asset;

                if (i == 0) {
                    if (unitOfAccount == address(0)) continue;

                    quotes[0] = unitOfAccount;
                } else {
                    quotes[0] = backupUnitOfAccounts[i - 1];
                }

                result.backupAssetPriceInfo = utilsLens.getAssetPriceInfo(bases[0], quotes[0]);

                if (
                    !result.backupAssetPriceInfo.queryFailure
                        || oracleLens.isStalePullOracle(
                            result.backupAssetPriceInfo.oracle, result.backupAssetPriceInfo.queryFailureReason
                        )
                ) {
                    result.backupAssetOracleInfo =
                        oracleLens.getOracleInfo(result.backupAssetPriceInfo.oracle, bases, quotes);

                    break;
                }
            }
        }

        return result;
    }

    function getVaultInfoFull(address vault) public view returns (VaultInfoFull memory) {
        VaultInfoStatic memory staticInfo = getVaultInfoStatic(vault);
        VaultInfoDynamic memory dynamicInfo = getVaultInfoDynamic(vault);

        VaultInfoFull memory result;

        // From VaultInfoStatic
        result.timestamp = staticInfo.timestamp;
        result.vault = staticInfo.vault;
        result.vaultName = staticInfo.vaultName;
        result.vaultSymbol = staticInfo.vaultSymbol;
        result.vaultDecimals = staticInfo.vaultDecimals;
        result.asset = staticInfo.asset;
        result.assetName = staticInfo.assetName;
        result.assetSymbol = staticInfo.assetSymbol;
        result.assetDecimals = staticInfo.assetDecimals;
        result.unitOfAccount = staticInfo.unitOfAccount;
        result.unitOfAccountName = staticInfo.unitOfAccountName;
        result.unitOfAccountSymbol = staticInfo.unitOfAccountSymbol;
        result.unitOfAccountDecimals = staticInfo.unitOfAccountDecimals;
        result.dToken = staticInfo.dToken;
        result.oracle = staticInfo.oracle;
        result.evc = staticInfo.evc;
        result.protocolConfig = staticInfo.protocolConfig;
        result.balanceTracker = staticInfo.balanceTracker;
        result.permit2 = staticInfo.permit2;
        result.creator = staticInfo.creator;

        // From VaultInfoDynamic
        result.totalShares = dynamicInfo.totalShares;
        result.totalCash = dynamicInfo.totalCash;
        result.totalBorrowed = dynamicInfo.totalBorrowed;
        result.totalAssets = dynamicInfo.totalAssets;
        result.accumulatedFeesShares = dynamicInfo.accumulatedFeesShares;
        result.accumulatedFeesAssets = dynamicInfo.accumulatedFeesAssets;
        result.governorFeeReceiver = dynamicInfo.governorFeeReceiver;
        result.protocolFeeReceiver = dynamicInfo.protocolFeeReceiver;
        result.protocolFeeShare = dynamicInfo.protocolFeeShare;
        result.interestFee = dynamicInfo.interestFee;
        result.hookedOperations = dynamicInfo.hookedOperations;
        result.configFlags = dynamicInfo.configFlags;
        result.supplyCap = dynamicInfo.supplyCap;
        result.borrowCap = dynamicInfo.borrowCap;
        result.maxLiquidationDiscount = dynamicInfo.maxLiquidationDiscount;
        result.liquidationCoolOffTime = dynamicInfo.liquidationCoolOffTime;
        result.interestRateModel = dynamicInfo.interestRateModel;
        result.hookTarget = dynamicInfo.hookTarget;
        result.governorAdmin = dynamicInfo.governorAdmin;
        result.irmInfo = dynamicInfo.irmInfo;
        result.collateralLTVInfo = dynamicInfo.collateralLTVInfo;
        result.liabilityPriceInfo = dynamicInfo.liabilityPriceInfo;
        result.collateralPriceInfo = dynamicInfo.collateralPriceInfo;
        result.oracleInfo = dynamicInfo.oracleInfo;
        result.backupAssetPriceInfo = dynamicInfo.backupAssetPriceInfo;
        result.backupAssetOracleInfo = dynamicInfo.backupAssetOracleInfo;

        return result;
    }

    function getRewardVaultInfo(address vault, address reward, uint256 numberOfEpochs)
        public
        view
        returns (VaultRewardInfo memory)
    {
        VaultRewardInfo memory result;

        result.timestamp = block.timestamp;

        result.vault = vault;
        result.reward = reward;
        result.rewardName = _getStringOrBytes32(result.reward, IEVault(vault).name.selector);
        result.rewardSymbol = _getStringOrBytes32(result.reward, IEVault(vault).symbol.selector);
        result.rewardDecimals = _getDecimals(result.reward);
        result.balanceTracker = IEVault(vault).balanceTrackerAddress();

        if (result.balanceTracker == address(0)) return result;

        result.epochDuration = IRewardStreams(result.balanceTracker).EPOCH_DURATION();
        result.currentEpoch = IRewardStreams(result.balanceTracker).currentEpoch();
        result.totalRewardedEligible = IRewardStreams(result.balanceTracker).totalRewardedEligible(vault, reward);
        result.totalRewardRegistered = IRewardStreams(result.balanceTracker).totalRewardRegistered(vault, reward);
        result.totalRewardClaimed = IRewardStreams(result.balanceTracker).totalRewardClaimed(vault, reward);

        result.epochInfoPrevious = new RewardAmountInfo[](numberOfEpochs);
        result.epochInfoUpcoming = new RewardAmountInfo[](numberOfEpochs);

        for (uint256 i; i < 2 * numberOfEpochs; ++i) {
            uint48 epoch = uint48(result.currentEpoch - numberOfEpochs + i);

            if (i < numberOfEpochs) {
                uint256 index = i;

                result.epochInfoPrevious[index].epoch = epoch;

                result.epochInfoPrevious[index].epochStart =
                    IRewardStreams(result.balanceTracker).getEpochStartTimestamp(epoch);

                result.epochInfoPrevious[index].epochEnd =
                    IRewardStreams(result.balanceTracker).getEpochEndTimestamp(epoch);

                result.epochInfoPrevious[index].rewardAmount =
                    IRewardStreams(result.balanceTracker).rewardAmount(vault, reward, epoch);
            } else {
                uint256 index = i - numberOfEpochs;

                result.epochInfoUpcoming[index].epoch = epoch;

                result.epochInfoUpcoming[index].epochStart =
                    IRewardStreams(result.balanceTracker).getEpochStartTimestamp(epoch);

                result.epochInfoUpcoming[index].epochEnd =
                    IRewardStreams(result.balanceTracker).getEpochEndTimestamp(epoch);

                result.epochInfoUpcoming[index].rewardAmount =
                    IRewardStreams(result.balanceTracker).rewardAmount(vault, reward, epoch);
            }
        }

        return result;
    }

    function getRecognizedCollateralsLTVInfo(address vault) public view returns (LTVInfo[] memory) {
        address[] memory collaterals = IEVault(vault).LTVList();
        LTVInfo[] memory ltvInfo = new LTVInfo[](collaterals.length);
        uint256 numberOfRecognizedCollaterals = 0;

        for (uint256 i = 0; i < collaterals.length; ++i) {
            ltvInfo[i].collateral = collaterals[i];

            (
                ltvInfo[i].borrowLTV,
                ltvInfo[i].liquidationLTV,
                ltvInfo[i].initialLiquidationLTV,
                ltvInfo[i].targetTimestamp,
                ltvInfo[i].rampDuration
            ) = IEVault(vault).LTVFull(collaterals[i]);

            if (ltvInfo[i].targetTimestamp != 0) {
                ++numberOfRecognizedCollaterals;
            }
        }

        LTVInfo[] memory collateralLTVInfo = new LTVInfo[](numberOfRecognizedCollaterals);

        for (uint256 i = 0; i < collaterals.length; ++i) {
            if (ltvInfo[i].targetTimestamp != 0) {
                collateralLTVInfo[i] = ltvInfo[i];
            }
        }

        return collateralLTVInfo;
    }

    function getVaultInterestRateModelInfo(address vault, uint256[] memory cash, uint256[] memory borrows)
        public
        view
        returns (VaultInterestRateModelInfo memory)
    {
        require(cash.length == borrows.length, "VaultLens: invalid input");

        VaultInterestRateModelInfo memory result;

        result.vault = vault;
        result.interestRateModel = IEVault(vault).interestRateModel();

        if (result.interestRateModel == address(0)) {
            result.queryFailure = true;
            return result;
        }

        uint256 interestFee = IEVault(vault).interestFee();
        result.interestRateInfo = new InterestRateInfo[](cash.length);

        for (uint256 i = 0; i < cash.length; ++i) {
            (bool success, bytes memory data) = result.interestRateModel.staticcall(
                abi.encodeCall(IIRM.computeInterestRateView, (vault, cash[i], borrows[i]))
            );

            if (!success || data.length < 32) {
                result.queryFailure = true;
                result.queryFailureReason = data;
                break;
            }

            result.interestRateInfo[i].cash = cash[i];
            result.interestRateInfo[i].borrows = borrows[i];
            result.interestRateInfo[i].borrowSPY = abi.decode(data, (uint256));
            (result.interestRateInfo[i].borrowAPY, result.interestRateInfo[i].supplyAPY) =
                _computeAPYs(result.interestRateInfo[i].borrowSPY, cash[i], borrows[i], interestFee);
        }

        result.interestRateModelInfo = irmLens.getInterestRateModelInfo(result.interestRateModel);

        return result;
    }

    function getVaultKinkInterestRateModelInfo(address vault) public view returns (VaultInterestRateModelInfo memory) {
        address interestRateModel = IEVault(vault).interestRateModel();

        if (interestRateModel == address(0)) {
            VaultInterestRateModelInfo memory result;
            result.vault = vault;
            return result;
        }

        uint256 kink = IRMLinearKink(interestRateModel).kink();
        uint256[] memory cash = new uint256[](3);
        uint256[] memory borrows = new uint256[](3);

        cash[0] = type(uint32).max;
        cash[1] = type(uint32).max - kink;
        cash[2] = 0;
        borrows[0] = 0;
        borrows[1] = kink;
        borrows[2] = type(uint32).max;

        return getVaultInterestRateModelInfo(vault, cash, borrows);
    }
}
"
    },
    "lib/reward-streams/src/interfaces/IRewardStreams.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.8.0;

import "./IBalanceTracker.sol";

/// @title IRewardStreams
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Interface for Reward Streams distributor contract.
interface IRewardStreams {
    function EPOCH_DURATION() external view returns (uint256);
    function MAX_EPOCHS_AHEAD() external view returns (uint256);
    function MAX_DISTRIBUTION_LENGTH() external view returns (uint256);
    function MAX_REWARDS_ENABLED() external view returns (uint256);
    function registerReward(address rewarded, address reward, uint48 startEpoch, uint128[] calldata rewardAmounts) external;
    function updateReward(address rewarded, address reward, address recipient) external returns (uint256);
    function claimReward(address rewarded, address reward, address recipient, bool ignoreRecentReward) external returns (uint256);
    function enableReward(address rewarded, address reward) external returns (bool);
    function disableReward(address rewarded, address reward, bool forfeitRecentReward) external returns (bool);
    function earnedReward(address account, address rewarded, address reward, bool ignoreRecentReward) external view returns (uint256);
    function enabledRewards(address account, address rewarded) external view returns (address[] memory);
    function isRewardEnabled(address account, address rewarded, address reward) external view returns (bool);
    function balanceOf(address account, address rewarded) external view returns (uint256);
    function rewardAmount(address rewarded, address reward) external view returns (uint256);
    function totalRewardedEligible(address rewarded, address reward) external view returns (uint256);
    function totalRewardRegistered(address rewarded, address reward) external view returns (uint256);
    function totalRewardClaimed(address rewarded, address reward) external view returns (uint256);
    function rewardAmount(address rewarded, address reward, uint48 epoch) external view returns (uint256);
    function currentEpoch() external view returns (uint48);
    function getEpoch(uint48 timestamp) external view returns (uint48);
    function getEpochStartTimestamp(uint48 epoch) external view returns (uint48);
    function getEpochEndTimestamp(uint48 epoch) external view returns (uint48);
}

/// @title ITrackingRewardStreams
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Interface for Tracking Reward Streams. Extends `IRewardStreams` and `IBalanceTracker`.
interface ITrackingRewardStreams is IRewardStreams, IBalanceTracker {}

/// @title IStakingRewardStreams
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Interface for Staking Reward Streams. Extends `IRewardStreams` with staking functionality.
interface IStakingRewardStreams is IRewardStreams {
    function stake(address rewarded, uint256 amount) external;
    function unstake(address rewarded, uint256 amount, address recipient, bool forfeitRecentReward) external;
}
"
    },
    "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 function) when
    /// account status is valid, or revert otherwise.
    /// @dev Only callable by EVC during status checks
    function checkVaultStatus() external returns (bytes4);
}

/// @title IBalanceForwarder
/// @notice Interface of the EVault's BalanceForwarder module
interface IBalanceForwarder {
    /// @notice Retrieve the address of rewards contract, tracking changes in account's balances
    /// @return The balance tracker address
    function balanceTrackerAddress() external view returns (address);

    /// @notice Retrieves boolean indicating if the account opted in to forward balance changes to the rewards contract
    /// @param account Address to query
    /// @return True if balance forwarder is enabled
    function balanceForwarderEnabled(address account) external view returns (bool);

    /// @notice Enables balance forwarding for the authenticated account
    /// @dev Only the authenticated account can enable balance forwarding for itself
    /// @dev Should call the IBalanceTracker hook with the current account's balance
    function enableBalanceForwarder() external;

    /// @notice Disables balance forwarding for the authenticated account
    /// @dev Only the authenticated account can disable balance forwarding for itself
    /// @dev Should call the IBalanceTracker hook with the account's balance of 0
    function disableBalanceForwarder() external;
}

/// @title IGovernance
/// @notice Interface of the EVault's Governance module
interface IGovernance {
    /// @notice Retrieves the address of the governor
    /// @return The governor address
    function governorAdmin() external view returns (address);

    /// @notice Retrieves address of the governance fee receiver
    /// @return The fee receiver address
    function feeReceiver() external view returns (address);

    /// @notice Retrieves the interest fee in effect for the vault
    /// @return Amount of interest that is redirected as a fee, as a fraction scaled by 1e4
    function interestFee() external view returns (uint16);

    /// @notice Looks up an asset's currently configured interest rate model
    /// @return Address of the interest rate contract or address zero to indicate 0% interest
    function interestRateModel() external view returns (address);

    /// @notice Retrieves the ProtocolConfig address
    /// @return The protocol config address
    function protocolConfigAddress() external view returns (address);

    /// @notice Retrieves the protocol fee share
    /// @return A percentage share of fees accrued belonging to the protocol, in 1e4 scale
    function protocolFeeShare() external view returns (uint256);

    /// @notice Retrieves the address which will receive protocol's fees
    /// @notice The protocol fee receiver address
    function protocolFeeReceiver() external view returns (address);

    /// @notice Retrieves supply and borrow caps in AmountCap format
    /// @return supplyCap The supply cap in AmountCap format
    /// @return borrowCap The borrow cap in AmountCap format
    function caps() external view returns (uint16 supplyCap, uint16 borrowCap);

    /// @notice Retrieves the borrow LTV of the collateral, which is used to determine if the account is healthy during
    /// account status checks.
    /// @param collateral The address of the collateral to query
    /// @return Borrowing LTV in 1e4 scale
    function LTVBorrow(address collateral) external view returns (uint16);

    /// @notice Retrieves the current liquidation LTV, which is used to determine if the account is eligible for
    /// liquidation
    /// @param collateral The address of the collateral to query
    /// @return Liquidation LTV in 1e4 scale
    function LTVLiquidation(address collateral) external view returns (uint16);

    /// @notice Retrieves LTV configuration for the collateral
    /// @param collateral Collateral asset
    /// @return borrowLTV The current value of borrow LTV for originating positions
    /// @return liquidationLTV The value of fully converged liquidation LTV
    /// @return initialLiquidationLTV The initial value of the liquidation LTV, when the ramp began
    /// @return targetTimestamp The timestamp when the liquidation LTV is considered fully converged
    /// @return rampDuration The time it takes for the liquidation LTV to converge from the initial value to the fully
    /// converged value
    function LTVFull(address collateral)
        external
        view
        returns (
            uint16 borrowLTV,
            uint16 liquidationLTV,
            uint16 initialLiquidationLTV,
            uint48 targetTimestamp,
            uint32 rampDuration
        );

    /// @notice Retrieves a list of collaterals with configured LTVs
    /// @return List of asset collaterals
    /// @dev Returned assets could have the ltv disabled (set to zero)
    function LTVList() external view returns (address[] memory);

    /// @notice Retrieves the maximum liquidation discount
    /// @return The maximum liquidation discount in 1e4 scale
    /// @dev The default value, which is zero, is deliberately bad, as it means there would be no incentive to liquidate
    /// unhealthy users. The vault creator must take care to properly select the limit, given the underlying and
    /// collaterals used.
    function maxLiquidationDiscount() external view returns (uint16);

    /// @notice Retrieves liquidation cool-off time, which must elapse after successful account status check before
    /// account can be liquidated
    /// @return The liquidation cool off time in seconds
    function liquidationCoolOffTime() external view returns (uint16);

    /// @notice Retrieves a hook target and a bitmask indicating which operations call the hook target
    /// @return hookTarget Address of the hook target contract
    /// @return hookedOps Bitmask with operations that should call the hooks. See Constants.sol for a list of operations
    function hookConfig() external view returns (address hookTarget, uint32 hookedOps);

    /// @notice Retrieves a bitmask indicating enabled config flags
    /// @return Bitmask with config flags enabled
    function configFlags() external view returns (uint32);

    /// @notice Address of EthereumVaultConnector contract
    /// @return The EVC address
    function EVC() external view returns (address);

    /// @notice Retrieves a reference asset used for liquidity calculations
    /// @return The address of the reference asset
    function unitOfAccount() external view returns (address);

    /// @notice Retrieves the address of the oracle contract
    /// @return The address of the oracle
    function oracle() external view returns (address);

    /// @notice Retrieves the Permit2 contract address
    /// @return The address of the Permit2 contract
    function permit2Address() external view returns (address);

    /// @notice Splits accrued fees balance according to protocol fee share and transfers shares to the governor fee
    /// receiver and protocol fee receiver
    function convertFees() external;

    /// @notice Set a new governor address
    /// @param newGovernorAdmin The new governor address
    /// @dev Set to zero address to renounce privileges and make the vault non-governed
    function setGovernorAdmin(address newGovernorAdmin) external;

    /// @notice Set a new governor fee receiver address
    /// @param newFeeReceiver The new fee receiver address
    function setFeeReceiver(address newFeeReceiver) external;

    /// @notice Set a new LTV config
    /// @param collateral Address of collateral to set LTV for
    /// @param borrowLTV New borrow LTV, for assessing account's health during account status checks, in 1e4 scale
    /// @param liquidationLTV New liquidation LTV after ramp ends in 1e4 scale
    /// @param rampDuration Ramp duration in seconds
    function setLTV(address collateral, uint16 borrowLTV, uint16 liquidationLTV, uint32 rampDuration) external;

    /// @notice Set a new maximum liquidation discount
    /// @param newDiscount New maximum liquidation discount in 1e4 scale
    /// @dev If the discount is zero (the default), the liquidators will not be incentivized to liquidate unhealthy
    /// accounts
    function setMaxLiquidationDiscount(uint16 newDiscount) external;

    /// @notice Set a new liquidation cool off time, which must elapse after successful account status check before
    /// account can be liquidated
    /// @param newCoolOffTime The new liquidation cool off time in seconds
    /// @dev Setting cool off time to zero allows liquidating the account in the same block as the last successful
    /// account status check
    function setLiquidationCoolOffTime(uint16 newCoolOffTime) external;

    /// @notice Set a new interest rate model contract
    /// @param newModel The new IRM address
    /// @dev If the new model reverts, perhaps due to governor error, the vault will silently use a zero interest
    /// rate. Governor should make sure the new interest rates are computed as expected.
    function setInterestRateModel(address newModel) external;

    /// @notice Set a new hook target and a new bitmap indicating which operations should call the hook target.
    /// Operations are defined in Constants.sol.
    /// @param newHookTarget The new hook target address. Use address(0) to simply disable hooked operations
    /// @param newHookedOps Bitmask with the new hooked operations
    /// @dev All operations are initially disabled in a newly created vault. The vault creator must set their
    /// own configuration to make the vault usable
    function setHookConfig(address newHookTarget, uint32 newHookedOps) external;

    /// @notice Set new bitmap indicating which config flags should be enabled. Flags are defined in Constants.sol
    /// @param newConfigFlags Bitmask with the new config flags
    function setConfigFlags(uint32 newConfigFlags) external;

    /// @notice Set new supply and borrow caps in AmountCap format
    /// @param supplyCap The new supply cap in AmountCap fromat
    /// @param borrowCap The new borrow cap in AmountCap fromat
    function setCaps(uint16 supplyCap, uint16 borrowCap) external;

    /// @notice Set a new interest fee
    /// @param newFee The new interest fee
    function setInterestFee(uint16 newFee) external;
}

/// @title IEVault
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Interface of the EVault, an EVC enabled lending vault
interface IEVault is
    IInitialize,
    IToken,
    IVault,
    IBorrowing,
    ILiquidation,
    IRiskManager,
    IBalanceForwarder,
    IGovernance
{
    /// @notice Fetch address of the `Initialize` module
    function MODULE_INITIALIZE() external view returns (address);
    /// @notice Fetch address of the `Token` module
    function MODULE_TOKEN() external view returns (address);
    /// @notice Fetch address of the `Vault` module
    function MODULE_VAULT() external view returns (address);
    /// @notice Fetch address of the `Borrowing` module
    function MODULE_BORROWING() external view returns (address);
    /// @notice Fetch address of the `Liquidation` module
    function MODULE_LIQUIDATION() external view returns (address);
    /// @notice Fetch address of the `RiskManager` module
    function MODULE_RISKMANAGER() external view returns (address);
    /// @notice Fetch address of the `BalanceForwarder` module
    function MODULE_BALANCE_FORWARDER() external view returns (address);
    /// @notice Fetch address of the `Governance` module
    function MODULE_GOVERNANCE() external view returns (address);
}
"
    },
    "lib/euler-vault-kit/src/InterestRateModels/IRMLinearKink.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./IIRM.sol";

/// @title IRMLinearKink
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Implementation of an interest rate model, where interest rate grows linearly with utilization, and spikes
/// after reaching kink
contract IRMLinearKink is IIRM {
    /// @notice Base interest rate applied when utilization is equal zero
    uint256 public immutable baseRate;
    /// @notice Slope of the function before the kink
    uint256 public immutable slope1;
    /// @notice Slope of the function after the kink
    uint256 public immutable slope2;
    /// @notice Utilization at which the slope of the interest rate function changes. In type(uint32).max scale.
    uint256 public immutable kink;

    constructor(uint256 baseRate_, uint256 slope1_, uint256 slope2_, uint32 kink_) {
        baseRate = baseRate_;
        slope1 = slope1_;
        slope2 = slope2_;
        kink = kink_;
    }

    /// @inheritdoc IIRM
    function computeInterestRate(address vault, uint256 cash, uint256 borrows)
        external
        view
        override
        returns (uint256)
    {
        if (msg.sender != vault) revert E_IRMUpdateUnauthorized();

        return computeInterestRateInternal(vault, cash, borrows);
    }

    /// @inheritdoc IIRM
    function computeInterestRateView(address vault, uint256 cash, uint256 borrows)
        external
        view
        override
        returns (uint256)
    {
        return computeInterestRateInternal(vault, cash, borrows);
    }

    function computeInterestRateInternal(address, uint256 cash, uint256 borrows) internal view returns (uint256) {
        uint256 totalAssets = cash + borrows;

        uint32 utilization = totalAssets == 0
            ? 0 // empty pool arbitrarily given utilization of 0
            : uint32(borrows * type(uint32).max / totalAssets);

        uint256 ir = baseRate;

        if (utilization <= kink) {
            ir += utilization * slope1;
        } else {
            ir += kink * slope1;

            uint256 utilizationOverKink;
            unchecked {
                utilizationOverKink = utilization - kink;
            }
            ir += slope2 * utilizationOverKink;
        }

        return ir;
    }
}
"
    },
    "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")) {
            (bool success, bytes memory result) =
                IOracle(oracleAddress).feed().staticcall(abi.encodeCall(IOracle.description, ()));
            string memory feedDescription = success && result.length >= 32 ? abi.decode(result, (string)) : "";

            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")) {
            (bool success, bytes memory result) =
                IOracle(oracleAddress).feed().staticcall(abi.encodeCall(IOracle.description, ()));
            string memory feedDescription = success && result.length >= 32 ? abi.decode(result, (string)) : "";

            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 oracleAddr

Tags:
ERC20, Multisig, Mintable, Burnable, Swap, Liquidity, Staking, Yield, Voting, Timelock, Upgradeable, Multi-Signature, Factory, Oracle|addr:0xc3c45633e45041bf3be841f89d2cb51e2f657403|verified:true|block:23690342|tx:0xca8a0aaf0ed61dc485507cc2642067ea371a5b300720e6ff6d4cbe482f870daf|first_check:1761831649

Submitted on: 2025-10-30 14:40:52

Comments

Log in to comment.

No comments yet.