Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/Lens/OracleLens.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Utils} from "./Utils.sol";
import {SnapshotRegistry} from "../SnapshotRegistry/SnapshotRegistry.sol";
import {IPriceOracle} from "euler-price-oracle/interfaces/IPriceOracle.sol";
import {Errors} from "euler-price-oracle/lib/Errors.sol";
import "./LensTypes.sol";
interface IOracle is IPriceOracle {
function base() external view returns (address);
function quote() external view returns (address);
function cross() external view returns (address);
function oracleBaseCross() external view returns (address);
function oracleCrossQuote() external view returns (address);
function feed() external view returns (address);
function pyth() external view returns (address);
function WETH() external view returns (address);
function STETH() external view returns (address);
function WSTETH() external view returns (address);
function tokenA() external view returns (address);
function tokenB() external view returns (address);
function pool() external view returns (address);
function governor() external view returns (address);
function maxStaleness() external view returns (uint256);
function maxConfWidth() external view returns (uint256);
function twapWindow() external view returns (uint32);
function fee() external view returns (uint24);
function feedDecimals() external view returns (uint8);
function feedId() external view returns (bytes32);
function fallbackOracle() external view returns (address);
function resolvedVaults(address) external view returns (address);
function cache() external view returns (uint208, uint48);
function rate() external view returns (uint256);
function rateProvider() external view returns (address);
function rwaOracle() external view returns (address);
function resolveOracle(uint256 inAmount, address base, address quote)
external
view
returns (uint256, address, address, address);
function getConfiguredOracle(address base, address quote) external view returns (address);
function description() external view returns (string memory);
function pendleMarket() external view returns (address);
function safeguardPool() external view returns (address);
function poolId() external view returns (bytes32);
function priceOracleIndex() external view returns (uint256);
}
contract OracleLens is Utils {
SnapshotRegistry public immutable adapterRegistry;
constructor(address _adapterRegistry) {
adapterRegistry = SnapshotRegistry(_adapterRegistry);
}
function getOracleInfo(address oracleAddress, address[] memory bases, address[] memory quotes)
public
view
returns (OracleDetailedInfo memory)
{
string memory name;
bytes memory oracleInfo;
{
bool success;
bytes memory result;
if (oracleAddress != address(0)) {
(success, result) = oracleAddress.staticcall(abi.encodeCall(IPriceOracle.name, ()));
}
if (success && result.length >= 32) {
name = abi.decode(result, (string));
} else {
return OracleDetailedInfo({oracle: oracleAddress, name: "", oracleInfo: ""});
}
}
if (_strEq(name, "ChainlinkOracle")) {
string memory feedDescription;
try IOracle(IOracle(oracleAddress).feed()).description() returns (string memory desc) {
feedDescription = desc;
} catch {
// feedDescription remains empty
}
oracleInfo = abi.encode(
ChainlinkOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
feed: IOracle(oracleAddress).feed(),
feedDescription: feedDescription,
maxStaleness: IOracle(oracleAddress).maxStaleness()
})
);
} else if (_strEq(name, "ChainlinkInfrequentOracle")) {
string memory feedDescription;
try IOracle(IOracle(oracleAddress).feed()).description() returns (string memory desc) {
feedDescription = desc;
} catch {
// feedDescription remains empty
}
oracleInfo = abi.encode(
ChainlinkInfrequentOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
feed: IOracle(oracleAddress).feed(),
feedDescription: feedDescription,
maxStaleness: IOracle(oracleAddress).maxStaleness()
})
);
} else if (_strEq(name, "ChronicleOracle")) {
oracleInfo = abi.encode(
ChronicleOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
feed: IOracle(oracleAddress).feed(),
maxStaleness: IOracle(oracleAddress).maxStaleness()
})
);
} else if (_strEq(name, "LidoOracle")) {
oracleInfo = abi.encode(
LidoOracleInfo({base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH()})
);
} else if (_strEq(name, "LidoFundamentalOracle")) {
oracleInfo = abi.encode(
LidoFundamentalOracleInfo({base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).WETH()})
);
} else if (_strEq(name, "PythOracle")) {
oracleInfo = abi.encode(
PythOracleInfo({
pyth: IOracle(oracleAddress).pyth(),
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
feedId: IOracle(oracleAddress).feedId(),
maxStaleness: IOracle(oracleAddress).maxStaleness(),
maxConfWidth: IOracle(oracleAddress).maxConfWidth()
})
);
} else if (_strEq(name, "RedstoneCoreOracle")) {
(uint208 cachePrice, uint48 cachePriceTimestamp) = IOracle(oracleAddress).cache();
oracleInfo = abi.encode(
RedstoneCoreOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
feedId: IOracle(oracleAddress).feedId(),
maxStaleness: IOracle(oracleAddress).maxStaleness(),
feedDecimals: IOracle(oracleAddress).feedDecimals(),
cachePrice: cachePrice,
cachePriceTimestamp: cachePriceTimestamp
})
);
} else if (_strEq(name, "UniswapV3Oracle")) {
oracleInfo = abi.encode(
UniswapV3OracleInfo({
tokenA: IOracle(oracleAddress).tokenA(),
tokenB: IOracle(oracleAddress).tokenB(),
pool: IOracle(oracleAddress).pool(),
fee: IOracle(oracleAddress).fee(),
twapWindow: IOracle(oracleAddress).twapWindow()
})
);
} else if (_strEq(name, "FixedRateOracle")) {
oracleInfo = abi.encode(
FixedRateOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
rate: IOracle(oracleAddress).rate()
})
);
} else if (_strEq(name, "RateProviderOracle")) {
oracleInfo = abi.encode(
RateProviderOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
rateProvider: IOracle(oracleAddress).rateProvider()
})
);
} else if (_strEq(name, "OndoOracle")) {
oracleInfo = abi.encode(
OndoOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
rwaOracle: IOracle(oracleAddress).rwaOracle()
})
);
} else if (_strEq(name, "PendleOracle")) {
oracleInfo = abi.encode(
PendleProviderOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
pendleMarket: IOracle(oracleAddress).pendleMarket(),
twapWindow: IOracle(oracleAddress).twapWindow()
})
);
} else if (_strEq(name, "PendleUniversalOracle")) {
oracleInfo = abi.encode(
PendleUniversalOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
pendleMarket: IOracle(oracleAddress).pendleMarket(),
twapWindow: IOracle(oracleAddress).twapWindow()
})
);
} else if (_strEq(name, "CurveEMAOracle")) {
oracleInfo = abi.encode(
CurveEMAOracleInfo({
base: IOracle(oracleAddress).base(),
quote: IOracle(oracleAddress).quote(),
pool: IOracle(oracleAddress).pool(),
priceOracleIndex: IOracle(oracleAddress).priceOracleIndex()
})
);
} else if (_strEq(name, "SwaapSafeguardOracle")) {
oracleInfo = abi.encode(
SwaapSafeguardProviderOracleInfo({
base: IOracle(oracleAddress).safeguardPool(),
quote: IOracle(oracleAddress).quote(),
poolId: IOracle(oracleAddress).poolId()
})
);
} else if (_strEq(name, "CrossAdapter")) {
address oracleBaseCross = IOracle(oracleAddress).oracleBaseCross();
address oracleCrossQuote = IOracle(oracleAddress).oracleCrossQuote();
OracleDetailedInfo memory oracleBaseCrossInfo = getOracleInfo(oracleBaseCross, bases, quotes);
OracleDetailedInfo memory oracleCrossQuoteInfo = getOracleInfo(oracleCrossQuote, bases, quotes);
oracleInfo = abi.encode(
CrossAdapterInfo({
base: IOracle(oracleAddress).base(),
cross: IOracle(oracleAddress).cross(),
quote: IOracle(oracleAddress).quote(),
oracleBaseCross: oracleBaseCross,
oracleCrossQuote: oracleCrossQuote,
oracleBaseCrossInfo: oracleBaseCrossInfo,
oracleCrossQuoteInfo: oracleCrossQuoteInfo
})
);
} else if (_strEq(name, "EulerRouter")) {
require(bases.length == quotes.length, "OracleLens: invalid input");
address[][] memory resolvedAssets = new address[][](bases.length);
address[] memory resolvedOracles = new address[](bases.length);
OracleDetailedInfo[] memory resolvedOraclesInfo = new OracleDetailedInfo[](bases.length);
for (uint256 i = 0; i < bases.length; ++i) {
(resolvedAssets[i], resolvedOracles[i], resolvedOraclesInfo[i]) =
_routerResolve(oracleAddress, resolvedAssets[i], bases[i], quotes[i]);
}
address fallbackOracle = IOracle(oracleAddress).fallbackOracle();
oracleInfo = abi.encode(
EulerRouterInfo({
governor: IOracle(oracleAddress).governor(),
fallbackOracle: fallbackOracle,
fallbackOracleInfo: getOracleInfo(fallbackOracle, bases, quotes),
bases: bases,
quotes: quotes,
resolvedAssets: resolvedAssets,
resolvedOracles: resolvedOracles,
resolvedOraclesInfo: resolvedOraclesInfo
})
);
}
return OracleDetailedInfo({oracle: oracleAddress, name: name, oracleInfo: oracleInfo});
}
function isStalePullOracle(address oracleAddress, bytes calldata failureReason) public view returns (bool) {
bytes4 failureReasonSelector = bytes4(failureReason);
return _isStalePythOracle(oracleAddress, failureReasonSelector)
|| _isStaleRedstoneOracle(oracleAddress, failureReasonSelector)
|| _isStaleCrossAdapter(oracleAddress, failureReasonSelector);
}
function getValidAdapters(address base, address quote) public view returns (address[] memory) {
return adapterRegistry.getValidAddresses(base, quote, block.timestamp);
}
function _routerResolve(
address oracleAddress,
address[] memory currentlyResolvedAssets,
address base,
address quote
)
internal
view
returns (address[] memory resolvedAssets, address resolvedOracle, OracleDetailedInfo memory resolvedOracleInfo)
{
if (base == quote) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
(bool success, bytes memory result) =
oracleAddress.staticcall(abi.encodeCall(IOracle.getConfiguredOracle, (base, quote)));
if (!success || result.length < 32) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
resolvedOracle = abi.decode(result, (address));
if (resolvedOracle != address(0)) {
address[] memory bases = new address[](1);
address[] memory quotes = new address[](1);
bases[0] = base;
quotes[0] = quote;
resolvedOracleInfo = getOracleInfo(resolvedOracle, bases, quotes);
return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
}
(success, result) = oracleAddress.staticcall(abi.encodeCall(IOracle.resolvedVaults, (base)));
if (!success || result.length < 32) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
address baseAsset = abi.decode(result, (address));
if (baseAsset != address(0)) {
resolvedAssets = new address[](currentlyResolvedAssets.length + 1);
for (uint256 i = 0; i < currentlyResolvedAssets.length; ++i) {
resolvedAssets[i] = currentlyResolvedAssets[i];
}
resolvedAssets[resolvedAssets.length - 1] = baseAsset;
return _routerResolve(oracleAddress, resolvedAssets, baseAsset, quote);
}
(success, result) = oracleAddress.staticcall(abi.encodeCall(IOracle.fallbackOracle, ()));
if (!success || result.length < 32) return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
resolvedOracle = abi.decode(result, (address));
if (resolvedOracle != address(0)) {
address[] memory bases = new address[](1);
address[] memory quotes = new address[](1);
bases[0] = base;
quotes[0] = quote;
resolvedOracleInfo = getOracleInfo(resolvedOracle, bases, quotes);
return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
}
return (currentlyResolvedAssets, resolvedOracle, resolvedOracleInfo);
}
function _isStalePythOracle(address oracle, bytes4 failureSelector) internal view returns (bool) {
if (oracle == address(0)) return false;
(bool success, bytes memory result) = oracle.staticcall(abi.encodeCall(IPriceOracle.name, ()));
if (success && result.length >= 32) {
string memory name = abi.decode(result, (string));
return _strEq(name, "PythOracle") && failureSelector == Errors.PriceOracle_InvalidAnswer.selector;
}
return false;
}
function _isStaleRedstoneOracle(address oracle, bytes4 failureSelector) internal view returns (bool) {
if (oracle == address(0)) return false;
(bool success, bytes memory result) = oracle.staticcall(abi.encodeCall(IPriceOracle.name, ()));
if (success && result.length >= 32) {
string memory name = abi.decode(result, (string));
return _strEq(name, "RedstoneCoreOracle") && failureSelector == Errors.PriceOracle_TooStale.selector;
}
return false;
}
function _isStaleCrossAdapter(address oracle, bytes4 failureSelector) internal view returns (bool) {
if (oracle == address(0)) return false;
(bool success, bytes memory result) = oracle.staticcall(abi.encodeCall(IPriceOracle.name, ()));
if (success && result.length >= 32) {
string memory name = abi.decode(result, (string));
if (!_strEq(name, "CrossAdapter")) return false;
} else {
return false;
}
address oracleBaseCross = IOracle(oracle).oracleBaseCross();
address oracleCrossQuote = IOracle(oracle).oracleCrossQuote();
return _isStalePythOracle(oracleBaseCross, failureSelector)
|| _isStaleRedstoneOracle(oracleBaseCross, failureSelector)
|| _isStalePythOracle(oracleCrossQuote, failureSelector)
|| _isStaleRedstoneOracle(oracleCrossQuote, failureSelector)
|| _isStaleCrossAdapter(oracleBaseCross, failureSelector)
|| _isStaleCrossAdapter(oracleCrossQuote, failureSelector);
}
}
"
},
"src/Lens/Utils.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IEVault} from "evk/EVault/IEVault.sol";
import {RPow} from "evk/EVault/shared/lib/RPow.sol";
abstract contract Utils {
uint256 internal constant SECONDS_PER_YEAR = 365.2425 * 86400;
uint256 internal constant ONE = 1e27;
uint256 internal constant CONFIG_SCALE = 1e4;
uint256 internal constant TTL_HS_ACCURACY = ONE / 1e4;
int256 internal constant TTL_COMPUTATION_MIN = 0;
int256 internal constant TTL_COMPUTATION_MAX = 400 * 1 days;
int256 public constant TTL_INFINITY = type(int256).max;
int256 public constant TTL_MORE_THAN_ONE_YEAR = type(int256).max - 1;
int256 public constant TTL_LIQUIDATION = -1;
int256 public constant TTL_ERROR = -2;
function getWETHAddress() internal view returns (address) {
if (block.chainid == 1) {
return 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
} else if (
block.chainid == 10 || block.chainid == 130 || block.chainid == 8453 || block.chainid == 1923
|| block.chainid == 480 || block.chainid == 57073 || block.chainid == 60808
) {
return 0x4200000000000000000000000000000000000006;
} else if (block.chainid == 56) {
return 0x2170Ed0880ac9A755fd29B2688956BD959F933F8;
} else if (block.chainid == 100) {
return 0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1;
} else if (block.chainid == 137) {
return 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619;
} else if (block.chainid == 146) {
return 0x50c42dEAcD8Fc9773493ED674b675bE577f2634b;
} else if (block.chainid == 42161) {
return 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
} else if (block.chainid == 43114) {
return 0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB;
} else if (block.chainid == 80094) {
return 0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590;
} else {
// bitcoin-specific and test networks
if (
block.chainid == 30 || block.chainid == 21000000 || block.chainid == 10143 || block.chainid == 80084
|| block.chainid == 2390
) {
return address(0);
}
// hyperEVM
if (block.chainid == 999) {
return address(0);
}
// TAC
if (block.chainid == 239) {
return address(0);
}
}
revert("getWETHAddress: Unsupported chain");
}
function _strEq(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
/// @dev for tokens like MKR which return bytes32 on name() or symbol()
function _getStringOrBytes32(address contractAddress, bytes4 selector) internal view returns (string memory) {
(bool success, bytes memory result) = contractAddress.staticcall(abi.encodeWithSelector(selector));
return (success && result.length != 0)
? result.length == 32 ? string(abi.encodePacked(result)) : abi.decode(result, (string))
: "";
}
function _getDecimals(address contractAddress) internal view returns (uint8) {
(bool success, bytes memory data) =
contractAddress.staticcall(abi.encodeCall(IEVault(contractAddress).decimals, ()));
return success && data.length >= 32 ? abi.decode(data, (uint8)) : 18;
}
function _computeAPYs(uint256 borrowSPY, uint256 cash, uint256 borrows, uint256 interestFee)
internal
pure
returns (uint256 borrowAPY, uint256 supplyAPY)
{
uint256 totalAssets = cash + borrows;
bool overflow;
(borrowAPY, overflow) = RPow.rpow(borrowSPY + ONE, SECONDS_PER_YEAR, ONE);
if (overflow) return (0, 0);
borrowAPY -= ONE;
supplyAPY =
totalAssets == 0 ? 0 : borrowAPY * borrows * (CONFIG_SCALE - interestFee) / totalAssets / CONFIG_SCALE;
}
struct CollateralInfo {
uint256 borrowSPY;
uint256 borrows;
uint256 totalAssets;
uint256 interestFee;
uint256 borrowInterest;
}
function _calculateTimeToLiquidation(
address liabilityVault,
uint256 liabilityValue,
address[] memory collaterals,
uint256[] memory collateralValues
) internal view returns (int256) {
// if there's no liability, time to liquidation is infinite
if (liabilityValue == 0) return TTL_INFINITY;
// get borrow interest rate
uint256 liabilitySPY;
{
(bool success, bytes memory data) =
liabilityVault.staticcall(abi.encodeCall(IEVault(liabilityVault).interestRate, ()));
if (success && data.length >= 32) {
liabilitySPY = abi.decode(data, (uint256));
}
}
// get individual collateral interest rates and total collateral value
CollateralInfo[] memory collateralInfos = new CollateralInfo[](collaterals.length);
uint256 collateralValue;
for (uint256 i = 0; i < collaterals.length; ++i) {
address collateral = collaterals[i];
(bool success, bytes memory data) =
collateral.staticcall(abi.encodeCall(IEVault(collateral).interestRate, ()));
if (success && data.length >= 32) {
collateralInfos[i].borrowSPY = abi.decode(data, (uint256));
}
(success, data) = collateral.staticcall(abi.encodeCall(IEVault(collateral).totalBorrows, ()));
if (success && data.length >= 32) {
collateralInfos[i].borrows = abi.decode(data, (uint256));
}
(success, data) = collateral.staticcall(abi.encodeCall(IEVault(collateral).cash, ()));
if (success && data.length >= 32) {
collateralInfos[i].totalAssets = abi.decode(data, (uint256)) + collateralInfos[i].borrows;
}
(success, data) = collateral.staticcall(abi.encodeCall(IEVault(collateral).interestFee, ()));
if (success && data.length >= 32) {
collateralInfos[i].interestFee = abi.decode(data, (uint256));
}
collateralValue += collateralValues[i];
}
// if liability is greater than or equal to collateral, the account is eligible for liquidation right away
if (liabilityValue >= collateralValue) return TTL_LIQUIDATION;
// if there's no borrow interest rate, time to liquidation is infinite
if (liabilitySPY == 0) return TTL_INFINITY;
int256 minTTL = TTL_COMPUTATION_MIN;
int256 maxTTL = TTL_COMPUTATION_MAX;
int256 ttl;
// calculate time to liquidation using binary search
while (true) {
ttl = minTTL + (maxTTL - minTTL) / 2;
// break if the search range is too small
if (maxTTL <= minTTL + 1 days) break;
if (ttl < 1 days) break;
// calculate the liability interest accrued
uint256 liabilityInterest;
if (liabilitySPY > 0) {
(uint256 multiplier, bool overflow) = RPow.rpow(liabilitySPY + ONE, uint256(ttl), ONE);
if (overflow) return TTL_ERROR;
liabilityInterest = liabilityValue * multiplier / ONE - liabilityValue;
}
// calculate the collaterals interest accrued
uint256 collateralInterest;
for (uint256 i = 0; i < collaterals.length; ++i) {
if (collateralInfos[i].borrowSPY == 0 || collateralInfos[i].totalAssets == 0) continue;
(uint256 multiplier, bool overflow) = RPow.rpow(collateralInfos[i].borrowSPY + ONE, uint256(ttl), ONE);
if (overflow) return TTL_ERROR;
collateralInfos[i].borrowInterest = collateralValues[i] * multiplier / ONE - collateralValues[i];
collateralInterest += collateralInfos[i].borrowInterest * collateralInfos[i].borrows
* (CONFIG_SCALE - collateralInfos[i].interestFee) / collateralInfos[i].totalAssets / CONFIG_SCALE;
}
// calculate the health factor
uint256 hs = (collateralValue + collateralInterest) * ONE / (liabilityValue + liabilityInterest);
// if the collateral interest accrues fater than the liability interest, the account should never be
// liquidated
if (collateralInterest >= liabilityInterest) return TTL_INFINITY;
// if the health factor is within the acceptable range, return the time to liquidation
if (hs >= ONE && hs - ONE <= TTL_HS_ACCURACY) break;
if (hs < ONE && ONE - hs <= TTL_HS_ACCURACY) break;
// adjust the search range
if (hs >= ONE) minTTL = ttl + 1 days;
else maxTTL = ttl - 1 days;
}
return ttl > int256(SECONDS_PER_YEAR) ? TTL_MORE_THAN_ONE_YEAR : int256(ttl) / 1 days;
}
}
"
},
"src/SnapshotRegistry/SnapshotRegistry.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Context} from "openzeppelin-contracts/utils/Context.sol";
import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol";
/// @title SnapshotRegistry
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Revokeable append-only registry of addresses.
contract SnapshotRegistry is EVCUtil, Ownable {
struct Entry {
/// @notice The timestamp when the address was added.
uint128 addedAt;
/// @notice The timestamp when the address was revoked.
uint128 revokedAt;
}
/// @notice List of addresses by their base and quote asset.
/// @dev The keys are lexicographically sorted (asset0 < asset1).
mapping(address asset0 => mapping(address asset1 => address[])) internal map;
/// @notice Addresses added to the registry.
mapping(address => Entry) public entries;
/// @notice An address was added to the registry.
/// @param element The address added.
/// @param asset0 The smaller address out of (base, quote).
/// @param asset1 The larger address out of (base, quote).
/// @param addedAt The timestamp when the address was added.
event Added(address indexed element, address indexed asset0, address indexed asset1, uint256 addedAt);
/// @notice An address was revoked from the registry.
/// @param element The address revoked.
/// @param revokedAt The timestamp when the address was revoked.
event Revoked(address indexed element, uint256 revokedAt);
/// @notice The address cannot be added because it already exists in the registry.
error Registry_AlreadyAdded();
/// @notice The address cannot be revoked because it does not exist in the registry.
error Registry_NotAdded();
/// @notice The address cannot be revoked because it was already revoked from the registry.
error Registry_AlreadyRevoked();
/// @notice Deploy SnapshotRegistry.
/// @param _evc The address of the EVC.
/// @param _owner The address of the owner.
constructor(address _evc, address _owner) EVCUtil(_evc) Ownable(_owner) {}
/// @notice Adds an address to the registry.
/// @param element The address to add.
/// @param base The corresponding base asset.
/// @param quote The corresponding quote asset.
/// @dev Only callable by the owner.
function add(address element, address base, address quote) external onlyEVCAccountOwner onlyOwner {
Entry storage entry = entries[element];
if (entry.addedAt != 0) revert Registry_AlreadyAdded();
entry.addedAt = uint128(block.timestamp);
(address asset0, address asset1) = _sort(base, quote);
map[asset0][asset1].push(element);
emit Added(element, asset0, asset1, block.timestamp);
}
/// @notice Revokes an address from the registry.
/// @param element The address to revoke.
/// @dev Only callable by the owner.
function revoke(address element) external onlyEVCAccountOwner onlyOwner {
Entry storage entry = entries[element];
if (entry.addedAt == 0) revert Registry_NotAdded();
if (entry.revokedAt != 0) revert Registry_AlreadyRevoked();
entry.revokedAt = uint128(block.timestamp);
emit Revoked(element, block.timestamp);
}
/// @notice Returns the all valid addresses for a given base and quote.
/// @param base The address of the base asset.
/// @param quote The address of the quote asset.
/// @param snapshotTime The timestamp to check.
/// @dev Order of base and quote does not matter.
/// @return All addresses for base and quote valid at `snapshotTime`.
function getValidAddresses(address base, address quote, uint256 snapshotTime)
external
view
returns (address[] memory)
{
(address asset0, address asset1) = _sort(base, quote);
address[] memory elements = map[asset0][asset1];
address[] memory validElements = new address[](elements.length);
uint256 numValid = 0;
for (uint256 i = 0; i < elements.length; ++i) {
address element = elements[i];
if (isValid(element, snapshotTime)) {
validElements[numValid++] = element;
}
}
/// @solidity memory-safe-assembly
assembly {
// update the length
mstore(validElements, numValid)
}
return validElements;
}
/// @notice Returns whether an address was valid at a point in time.
/// @param element The address to check.
/// @param snapshotTime The timestamp to check.
/// @dev Returns false if:
/// - address was never added,
/// - address was added after the timestamp,
/// - address was revoked before or at the timestamp.
/// @return Whether `element` was valid at `snapshotTime`.
function isValid(address element, uint256 snapshotTime) public view returns (bool) {
uint256 addedAt = entries[element].addedAt;
uint256 revokedAt = entries[element].revokedAt;
if (addedAt == 0 || addedAt > snapshotTime) return false;
if (revokedAt != 0 && revokedAt <= snapshotTime) return false;
return true;
}
/// @notice Lexicographically sort two addresses.
/// @param assetA One of the assets in the pair.
/// @param assetB The other asset in the pair.
/// @return The address first in lexicographic order.
/// @return The address second in lexicographic order.
function _sort(address assetA, address assetB) internal pure returns (address, address) {
return assetA < assetB ? (assetA, assetB) : (assetB, assetA);
}
/// @dev Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be
/// called by the current owner.
/// NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is
/// only available to the owner.
function renounceOwnership() public virtual override onlyEVCAccountOwner {
super.renounceOwnership();
}
/// @dev Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.
function transferOwnership(address newOwner) public virtual override onlyEVCAccountOwner {
super.transferOwnership(newOwner);
}
/// @notice Retrieves the message sender in the context of the EVC.
/// @dev This function returns the account on behalf of which the current operation is being performed, which is
/// either msg.sender or the account authenticated by the EVC.
/// @return The address of the message sender.
function _msgSender() internal view override (Context, EVCUtil) returns (address) {
return EVCUtil._msgSender();
}
}
"
},
"lib/euler-price-oracle/src/interfaces/IPriceOracle.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
/// @title IPriceOracle
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Common PriceOracle interface.
interface IPriceOracle {
/// @notice Get the name of the oracle.
/// @return The name of the oracle.
function name() external view returns (string memory);
/// @notice One-sided price: How much quote token you would get for inAmount of base token, assuming no price spread.
/// @param inAmount The amount of `base` to convert.
/// @param base The token that is being priced.
/// @param quote The token that is the unit of account.
/// @return outAmount The amount of `quote` that is equivalent to `inAmount` of `base`.
function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256 outAmount);
/// @notice Two-sided price: How much quote token you would get/spend for selling/buying inAmount of base token.
/// @param inAmount The amount of `base` to convert.
/// @param base The token that is being priced.
/// @param quote The token that is the unit of account.
/// @return bidOutAmount The amount of `quote` you would get for selling `inAmount` of `base`.
/// @return askOutAmount The amount of `quote` you would spend for buying `inAmount` of `base`.
function getQuotes(uint256 inAmount, address base, address quote)
external
view
returns (uint256 bidOutAmount, uint256 askOutAmount);
}
"
},
"lib/euler-price-oracle/src/lib/Errors.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
/// @title Errors
/// @custom:security-contact security@euler.xyz
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Collects common errors in PriceOracles.
library Errors {
/// @notice The external feed returned an invalid answer.
error PriceOracle_InvalidAnswer();
/// @notice The configuration parameters for the PriceOracle are invalid.
error PriceOracle_InvalidConfiguration();
/// @notice The base/quote path is not supported.
/// @param base The address of the base asset.
/// @param quote The address of the quote asset.
error PriceOracle_NotSupported(address base, address quote);
/// @notice The quote cannot be completed due to overflow.
error PriceOracle_Overflow();
/// @notice The price is too stale.
/// @param staleness The time elapsed since the price was updated.
/// @param maxStaleness The maximum time elapsed since the last price update.
error PriceOracle_TooStale(uint256 staleness, uint256 maxStaleness);
/// @notice The method can only be called by the governor.
error Governance_CallerNotGovernor();
}
"
},
"src/Lens/LensTypes.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
struct AccountInfo {
EVCAccountInfo evcAccountInfo;
VaultAccountInfo vaultAccountInfo;
AccountRewardInfo accountRewardInfo;
}
struct AccountMultipleVaultsInfo {
EVCAccountInfo evcAccountInfo;
VaultAccountInfo[] vaultAccountInfo;
AccountRewardInfo[] accountRewardInfo;
}
struct EVCAccountInfo {
uint256 timestamp;
address evc;
address account;
bytes19 addressPrefix;
address owner;
bool isLockdownMode;
bool isPermitDisabledMode;
uint256 lastAccountStatusCheckTimestamp;
address[] enabledControllers;
address[] enabledCollaterals;
}
struct VaultAccountInfo {
uint256 timestamp;
address account;
address vault;
address asset;
uint256 assetsAccount;
uint256 shares;
uint256 assets;
uint256 borrowed;
uint256 assetAllowanceVault;
uint256 assetAllowanceVaultPermit2;
uint256 assetAllowanceExpirationVaultPermit2;
uint256 assetAllowancePermit2;
bool balanceForwarderEnabled;
bool isController;
bool isCollateral;
AccountLiquidityInfo liquidityInfo;
}
struct AccountLiquidityInfo {
bool queryFailure;
bytes queryFailureReason;
int256 timeToLiquidation;
uint256 liabilityValue;
uint256 collateralValueBorrowing;
uint256 collateralValueLiquidation;
uint256 collateralValueRaw;
CollateralLiquidityInfo[] collateralLiquidityBorrowingInfo;
CollateralLiquidityInfo[] collateralLiquidityLiquidationInfo;
CollateralLiquidityInfo[] collateralLiquidityRawInfo;
}
struct CollateralLiquidityInfo {
address collateral;
uint256 collateralValue;
}
struct VaultInfoERC4626 {
uint256 timestamp;
address vault;
string vaultName;
string vaultSymbol;
uint256 vaultDecimals;
address asset;
string assetName;
string assetSymbol;
uint256 assetDecimals;
uint256 totalShares;
uint256 totalAssets;
bool isEVault;
}
struct VaultInfoFull {
uint256 timestamp;
address vault;
string vaultName;
string vaultSymbol;
uint256 vaultDecimals;
address asset;
string assetName;
string assetSymbol;
uint256 assetDecimals;
address unitOfAccount;
string unitOfAccountName;
string unitOfAccountSymbol;
uint256 unitOfAccountDecimals;
uint256 totalShares;
uint256 totalCash;
uint256 totalBorrowed;
uint256 totalAssets;
uint256 accumulatedFeesShares;
uint256 accumulatedFeesAssets;
address governorFeeReceiver;
address protocolFeeReceiver;
uint256 protocolFeeShare;
uint256 interestFee;
uint256 hookedOperations;
uint256 configFlags;
uint256 supplyCap;
uint256 borrowCap;
uint256 maxLiquidationDiscount;
uint256 liquidationCoolOffTime;
address dToken;
address oracle;
address interestRateModel;
address hookTarget;
address evc;
address protocolConfig;
address balanceTracker;
address permit2;
address creator;
address governorAdmin;
VaultInterestRateModelInfo irmInfo;
LTVInfo[] collateralLTVInfo;
AssetPriceInfo liabilityPriceInfo;
AssetPriceInfo[] collateralPriceInfo;
OracleDetailedInfo oracleInfo;
AssetPriceInfo backupAssetPriceInfo;
OracleDetailedInfo backupAssetOracleInfo;
}
struct LTVInfo {
address collateral;
uint256 borrowLTV;
uint256 liquidationLTV;
uint256 initialLiquidationLTV;
uint256 targetTimestamp;
uint256 rampDuration;
}
struct AssetPriceInfo {
bool queryFailure;
bytes queryFailureReason;
uint256 timestamp;
address oracle;
address asset;
address unitOfAccount;
uint256 amountIn;
uint256 amountOutMid;
uint256 amountOutBid;
uint256 amountOutAsk;
}
struct VaultInterestRateModelInfo {
bool queryFailure;
bytes queryFailureReason;
address vault;
address interestRateModel;
InterestRateInfo[] interestRateInfo;
InterestRateModelDetailedInfo interestRateModelInfo;
}
struct InterestRateInfo {
uint256 cash;
uint256 borrows;
uint256 borrowSPY;
uint256 borrowAPY;
uint256 supplyAPY;
}
enum InterestRateModelType {
UNKNOWN,
KINK,
ADAPTIVE_CURVE,
KINKY,
FIXED_CYCLICAL_BINARY
}
struct InterestRateModelDetailedInfo {
address interestRateModel;
InterestRateModelType interestRateModelType;
bytes interestRateModelParams;
}
struct KinkIRMInfo {
uint256 baseRate;
uint256 slope1;
uint256 slope2;
uint256 kink;
}
struct AdaptiveCurveIRMInfo {
int256 targetUtilization;
int256 initialRateAtTarget;
int256 minRateAtTarget;
int256 maxRateAtTarget;
int256 curveSteepness;
int256 adjustmentSpeed;
}
struct KinkyIRMInfo {
uint256 baseRate;
uint256 slope;
uint256 shape;
uint256 kink;
uint256 cutoff;
}
struct FixedCyclicalBinaryIRMInfo {
uint256 primaryRate;
uint256 secondaryRate;
uint256 primaryDuration;
uint256 secondaryDuration;
uint256 startTimestamp;
}
struct AccountRewardInfo {
uint256 timestamp;
address account;
address vault;
address balanceTracker;
bool balanceForwarderEnabled;
uint256 balance;
EnabledRewardInfo[] enabledRewardsInfo;
}
struct EnabledRewardInfo {
address reward;
uint256 earnedReward;
uint256 earnedRewardRecentIgnored;
}
struct VaultRewardInfo {
uint256 timestamp;
address vault;
address reward;
string rewardName;
string rewardSymbol;
uint8 rewardDecimals;
address balanceTracker;
uint256 epochDuration;
uint256 currentEpoch;
uint256 totalRewardedEligible;
uint256 totalRewardRegistered;
uint256 totalRewardClaimed;
RewardAmountInfo[] epochInfoPrevious;
RewardAmountInfo[] epochInfoUpcoming;
}
struct RewardAmountInfo {
uint256 epoch;
uint256 epochStart;
uint256 epochEnd;
uint256 rewardAmount;
}
struct OracleDetailedInfo {
address oracle;
string name;
bytes oracleInfo;
}
struct EulerRouterInfo {
address governor;
address fallbackOracle;
OracleDetailedInfo fallbackOracleInfo;
address[] bases;
address[] quotes;
address[][] resolvedAssets;
address[] resolvedOracles;
OracleDetailedInfo[] resolvedOraclesInfo;
}
struct ChainlinkOracleInfo {
address base;
address quote;
address feed;
string feedDescription;
uint256 maxStaleness;
}
struct ChainlinkInfrequentOracleInfo {
address base;
address quote;
address feed;
string feedDescription;
uint256 maxStaleness;
}
struct ChronicleOracleInfo {
address base;
address quote;
address feed;
uint256 maxStaleness;
}
struct LidoOracleInfo {
address base;
address quote;
}
struct LidoFundamentalOracleInfo {
address base;
address quote;
}
struct PythOracleInfo {
address pyth;
address base;
address quote;
bytes32 feedId;
uint256 maxStaleness;
uint256 maxConfWidth;
}
struct RedstoneCoreOracleInfo {
address base;
address quote;
bytes32 feedId;
uint8 feedDecimals;
uint256 maxStaleness;
uint208 cachePrice;
uint48 cachePriceTimestamp;
}
struct UniswapV3OracleInfo {
address tokenA;
address tokenB;
address pool;
uint24 fee;
uint32 twapWindow;
}
struct FixedRateOracleInfo {
address base;
address quote;
uint256 rate;
}
struct RateProviderOracleInfo {
address base;
address quote;
address rateProvider;
}
struct OndoOracleInfo {
address base;
address quote;
address rwaOracle;
}
struct PendleProviderOracleInfo {
address base;
address quote;
address pendleMarket;
uint32 twapWindow;
}
struct PendleUniversalOracleInfo {
address base;
address quote;
address pendleMarket;
uint32 twapWindow;
}
struct CurveEMAOracleInfo {
address base;
address quote;
address pool;
uint256 priceOracleIndex;
}
struct SwaapSafeguardProviderOracleInfo {
address base;
address quote;
bytes32 poolId;
}
struct CrossAdapterInfo {
address base;
address cross;
address quote;
address oracleBaseCross;
address oracleCrossQuote;
OracleDetailedInfo oracleBaseCrossInfo;
OracleDetailedInfo oracleCrossQuoteInfo;
}
struct EulerEarnVaultInfoFull {
uint256 timestamp;
address vault;
string vaultName;
string vaultSymbol;
uint256 vaultDecimals;
address asset;
string assetName;
string assetSymbol;
uint256 assetDecimals;
uint256 totalShares;
uint256 totalAssets;
uint256 lostAssets;
uint256 availableAssets;
uint256 timelock;
uint256 performanceFee;
address feeReceiver;
address owner;
address creator;
address curator;
address guardian;
address evc;
address permit2;
uint256 pendingTimelock;
uint256 pendingTimelockValidAt;
address pendingGuardian;
uint256 pendingGuardianValidAt;
address[] supplyQueue;
EulerEarnVaultStrategyInfo[] strategies;
}
struct EulerEarnVaultStrategyInfo {
address strategy;
uint256 allocatedAssets;
uint256 availableAssets;
uint256 currentAllocationCap;
uint256 pendingAllocationCap;
uint256 pendingAllocationCapValidAt;
uint256 removableAt;
VaultInfoERC4626 info;
}
"
},
"lib/euler-vault-kit/src/EVault/IEVault.sol": {
"content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
import {IVault as IEVCVault} from "ethereum-vault-connector/interfaces/IVault.sol";
// Full interface of EVault and all it's modules
/// @title IInitialize
/// @notice Interface of the initialization module of EVault
interface IInitialize {
/// @notice Initialization of the newly deployed proxy contract
/// @param proxyCreator Account which created the proxy or should be the initial governor
function initialize(address proxyCreator) external;
}
/// @title IERC20
/// @notice Interface of the EVault's Initialize module
interface IERC20 {
/// @notice Vault share token (eToken) name, ie "Euler Vault: DAI"
/// @return The name of the eToken
function name() external view returns (string memory);
/// @notice Vault share token (eToken) symbol, ie "eDAI"
/// @return The symbol of the eToken
function symbol() external view returns (string memory);
/// @notice Decimals, the same as the asset's or 18 if the asset doesn't implement `decimals()`
/// @return The decimals of the eToken
function decimals() external view returns (uint8);
/// @notice Sum of all eToken balances
/// @return The total supply of the eToken
function totalSupply() external view returns (uint256);
/// @notice Balance of a particular account, in eTokens
/// @param account Address to query
/// @return The balance of the account
function balanceOf(address account) external view returns (uint256);
/// @notice Retrieve the current allowance
/// @param holder The account holding the eTokens
/// @param spender Trusted address
/// @return The allowance from holder for spender
function allowance(address holder, address spender) external view returns (uint256);
/// @notice Transfer eTokens to another address
/// @param to Recipient account
/// @param amount In shares.
/// @return True if transfer succeeded
function transfer(address to, uint256 amount) external returns (bool);
/// @notice Transfer eTokens from one address to another
/// @param from This address must've approved the to address
/// @param to Recipient account
/// @param amount In shares
/// @return True if transfer succeeded
function transferFrom(address from, address to, uint256 amount) external returns (bool);
/// @notice Allow spender to access an amount of your eTokens
/// @param spender Trusted address
/// @param amount Use max uint for "infinite" allowance
/// @return True if approval succeeded
function approve(address spender, uint256 amount) external returns (bool);
}
/// @title IToken
/// @notice Interface of the EVault's Token module
interface IToken is IERC20 {
/// @notice Transfer the full eToken balance of an address to another
/// @param from This address must've approved the to address
/// @param to Recipient account
/// @return True if transfer succeeded
function transferFromMax(address from, address to) external returns (bool);
}
/// @title IERC4626
/// @notice Interface of an ERC4626 vault
interface IERC4626 {
/// @notice Vault's underlying asset
/// @return The vault's underlying asset
function asset() external view returns (address);
/// @notice Total amount of managed assets, cash and borrows
/// @return The total amount of assets
function totalAssets() external view returns (uint256);
/// @notice Calculate amount of assets corresponding to the requested shares amount
/// @param shares Amount of shares to convert
/// @return The amount of assets
function convertToAssets(uint256 shares) external view returns (uint256);
/// @notice Calculate amount of shares corresponding to the requested assets amount
/// @param assets Amount of assets to convert
/// @return The amount of shares
function convertToShares(uint256 assets) external view returns (uint256);
/// @notice Fetch the maximum amount of assets a user can deposit
/// @param account Address to query
/// @return The max amount of assets the account can deposit
function maxDeposit(address account) external view returns (uint256);
/// @notice Calculate an amount of shares that would be created by depositing assets
/// @param assets Amount of assets deposited
/// @return Amount of shares received
function previewDeposit(uint256 assets) external view returns (uint256);
/// @notice Fetch the maximum amount of shares a user can mint
/// @param account Address to query
/// @return The max amount of shares the account can mint
function maxMint(address account) external view returns (uint256);
/// @notice Calculate an amount of assets that would be required to mint requested amount of shares
/// @param shares Amount of shares to be minted
/// @return Required amount of assets
function previewMint(uint256 shares) external view returns (uint256);
/// @notice Fetch the maximum amount of assets a user is allowed to withdraw
/// @param owner Account holding the shares
/// @return The maximum amount of assets the owner is allowed to withdraw
function maxWithdraw(address owner) external view returns (uint256);
/// @notice Calculate the amount of shares that will be burned when withdrawing requested amount of assets
/// @param assets Amount of assets withdrawn
/// @return Amount of shares burned
function previewWithdraw(uint256 assets) external view returns (uint256);
/// @notice Fetch the maximum amount of shares a user is allowed to redeem for assets
/// @param owner Account holding the shares
/// @return The maximum amount of shares the owner is allowed to redeem
function maxRedeem(address owner) external view returns (uint256);
/// @notice Calculate the amount of assets that will be transferred when redeeming requested amount of shares
/// @param shares Amount of shares redeemed
/// @return Amount of assets transferred
function previewRedeem(uint256 shares) external view returns (uint256);
/// @notice Transfer requested amount of underlying tokens from sender to the vault pool in return for shares
/// @param amount Amount of assets to deposit (use max uint256 for full underlying token balance)
/// @param receiver An account to receive the shares
/// @return Amount of shares minted
/// @dev Deposit will round down the amount of assets that are converted to shares. To prevent losses consider using
/// mint instead.
function deposit(uint256 amount, address receiver) external returns (uint256);
/// @notice Transfer underlying tokens from sender to the vault pool in return for requested amount of shares
/// @param amount Amount of shares to be minted
/// @param receiver An account to receive the shares
/// @return Amount of assets deposited
function mint(uint256 amount, address receiver) external returns (uint256);
/// @notice Transfer requested amount of underlying tokens from the vault and decrease account's shares balance
/// @param amount Amount of assets to withdraw
/// @param receiver Account to receive the withdrawn assets
/// @param owner Account holding the shares to burn
/// @return Amount of shares burned
function withdraw(uint256 amount, address receiver, address owner) external returns (uint256);
/// @notice Burn requested shares and transfer corresponding underlying tokens from the vault to the receiver
/// @param amount Amount of shares to burn (use max uint256 to burn full owner balance)
/// @param receiver Account to receive the withdrawn assets
/// @param owner Account holding the shares to burn.
/// @return Amount of assets transferred
function redeem(uint256 amount, address receiver, address owner) external returns (uint256);
}
/// @title IVault
/// @notice Interface of the EVault's Vault module
interface IVault is IERC4626 {
/// @notice Balance of the fees accumulator, in shares
/// @return The accumulated fees in shares
function accumulatedFees() external view returns (uint256);
/// @notice Balance of the fees accumulator, in underlying units
/// @return The accumulated fees in asset units
function accumulatedFeesAssets() external view returns (uint256);
/// @notice Address of the original vault creator
/// @return The address of the creator
function creator() external view returns (address);
/// @notice Creates shares for the receiver, from excess asset balances of the vault (not accounted for in `cash`)
/// @param amount Amount of assets to claim (use max uint256 to claim all available assets)
/// @param receiver An account to receive the shares
/// @return Amount of shares minted
/// @dev Could be used as an alternative deposit flow in certain scenarios. E.g. swap directly to the vault, call
/// `skim` to claim deposit.
function skim(uint256 amount, address receiver) external returns (uint256);
}
/// @title IBorrowing
/// @notice Interface of the EVault's Borrowing module
interface IBorrowing {
/// @notice Sum of all outstanding debts, in underlying units (increases as interest is accrued)
/// @return The total borrows in asset units
function totalBorrows() external view returns (uint256);
/// @notice Sum of all outstanding debts, in underlying units scaled up by shifting
/// INTERNAL_DEBT_PRECISION_SHIFT bits
/// @return The total borrows in internal debt precision
function totalBorrowsExact() external view returns (uint256);
/// @notice Balance of vault assets as tracked by deposits/withdrawals and borrows/repays
/// @return The amount of assets the vault tracks as current direct holdings
function cash() external view returns (uint256);
/// @notice Debt owed by a particular account, in underlying units
/// @param account Address to query
/// @return The debt of the account in asset units
function debtOf(address account) external view returns (uint256);
/// @notice Debt owed by a particular account, in underlying units scaled up by shifting
/// INTERNAL_DEBT_PRECISION_SHIFT bits
/// @param account Address to query
/// @return The debt of the account in internal precision
function debtOfExact(address account) external view returns (uint256);
/// @notice Retrieves the current interest rate for an asset
/// @return The interest rate in yield-per-second, scaled by 10**27
function interestRate() external view returns (uint256);
/// @notice Retrieves the current interest rate accumulator for an asset
/// @return An opaque accumulator that increases as interest is accrued
function interestAccumulator() external view returns (uint256);
/// @notice Returns an address of the sidecar DToken
/// @return The address of the DToken
function dToken() external view returns (address);
/// @notice Transfer underlying tokens from the vault to the sender, and increase sender's debt
/// @param amount Amount of assets to borrow (use max uint256 for all available tokens)
/// @param receiver Account receiving the borrowed tokens
/// @return Amount of assets borrowed
function borrow(uint256 amount, address receiver) external returns (uint256);
/// @notice Transfer underlying tokens from the sender to the vault, and decrease receiver's debt
/// @param amount Amount of debt to repay in assets (use max uint256 for full debt)
/// @param receiver Account holding the debt to be repaid
/// @return Amount of assets repaid
function repay(uint256 amount, address receiver) external returns (uint256);
/// @notice Pay off liability with shares ("self-repay")
/// @param amount In asset units (use max uint256 to repay the debt in full or up to the available deposit)
/// @param receiver Account to remove debt from by burning sender's shares
/// @return shares Amount of shares burned
/// @return debt Amount of debt removed in assets
/// @dev Equivalent to withdrawing and repaying, but no assets are needed to be present in the vault
/// @dev Contrary to a regular `repay`, if account is unhealthy, the repay amount must bring the account back to
/// health, or the operation will revert during account status check
function repayWithShares(uint256 amount, address receiver) external returns (uint256 shares, uint256 debt);
/// @notice Take over debt from another account
/// @param amount Amount of debt in asset units (use max uint256 for all the account's debt)
/// @param from Account to pull the debt from
/// @dev Due to internal debt precision accounting, the liability reported on either or both accounts after
/// calling `pullDebt` may not match the `amount` requested precisely
function pullDebt(uint256 amount, address from) external;
/// @notice Request a flash-loan. A onFlashLoan() callback in msg.sender will be invoked, which must repay the loan
/// to the main Euler address prior to returning.
/// @param amount In asset units
/// @param data Passed through to the onFlashLoan() callback, so contracts don't need to store transient data in
/// storage
function flashLoan(uint256 amount, bytes calldata data) external;
/// @notice Updates interest accumulator and totalBorrows, credits reserves, re-targets interest rate, and logs
/// vault status
function touch() external;
}
/// @title ILiquidation
/// @notice Interface of the EVault's Liquidation module
interface ILiquidation {
/// @notice Checks to see if a liquidation would be profitable, without actually doing anything
/// @param liquidator Address that will initiate the liquidation
/// @param violator Address that may be in collateral violation
/// @param collateral Collateral which is to be seized
/// @return maxRepay Max amount of debt that can be repaid, in asset units
/// @return maxYield Yield in collateral corresponding to max allowed amount of debt to be repaid, in collateral
/// balance (shares for vaults)
function checkLiquidation(address liquidator, address violator, address collateral)
external
view
returns (uint256 maxRepay, uint256 maxYield);
/// @notice Attempts to perform a liquidation
/// @param violator Address that may be in collateral violation
/// @param collateral Collateral which is to be seized
/// @param repayAssets The amount of underlying debt to be transferred from violator to sender, in asset units (use
/// max uint256 to repay the maximum possible amount). Meant as slippage check together with `minYieldBalance`
/// @param minYieldBalance The minimum acceptable amount of collateral to be transferred from violator to sender, in
/// collateral balance units (shares for vaults). Meant as slippage check together with `repayAssets`
/// @dev If `repayAssets` is set to max uint256 it is assumed the caller will perform their own slippage checks to
/// make sure they are not taking on too much debt. This option is mainly meant for smart contract liquidators
function liquidate(address violator, address collateral, uint256 repayAssets, uint256 minYieldBalance) external;
}
/// @title IRiskManager
/// @notice Interface of the EVault's RiskManager module
interface IRiskManager is IEVCVault {
/// @notice Retrieve account's total liquidity
/// @param account Account holding debt in this vault
/// @param liquidation Flag to indicate if the calculation should be performed in liquidation vs account status
/// check mode, where different LTV values might apply.
/// @return collateralValue Total risk adjusted value of all collaterals in unit of account
/// @return liabilityValue Value of debt in unit of account
function accountLiquidity(address account, bool liquidation)
external
view
returns (uint256 collateralValue, uint256 liabilityValue);
/// @notice Retrieve account's liquidity per collateral
/// @param account Account holding debt in this vault
/// @param liquidation Flag to indicate if the calculation should be performed in liquidation vs account status
/// check mode, where different LTV values might apply.
/// @return collaterals Array of collaterals enabled
/// @return collateralValues Array of risk adjusted collateral values corresponding to items in collaterals array.
/// In unit of account
/// @return liabilityValue Value of debt in unit of account
function accountLiquidityFull(address account, bool liquidation)
external
view
returns (address[] memory collaterals, uint256[] memory collateralValues, uint256 liabilityValue);
/// @notice Release control of the account on EVC if no outstanding debt is present
function disableController() external;
/// @notice Checks the status of an account and reverts if account is not healthy
/// @param account The address of the account to be checked
/// @return magicValue Must return the bytes4 magic value 0xb168c58f (which is a selector of this function) when
/// account status is valid, or revert otherwise.
/// @dev Only callable by EVC during status checks
function checkAccountStatus(address account, address[] calldata collaterals) external view returns (bytes4);
/// @notice Checks the status of the vault and reverts if caps are exceeded
/// @return magicValue Must return the bytes4 magic value 0x4b3d1223 (which is a selector of this fun
Submitted on: 2025-09-27 12:12:08
Comments
Log in to comment.
No comments yet.