EulerEarnVaultLens

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/EulerEarnVaultLens.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {
    IEulerEarn, IERC4626, MarketConfig, PendingUint136, PendingAddress
} from "euler-earn/interfaces/IEulerEarn.sol";
import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol";
import {UtilsLens} from "./UtilsLens.sol";
import {Utils} from "./Utils.sol";
import "./LensTypes.sol";

contract EulerEarnVaultLens is Utils {
    UtilsLens public immutable utilsLens;

    constructor(address _utilsLens) {
        utilsLens = UtilsLens(_utilsLens);
    }

    function getVaultInfoFull(address vault) public view returns (EulerEarnVaultInfoFull memory) {
        EulerEarnVaultInfoFull memory result;

        result.timestamp = block.timestamp;

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

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

        result.totalShares = IEulerEarn(vault).totalSupply();
        result.totalAssets = IEulerEarn(vault).totalAssets();
        result.lostAssets = IEulerEarn(vault).lostAssets();

        if (result.lostAssets > 0) {
            uint256 coveredLostAssets = IEulerEarn(vault).convertToAssets(IEulerEarn(vault).balanceOf(address(1)));
            result.lostAssets = result.lostAssets > coveredLostAssets ? result.lostAssets - coveredLostAssets : 0;
        }

        result.timelock = IEulerEarn(vault).timelock();
        result.performanceFee = IEulerEarn(vault).fee();
        result.feeReceiver = IEulerEarn(vault).feeRecipient();
        result.owner = IEulerEarn(vault).owner();
        result.creator = IEulerEarn(vault).creator();
        result.curator = IEulerEarn(vault).curator();
        result.guardian = IEulerEarn(vault).guardian();
        result.evc = EVCUtil(vault).EVC();
        result.permit2 = IEulerEarn(vault).permit2Address();

        PendingUint136 memory pendingTimelock = IEulerEarn(vault).pendingTimelock();
        PendingAddress memory pendingGuardian = IEulerEarn(vault).pendingGuardian();

        result.pendingTimelock = pendingTimelock.value;
        result.pendingTimelockValidAt = pendingTimelock.validAt;
        result.pendingGuardian = pendingGuardian.value;
        result.pendingGuardianValidAt = pendingGuardian.validAt;

        result.supplyQueue = new address[](IEulerEarn(vault).supplyQueueLength());
        for (uint256 i; i < result.supplyQueue.length; ++i) {
            result.supplyQueue[i] = address(IEulerEarn(vault).supplyQueue(i));
        }

        result.strategies = new EulerEarnVaultStrategyInfo[](IEulerEarn(vault).withdrawQueueLength());

        for (uint256 i; i < result.strategies.length; ++i) {
            result.strategies[i] = getStrategyInfo(vault, address(IEulerEarn(vault).withdrawQueue(i)));
            result.availableAssets += result.strategies[i].availableAssets;
        }

        return result;
    }

    function getStrategiesInfo(address vault, address[] calldata strategies)
        public
        view
        returns (EulerEarnVaultStrategyInfo[] memory)
    {
        EulerEarnVaultStrategyInfo[] memory result = new EulerEarnVaultStrategyInfo[](strategies.length);

        for (uint256 i; i < strategies.length; ++i) {
            result[i] = getStrategyInfo(vault, strategies[i]);
        }

        return result;
    }

    function getStrategyInfo(address _vault, address _strategy)
        public
        view
        returns (EulerEarnVaultStrategyInfo memory)
    {
        IEulerEarn vault = IEulerEarn(_vault);
        IERC4626 strategy = IERC4626(_strategy);
        MarketConfig memory config = vault.config(strategy);
        PendingUint136 memory pendingConfig = vault.pendingCap(strategy);

        return EulerEarnVaultStrategyInfo({
            strategy: _strategy,
            allocatedAssets: vault.expectedSupplyAssets(strategy),
            availableAssets: vault.maxWithdrawFromStrategy(strategy),
            currentAllocationCap: config.cap,
            pendingAllocationCap: pendingConfig.value,
            pendingAllocationCapValidAt: pendingConfig.validAt,
            removableAt: config.removableAt,
            info: utilsLens.getVaultInfoERC4626(_strategy)
        });
    }
}
"
    },
    "lib/euler-earn/src/interfaces/IEulerEarn.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IEulerEarnFactory} from "./IEulerEarnFactory.sol";

import {IERC4626} from "openzeppelin-contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "openzeppelin-contracts/token/ERC20/extensions/IERC20Permit.sol";

import {MarketConfig, PendingUint136, PendingAddress} from "../libraries/PendingLib.sol";

struct MarketAllocation {
    /// @notice The vault to allocate.
    IERC4626 id;
    /// @notice The amount of assets to allocate.
    uint256 assets;
}

interface IOwnable {
    function owner() external view returns (address);
    function transferOwnership(address) external;
    function renounceOwnership() external;
    function acceptOwnership() external;
    function pendingOwner() external view returns (address);
}

/// @dev This interface is used for factorizing IEulerEarnStaticTyping and IEulerEarn.
/// @dev Consider using the IEulerEarn interface instead of this one.
interface IEulerEarnBase {
    /// @notice The address of the Permit2 contract.
    function permit2Address() external view returns (address);

    /// @notice The address of the creator.
    function creator() external view returns (address);

    /// @notice The address of the curator.
    function curator() external view returns (address);

    /// @notice Stores whether an address is an allocator or not.
    function isAllocator(address target) external view returns (bool);

    /// @notice The current guardian. Can be set even without the timelock set.
    function guardian() external view returns (address);

    /// @notice The current fee.
    function fee() external view returns (uint96);

    /// @notice The fee recipient.
    function feeRecipient() external view returns (address);

    /// @notice The current timelock.
    function timelock() external view returns (uint256);

    /// @dev Stores the order of vaults in which liquidity is supplied upon deposit.
    /// @dev Can contain any vault. A vault is skipped as soon as its supply cap is reached.
    function supplyQueue(uint256) external view returns (IERC4626);

    /// @notice Returns the length of the supply queue.
    function supplyQueueLength() external view returns (uint256);

    /// @dev Stores the order of vault from which liquidity is withdrawn upon withdrawal.
    /// @dev Always contain all non-zero cap vault as well as all vault on which the Earn vault supplies liquidity,
    /// without duplicate.
    function withdrawQueue(uint256) external view returns (IERC4626);

    /// @notice Returns the length of the withdraw queue.
    function withdrawQueueLength() external view returns (uint256);

    /// @notice Returns the amount of assets that can be withdrawn from given strategy vault.
    /// @dev Accounts for internally tracked balance, ignoring direct shares transfer and for assets available in the strategy.
    function maxWithdrawFromStrategy(IERC4626 id) external view returns (uint256);

    /// @notice Returns the amount of assets expected to be supplied to the strategy vault.
    /// @dev Accounts for internally tracked balance, ignoring direct shares transfer.
    function expectedSupplyAssets(IERC4626 id) external view returns (uint256);

    /// @notice Stores the total assets managed by this vault when the fee was last accrued.
    function lastTotalAssets() external view returns (uint256);

    /// @notice Stores the missing assets due to realized bad debt or forced vault removal.
    /// @dev In order to cover those lost assets, it is advised to supply on behalf of address(1) on the vault
    /// (canonical method).
    function lostAssets() external view returns (uint256);

    /// @notice Submits a `newTimelock`.
    /// @dev Warning: Reverts if a timelock is already pending. Revoke the pending timelock to overwrite it.
    /// @dev In case the new timelock is higher than the current one, the timelock is set immediately.
    function submitTimelock(uint256 newTimelock) external;

    /// @notice Accepts the pending timelock.
    function acceptTimelock() external;

    /// @notice Revokes the pending timelock.
    /// @dev Does not revert if there is no pending timelock.
    function revokePendingTimelock() external;

    /// @notice Submits a `newSupplyCap` for the vault.
    /// @dev Warning: Reverts if a cap is already pending. Revoke the pending cap to overwrite it.
    /// @dev Warning: Reverts if a vault removal is pending.
    /// @dev In case the new cap is lower than the current one, the cap is set immediately.
    /// @dev For the sake of backwards compatibility, the max allowed cap can either be set to type(uint184).max or type(uint136).max.
    function submitCap(IERC4626 id, uint256 newSupplyCap) external;

    /// @notice Accepts the pending cap of the vault.
    function acceptCap(IERC4626 id) external;

    /// @notice Revokes the pending cap of the vault.
    /// @dev Does not revert if there is no pending cap.
    function revokePendingCap(IERC4626 id) external;

    /// @notice Submits a forced vault removal from the Earn vault, eventually losing all funds supplied to the vault.
    /// @notice This forced removal is expected to be used as an emergency process in case a vault constantly reverts.
    /// To softly remove a sane vault, the curator role is expected to bundle a reallocation that empties the vault
    /// first (using `reallocate`), followed by the removal of the vault (using `updateWithdrawQueue`).
    /// @dev Warning: Reverts for non-zero cap or if there is a pending cap. Successfully submitting a zero cap will
    /// prevent such reverts.
    function submitMarketRemoval(IERC4626 id) external;

    /// @notice Revokes the pending removal of the vault.
    /// @dev Does not revert if there is no pending vault removal.
    function revokePendingMarketRemoval(IERC4626 id) external;

    /// @notice Sets the name of the Earn vault.
    function setName(string memory newName) external;

    /// @notice Sets the symbol of the Earn vault.
    function setSymbol(string memory newSymbol) external;

    /// @notice Submits a `newGuardian`.
    /// @notice Warning: a malicious guardian could disrupt the Earn vault's operation, and would have the power to revoke
    /// any pending guardian.
    /// @dev In case there is no guardian, the guardian is set immediately.
    /// @dev Warning: Submitting a guardian will overwrite the current pending guardian.
    function submitGuardian(address newGuardian) external;

    /// @notice Accepts the pending guardian.
    function acceptGuardian() external;

    /// @notice Revokes the pending guardian.
    function revokePendingGuardian() external;

    /// @notice Sets `newAllocator` as an allocator or not (`newIsAllocator`).
    function setIsAllocator(address newAllocator, bool newIsAllocator) external;

    /// @notice Sets `curator` to `newCurator`.
    function setCurator(address newCurator) external;

    /// @notice Sets the `fee` to `newFee`.
    function setFee(uint256 newFee) external;

    /// @notice Sets `feeRecipient` to `newFeeRecipient`.
    function setFeeRecipient(address newFeeRecipient) external;

    /// @notice Sets `supplyQueue` to `newSupplyQueue`.
    /// @param newSupplyQueue is an array of enabled vaults, and can contain duplicate vaults, but it would only
    /// increase the cost of depositing to the vault.
    function setSupplyQueue(IERC4626[] calldata newSupplyQueue) external;

    /// @notice Updates the withdraw queue. Some vaults can be removed, but no vault can be added.
    /// @notice Removing a vault requires the vault to have 0 supply on it, or to have previously submitted a removal
    /// for this vault (with the function `submitMarketRemoval`).
    /// @notice Warning: Anyone can supply on behalf of the vault so the call to `updateWithdrawQueue` that expects a
    /// vault to be empty can be griefed by a front-run. To circumvent this, the allocator can simply bundle a
    /// reallocation that withdraws max from this vault with a call to `updateWithdrawQueue`.
    /// @dev Warning: Removing a vault with supply will decrease the fee accrued until one of the functions updating
    /// `lastTotalAssets` is triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
    /// @dev Warning: `updateWithdrawQueue` is not idempotent. Submitting twice the same tx will change the queue twice.
    /// @param indexes The indexes of each vault in the previous withdraw queue, in the new withdraw queue's order.
    function updateWithdrawQueue(uint256[] calldata indexes) external;

    /// @notice Reallocates the vault's liquidity so as to reach a given allocation of assets on each given vault.
    /// @dev The behavior of the reallocation can be altered by state changes, including:
    /// - Deposits on the Earn vault that supplies to vaults that are expected to be supplied to during reallocation.
    /// - Withdrawals from the Earn vault that withdraws from vaults that are expected to be withdrawn from during
    /// reallocation.
    /// - Donations to the vault on vaults that are expected to be supplied to during reallocation.
    /// - Withdrawals from vaults that are expected to be withdrawn from during reallocation.
    /// @dev Sender is expected to pass `assets = type(uint256).max` with the last MarketAllocation of `allocations` to
    /// supply all the remaining withdrawn liquidity, which would ensure that `totalWithdrawn` = `totalSupplied`.
    /// @dev A supply in a reallocation step will make the reallocation revert if the amount is greater than the net
    /// amount from previous steps (i.e. total withdrawn minus total supplied).
    function reallocate(MarketAllocation[] calldata allocations) external;
}

/// @dev This interface is inherited by IEulerEarn so that function signatures are checked by the compiler.
/// @dev Consider using the IEulerEarn interface instead of this one.
interface IEulerEarnStaticTyping is IEulerEarnBase {
    /// @notice Returns the current configuration of each vault.
    function config(IERC4626) external view returns (uint112 balance, uint136 cap, bool enabled, uint64 removableAt);

    /// @notice Returns the pending guardian.
    function pendingGuardian() external view returns (address guardian, uint64 validAt);

    /// @notice Returns the pending cap for each vault.
    function pendingCap(IERC4626) external view returns (uint136 value, uint64 validAt);

    /// @notice Returns the pending timelock.
    function pendingTimelock() external view returns (uint136 value, uint64 validAt);
}

/// @title IEulerEarn
/// @author Forked with gratitude from Morpho Labs. Inspired by Silo Labs.
/// @custom:contact security@morpho.org
/// @custom:contact security@euler.xyz
/// @dev Use this interface for IEulerEarn to have access to all the functions with the appropriate function
/// signatures.
interface IEulerEarn is IEulerEarnBase, IERC4626, IERC20Permit, IOwnable {
    /// @notice Returns the address of the Ethereum Vault Connector (EVC) used by this contract.
    function EVC() external view returns (address);

    /// @notice Returns the current configuration of each vault.
    function config(IERC4626) external view returns (MarketConfig memory);

    /// @notice Returns the pending guardian.
    function pendingGuardian() external view returns (PendingAddress memory);

    /// @notice Returns the pending cap for each vault.
    function pendingCap(IERC4626) external view returns (PendingUint136 memory);

    /// @notice Returns the pending timelock.
    function pendingTimelock() external view returns (PendingUint136 memory);
}
"
    },
    "lib/ethereum-vault-connector/src/utils/EVCUtil.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {IEVC} from "../interfaces/IEthereumVaultConnector.sol";
import {ExecutionContext, EC} from "../ExecutionContext.sol";

/// @title EVCUtil
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice This contract is an abstract base contract for interacting with the Ethereum Vault Connector (EVC).
/// It provides utility functions for authenticating the callers in the context of the EVC, a pattern for enforcing the
/// contracts to be called through the EVC.
abstract contract EVCUtil {
    using ExecutionContext for EC;

    uint160 internal constant ACCOUNT_ID_OFFSET = 8;
    IEVC internal immutable evc;

    error EVC_InvalidAddress();
    error NotAuthorized();
    error ControllerDisabled();

    constructor(address _evc) {
        if (_evc == address(0)) revert EVC_InvalidAddress();

        evc = IEVC(_evc);
    }

    /// @notice Returns the address of the Ethereum Vault Connector (EVC) used by this contract.
    /// @return The address of the EVC contract.
    function EVC() external view virtual returns (address) {
        return address(evc);
    }

    /// @notice Ensures that the msg.sender is the EVC by using the EVC callback functionality if necessary.
    /// @dev Optional to use for functions requiring account and vault status checks to enforce predictable behavior.
    /// @dev If this modifier used in conjuction with any other modifier, it must appear as the first (outermost)
    /// modifier of the function.
    modifier callThroughEVC() virtual {
        _callThroughEVC();
        _;
    }

    /// @notice Ensures that the caller is the EVC in the appropriate context.
    /// @dev Should be used for checkAccountStatus and checkVaultStatus functions.
    modifier onlyEVCWithChecksInProgress() virtual {
        _onlyEVCWithChecksInProgress();
        _;
    }

    /// @notice Ensures a standard authentication path on the EVC allowing the account owner or any of its EVC accounts.
    /// @dev This modifier checks if the caller is the EVC and if so, verifies the execution context.
    /// It reverts if the operator is authenticated, control collateral is in progress, or checks are in progress.
    /// @dev This modifier must not be used on functions utilized by liquidation flows, i.e. transfer or withdraw.
    /// @dev This modifier must not be used on checkAccountStatus and checkVaultStatus functions.
    /// @dev This modifier can be used on access controlled functions to prevent non-standard authentication paths on
    /// the EVC.
    modifier onlyEVCAccount() virtual {
        _authenticateCallerWithStandardContextState(false);
        _;
    }

    /// @notice Ensures a standard authentication path on the EVC.
    /// @dev This modifier checks if the caller is the EVC and if so, verifies the execution context.
    /// It reverts if the operator is authenticated, control collateral is in progress, or checks are in progress.
    /// It reverts if the authenticated account owner is known and it is not the account owner.
    /// @dev It assumes that if the caller is not the EVC, the caller is the account owner.
    /// @dev This modifier must not be used on functions utilized by liquidation flows, i.e. transfer or withdraw.
    /// @dev This modifier must not be used on checkAccountStatus and checkVaultStatus functions.
    /// @dev This modifier can be used on access controlled functions to prevent non-standard authentication paths on
    /// the EVC.
    modifier onlyEVCAccountOwner() virtual {
        _authenticateCallerWithStandardContextState(true);
        _;
    }

    /// @notice Checks whether the specified account and the other account have the same owner.
    /// @dev The function is used to check whether one account is authorized to perform operations on behalf of the
    /// other. Accounts are considered to have a common owner if they share the first 19 bytes of their address.
    /// @param account The address of the account that is being checked.
    /// @param otherAccount The address of the other account that is being checked.
    /// @return A boolean flag that indicates whether the accounts have the same owner.
    function _haveCommonOwner(address account, address otherAccount) internal pure returns (bool) {
        bool result;
        assembly {
            result := lt(xor(account, otherAccount), 0x100)
        }
        return result;
    }

    /// @notice Returns the address prefix of the specified account.
    /// @dev The address prefix is the first 19 bytes of the account address.
    /// @param account The address of the account whose address prefix is being retrieved.
    /// @return A bytes19 value that represents the address prefix of the account.
    function _getAddressPrefix(address account) internal pure returns (bytes19) {
        return bytes19(uint152(uint160(account) >> ACCOUNT_ID_OFFSET));
    }

    /// @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 virtual returns (address) {
        address sender = msg.sender;

        if (sender == address(evc)) {
            (sender,) = evc.getCurrentOnBehalfOfAccount(address(0));
        }

        return sender;
    }

    /// @notice Retrieves the message sender in the context of the EVC for a borrow operation.
    /// @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. This function reverts if this contract is not enabled
    /// as a controller for the account on behalf of which the operation is being executed.
    /// @return The address of the message sender.
    function _msgSenderForBorrow() internal view virtual returns (address) {
        address sender = msg.sender;
        bool controllerEnabled;

        if (sender == address(evc)) {
            (sender, controllerEnabled) = evc.getCurrentOnBehalfOfAccount(address(this));
        } else {
            controllerEnabled = evc.isControllerEnabled(sender, address(this));
        }

        if (!controllerEnabled) {
            revert ControllerDisabled();
        }

        return sender;
    }

    /// @notice Retrieves the message sender, ensuring it's any EVC account meaning that the execution context is in a
    /// standard state (not operator authenticated, not control collateral in progress, not checks in progress).
    /// @dev This function must not be used on functions utilized by liquidation flows, i.e. transfer or withdraw.
    /// @dev This function must not be used on checkAccountStatus and checkVaultStatus functions.
    /// @dev This function can be used on access controlled functions to prevent non-standard authentication paths on
    /// the EVC.
    /// @return The address of the message sender.
    function _msgSenderOnlyEVCAccount() internal view returns (address) {
        return _authenticateCallerWithStandardContextState(false);
    }

    /// @notice Retrieves the message sender, ensuring it's the EVC account owner and that the execution context is in a
    /// standard state (not operator authenticated, not control collateral in progress, not checks in progress).
    /// @dev It assumes that if the caller is not the EVC, the caller is the account owner.
    /// @dev This function must not be used on functions utilized by liquidation flows, i.e. transfer or withdraw.
    /// @dev This function must not be used on checkAccountStatus and checkVaultStatus functions.
    /// @dev This function can be used on access controlled functions to prevent non-standard authentication paths on
    /// the EVC.
    /// @return The address of the message sender.
    function _msgSenderOnlyEVCAccountOwner() internal view returns (address) {
        return _authenticateCallerWithStandardContextState(true);
    }

    /// @notice Calls the current external function through the EVC.
    /// @dev This function is used to route the current call through the EVC if it's not already coming from the EVC. It
    /// makes the EVC set the execution context and call back this contract with unchanged calldata. msg.sender is used
    /// as the onBehalfOfAccount.
    /// @dev This function shall only be used by the callThroughEVC modifier.
    function _callThroughEVC() internal {
        address _evc = address(evc);
        if (msg.sender == _evc) return;

        assembly {
            mstore(0, 0x1f8b521500000000000000000000000000000000000000000000000000000000) // EVC.call selector
            mstore(4, address()) // EVC.call 1st argument - address(this)
            mstore(36, caller()) // EVC.call 2nd argument - msg.sender
            mstore(68, callvalue()) // EVC.call 3rd argument - msg.value
            mstore(100, 128) // EVC.call 4th argument - msg.data, offset to the start of encoding - 128 bytes
            mstore(132, calldatasize()) // msg.data length
            calldatacopy(164, 0, calldatasize()) // original calldata

            // abi encoded bytes array should be zero padded so its length is a multiple of 32
            // store zero word after msg.data bytes and round up calldatasize to nearest multiple of 32
            mstore(add(164, calldatasize()), 0)
            let result := call(gas(), _evc, callvalue(), 0, add(164, and(add(calldatasize(), 31), not(31))), 0, 0)

            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(64, sub(returndatasize(), 64)) } // strip bytes encoding from call return
        }
    }

    /// @notice Ensures that the function is called only by the EVC during the checks phase
    /// @dev Reverts if the caller is not the EVC or if checks are not in progress.
    function _onlyEVCWithChecksInProgress() internal view {
        if (msg.sender != address(evc) || !evc.areChecksInProgress()) {
            revert NotAuthorized();
        }
    }

    /// @notice Ensures that the function is called only by the EVC account owner or any of its EVC accounts
    /// @dev This function checks if the caller is the EVC and if so, verifies that the execution context is not in a
    /// special state (operator authenticated, collateral control in progress, or checks in progress). If
    /// onlyAccountOwner is true and the owner was already registered on the EVC, it verifies that the onBehalfOfAccount
    /// is the owner. If onlyAccountOwner is false, it allows any EVC account of the owner to call the function.
    /// @param onlyAccountOwner If true, only allows the account owner; if false, allows any EVC account of the owner
    /// @return The address of the message sender.
    function _authenticateCallerWithStandardContextState(bool onlyAccountOwner) internal view returns (address) {
        if (msg.sender == address(evc)) {
            EC ec = EC.wrap(evc.getRawExecutionContext());

            if (ec.isOperatorAuthenticated() || ec.isControlCollateralInProgress() || ec.areChecksInProgress()) {
                revert NotAuthorized();
            }

            address onBehalfOfAccount = ec.getOnBehalfOfAccount();

            if (onlyAccountOwner) {
                address owner = evc.getAccountOwner(onBehalfOfAccount);

                if (owner != address(0) && owner != onBehalfOfAccount) {
                    revert NotAuthorized();
                }
            }

            return onBehalfOfAccount;
        }

        return msg.sender;
    }
}
"
    },
    "src/Lens/UtilsLens.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol";
import {IEVault} from "evk/EVault/IEVault.sol";
import {IPriceOracle} from "euler-price-oracle/interfaces/IPriceOracle.sol";
import {OracleLens} from "./OracleLens.sol";
import {Utils} from "./Utils.sol";
import "./LensTypes.sol";

contract UtilsLens is Utils {
    GenericFactory public immutable eVaultFactory;
    OracleLens public immutable oracleLens;

    constructor(address _eVaultFactory, address _oracleLens) {
        eVaultFactory = GenericFactory(_eVaultFactory);
        oracleLens = OracleLens(_oracleLens);
    }

    function getVaultInfoERC4626(address vault) public view returns (VaultInfoERC4626 memory) {
        VaultInfoERC4626 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.totalShares = IEVault(vault).totalSupply();
        result.totalAssets = IEVault(vault).totalAssets();

        result.isEVault = eVaultFactory.isProxy(vault);

        return result;
    }

    function getAPYs(address vault) external view returns (uint256 borrowAPY, uint256 supplyAPY) {
        return _computeAPYs(
            IEVault(vault).interestRate(),
            IEVault(vault).cash(),
            IEVault(vault).totalBorrows(),
            IEVault(vault).interestFee()
        );
    }

    function computeAPYs(uint256 borrowSPY, uint256 cash, uint256 borrows, uint256 interestFee)
        external
        pure
        returns (uint256 borrowAPY, uint256 supplyAPY)
    {
        return _computeAPYs(borrowSPY, cash, borrows, interestFee);
    }

    function calculateTimeToLiquidation(
        address liabilityVault,
        uint256 liabilityValue,
        address[] memory collaterals,
        uint256[] memory collateralValues
    ) external view returns (int256) {
        return _calculateTimeToLiquidation(liabilityVault, liabilityValue, collaterals, collateralValues);
    }

    function getControllerAssetPriceInfo(address controller, address asset)
        public
        view
        returns (AssetPriceInfo memory)
    {
        AssetPriceInfo memory result;

        result.timestamp = block.timestamp;

        result.oracle = IEVault(controller).oracle();
        result.asset = asset;
        result.unitOfAccount = IEVault(controller).unitOfAccount();

        result.amountIn = 10 ** _getDecimals(asset);

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

        (bool success, bytes memory data) = result.oracle.staticcall(
            abi.encodeCall(IPriceOracle.getQuote, (result.amountIn, asset, result.unitOfAccount))
        );

        if (success && data.length >= 32) {
            result.amountOutMid = abi.decode(data, (uint256));
        } else {
            result.queryFailure = true;
            result.queryFailureReason = data;
        }

        (success, data) = result.oracle.staticcall(
            abi.encodeCall(IPriceOracle.getQuotes, (result.amountIn, asset, result.unitOfAccount))
        );

        if (success && data.length >= 64) {
            (result.amountOutBid, result.amountOutAsk) = abi.decode(data, (uint256, uint256));
        } else {
            result.queryFailure = true;
        }

        return result;
    }

    function getAssetPriceInfo(address asset, address unitOfAccount) public view returns (AssetPriceInfo memory) {
        AssetPriceInfo memory result;

        result.timestamp = block.timestamp;

        result.asset = asset;
        result.unitOfAccount = unitOfAccount;

        result.amountIn = 10 ** _getDecimals(asset);

        address[] memory adapters = oracleLens.getValidAdapters(asset, unitOfAccount);
        uint256 amountIn = result.amountIn;

        if (adapters.length == 0) {
            (bool success, bytes memory data) =
                asset.staticcall{gas: 100000}(abi.encodeCall(IEVault(asset).convertToAssets, (amountIn)));

            if (success && data.length >= 32) {
                amountIn = abi.decode(data, (uint256));
                (success, data) = asset.staticcall(abi.encodeCall(IEVault(asset).asset, ()));

                if (success && data.length >= 32) {
                    asset = abi.decode(data, (address));
                    adapters = oracleLens.getValidAdapters(asset, unitOfAccount);
                }
            }
        }

        if (adapters.length == 0) {
            result.queryFailure = true;
            return result;
        }

        for (uint256 i = 0; i < adapters.length; ++i) {
            result.oracle = adapters[i];
            result.queryFailure = false;
            result.queryFailureReason = "";

            (bool success, bytes memory data) =
                result.oracle.staticcall(abi.encodeCall(IPriceOracle.getQuote, (amountIn, asset, unitOfAccount)));

            if (success && data.length >= 32) {
                result.amountOutMid = abi.decode(data, (uint256));
            } else {
                result.queryFailure = true;
                result.queryFailureReason = data;
            }

            (success, data) =
                result.oracle.staticcall(abi.encodeCall(IPriceOracle.getQuotes, (amountIn, asset, unitOfAccount)));

            if (success && data.length >= 64) {
                (result.amountOutBid, result.amountOutAsk) = abi.decode(data, (uint256, uint256));
            } else {
                result.queryFailure = true;
            }

            if (!result.queryFailure) break;
        }

        return result;
    }

    function tokenBalances(address account, address[] calldata tokens) public view returns (uint256[] memory) {
        uint256[] memory balances = new uint256[](tokens.length);

        for (uint256 i = 0; i < tokens.length; ++i) {
            if (tokens[i] != address(0)) balances[i] = IEVault(tokens[i]).balanceOf(account);
            else balances[i] = account.balance;
        }

        return balances;
    }

    function tokenAllowances(address spender, address account, address[] calldata tokens)
        public
        view
        returns (uint256[] memory)
    {
        uint256[] memory allowances = new uint256[](tokens.length);

        for (uint256 i = 0; i < tokens.length; ++i) {
            allowances[i] = IEVault(tokens[i]).allowance(account, spender);
        }

        return allowances;
    }
}
"
    },
    "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 || block.chainid == 998
            ) {
                return address(0);
            }
            // hyperEVM
            if (block.chainid == 999) {
                return address(0);
            }

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

            // Plasma
            if (block.chainid == 9745) {
                return address(0);
            }

            // Monad
            if (block.chainid == 143) {
                return address(0);
            }

            // Sepolia
            if (block.chainid == 11155111) {
                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/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;
    address account;
    address vault;
    address unitOfAccount;
    int256 timeToLiquidation;
    uint256 liabilityValueBorrowing;
    uint256 liabilityValueLiquidation;
    uint256 collateralValueBorrowing;
    uint256 collateralValueLiquidation;
    uint256 collateralValueRaw;
    address[] collaterals;
    uint256[] collateralValuesBorrowing;
    uint256[] collateralValuesLiquidation;
    uint256[] collateralValuesRaw;
}

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 VaultInfoStatic {
    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;
    address dToken;
    address oracle;
    address evc;
    address protocolConfig;
    address balanceTracker;
    address permit2;
    address creator;
}

struct VaultInfoDynamic {
    uint256 timestamp;
    address vault;
    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 interestRateModel;
    address hookTarget;
    address governorAdmin;
    VaultInterestRateModelInfo irmInfo;
    LTVInfo[] collateralLTVInfo;
    AssetPriceInfo liabilityPriceInfo;
    AssetPriceInfo[] collateralPriceInfo;
    OracleDetailedInfo oracleInfo;
    AssetPriceInfo backupAssetPriceInfo;
    OracleDetailedInfo backupAssetOracleInfo;
}

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-earn/src/interfaces/IEulerEarnFactory.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IEulerEarn} from "./IEulerEarn.sol";

/// @title IEulerEarnFactory
/// @author Forked with gratitude from Morpho Labs. Inspired by Silo Labs.
/// @custom:contact security@morpho.org
/// @custom:contact security@euler.xyz
/// @notice Interface of EulerEarn's factory.
interface IEulerEarnFactory {
    /// @notice The address of the Permit2 contract.
    function permit2Address() external view returns (address);

    /// @notice The address of the supported perspective contract.
    function supportedPerspective() external view returns (address);

    /// @notice Whether a vault was created with the factory.
    function isVault(address target) external view returns (bool);

    /// @notice Fetch the length of the deployed proxies list
    /// @return The length of the proxy list array
    function getVaultListLength() external view returns (uint256);

    /// @notice Get a slice of the deployed proxies array
    /// @param start Start index of the slice
    /// @param end End index of the slice
    /// @return list An array containing the slice of the proxy list
    function getVaultListSlice(uint256 start, uint256 end) external view returns (address[] memory list);

    /// @notice Sets the perspective contract.
    /// @param _perspective The address of the new perspective contract.
    function setPerspective(address _perspective) external;

    /// @notice Whether a strategy is allowed to be used by the Earn vault.
    /// @dev Warning: Only allow trusted, correctly implemented ERC4626 strategies to be used by the Earn vault.
    /// @dev Warning: Allowed strategies must not be prone to the first-depositor attack.
    /// @dev Warning: To prevent exchange rate manipulation, it is recommended that the allowed strategies are not empty or have sufficient protection.
    function isStrategyAllowed(address id) external view returns (bool);

    /// @notice Creates a new EulerEarn vault.
    /// @param initialOwner The owner of the vault.
    /// @param initialTimelock The initial timelock of the vault.
    /// @param asset The address of the underlying asset.
    /// @param name The name of the vault.
    /// @param symbol The symbol of the vault.
    /// @param salt The salt to use for the EulerEarn vault's CREATE2 address.
    function createEulerEarn(
        address initialOwner,
        uint256 initialTimelock,
        address asset,
        string memory name,
        string memory symbol,
        bytes32 salt
    ) external returns (IEulerEarn eulerEarn);
}
"
    },
    "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
 */
interface IERC4626 is IERC20, IERC20Metadata {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maxim

Tags:
ERC20, Multisig, Mintable, Burnable, Swap, Liquidity, Yield, Voting, Timelock, Upgradeable, Multi-Signature, Factory, Oracle|addr:0xa09144beae23d8e7836aeb0fe17dd2647241a8be|verified:true|block:23690343|tx:0x91fb1c4a114f6ed13312278ca63813c4de360a3f7c0353ee88b08c4a8f4620ed|first_check:1761831661

Submitted on: 2025-10-30 14:41:04

Comments

Log in to comment.

No comments yet.