Description:
Decentralized Finance (DeFi) protocol contract providing Pausable, Swap, Liquidity, Factory, Oracle functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/oracles/APYOracleV3.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IAPYOracle} from "../interfaces/IAPYOracle.sol";
import {IAavePool} from "../interfaces/external/IAavePool.sol";
import {ICompoundComet} from "../interfaces/external/ICompoundComet.sol";
import {IVesperPool} from "../interfaces/IVesperPool.sol";
/**
* @title APYOracleV3
* @notice Fixed APY Oracle with keeper access control and rate limiting
* @dev Fixes critical vulnerability that allowed APY manipulation via rapid updates
*
* SECURITY FIXES:
* 1. Keeper-only updates (no public access)
* 2. Per-protocol rate limiting (minimum 23 hours between updates)
* 3. Timestamp-based APY calculation (actual time elapsed, not assumed)
* 4. Guardian emergency pause capability
*/
contract APYOracleV3 is IAPYOracle {
// ============ State Variables ============
// Ownership and access control
address public owner;
address public guardian; // Can pause updates in emergency
bool public paused;
// Keeper management (NEW - SECURITY FIX)
mapping(address => bool) public keepers;
uint256 public keeperCount;
// Per-protocol rate limiting (NEW - SECURITY FIX)
mapping(address => uint256) public lastProtocolUpdate;
uint256 public constant MIN_UPDATE_INTERVAL = 23 hours;
// Dynamic adapter registry
mapping(address => bool) public registeredAdapters;
mapping(string => address) public adapterByName;
mapping(address => string) public nameByAdapter;
mapping(address => bool) public isDirectAPY;
// Protocol vault addresses (mainnet)
address public constant MORPHO_VAULT = 0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB;
address public constant YEARN_VAULT = 0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE;
address public constant VESPER_VAULT = 0x0C49066C0808Ee8c673553B7cbd99BCC9ABf113d;
address public constant AAVE_POOL = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;
address public constant COMPOUND_COMET = 0xc3d688B66703497DAA19211EEdff47f25384cdc3;
address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
// Constants
uint256 private constant SECONDS_PER_YEAR = 365 days;
uint256 private constant PRICE_DECIMALS = 1e18;
uint256 private constant WEEK_SIZE = 7;
// Enhanced price tracking with timestamps (SECURITY FIX)
struct PricePoint {
uint256 price;
uint256 timestamp;
}
address[] public allAdapters;
mapping(address => uint256) private adapterIndex; // for quick removal
mapping(address => PricePoint[7]) public priceHistory;
mapping(address => uint256) public currentIndex;
mapping(address => bool) public initialized;
// Manual override system for testing
mapping(address => uint256) public manualAPY;
mapping(address => bool) public useManualAPY;
// Adapter to protocol vault mapping
mapping(address => address) public adapterToVault;
// Events
event KeeperAdded(address indexed keeper);
event KeeperRemoved(address indexed keeper);
event GuardianSet(address indexed guardian);
event EmergencyPause(address indexed triggeredBy);
event EmergencyUnpause(address indexed triggeredBy);
event AdapterRegistered(string indexed name, address indexed adapter, bool isDirectAPY);
event AdapterUnregistered(string indexed name, address indexed adapter);
event VaultMappingSet(address indexed adapter, address indexed vault);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// ============ Modifiers ============
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier onlyKeeper() {
require(keepers[msg.sender] || msg.sender == owner, "Not authorized keeper");
_;
}
modifier whenNotPaused() {
require(!paused, "Oracle paused");
_;
}
modifier rateLimited(address protocol) {
require(
block.timestamp >= lastProtocolUpdate[protocol] + MIN_UPDATE_INTERVAL,
"Update too soon - 23hr minimum"
);
_;
}
// ============ Constructor ============
constructor() {
owner = msg.sender;
emit APYOracleInitialized(address(this));
}
// ============ Access Control Functions ============
/**
* @notice Add a keeper address that can update prices
* @param keeper The address to add as keeper
*/
function addKeeper(address keeper) external onlyOwner {
require(keeper != address(0), "Invalid keeper");
require(!keepers[keeper], "Already keeper");
keepers[keeper] = true;
keeperCount++;
emit KeeperAdded(keeper);
}
/**
* @notice Remove a keeper address
* @param keeper The address to remove
*/
function removeKeeper(address keeper) external onlyOwner {
require(keepers[keeper], "Not a keeper");
keepers[keeper] = false;
keeperCount--;
emit KeeperRemoved(keeper);
}
/**
* @notice Set guardian for emergency pause
* @param _guardian The guardian address
*/
function setGuardian(address _guardian) external onlyOwner {
guardian = _guardian;
emit GuardianSet(_guardian);
}
/**
* @notice Emergency pause (guardian or owner)
*/
function emergencyPause() external {
require(msg.sender == owner || msg.sender == guardian, "Not authorized");
paused = true;
emit EmergencyPause(msg.sender);
}
/**
* @notice Unpause (owner only)
*/
function emergencyUnpause() external onlyOwner {
paused = false;
emit EmergencyUnpause(msg.sender);
}
/**
* @notice Transfer ownership
* @param newOwner The new owner address
*/
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "Invalid owner");
address oldOwner = owner;
owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
// ============ Registry Functions ============
function registerAdapter(
string memory name,
address adapter,
bool _isDirectAPY
) external onlyOwner {
require(adapter != address(0), "Invalid adapter");
require(bytes(name).length > 0, "Invalid name");
require(!registeredAdapters[adapter], "Already registered");
registeredAdapters[adapter] = true;
adapterByName[name] = adapter;
nameByAdapter[adapter] = name;
isDirectAPY[adapter] = _isDirectAPY;
// add to dynamic list
adapterIndex[adapter] = allAdapters.length;
allAdapters.push(adapter);
emit AdapterRegistered(name, adapter, _isDirectAPY);
}
function setAdapterVaultMapping(address adapter, address vault) external onlyOwner {
require(registeredAdapters[adapter], "Adapter not registered");
require(vault != address(0), "Invalid vault");
uint256 testPrice = _getCurrentPrice(vault);
require(testPrice > 0, "APYOracleV3: unsupported vault");
adapterToVault[adapter] = vault;
emit VaultMappingSet(adapter, vault);
}
function unregisterAdapter(string memory name) external onlyOwner {
address adapter = adapterByName[name];
require(adapter != address(0), "Adapter not found");
delete registeredAdapters[adapter];
delete adapterByName[name];
delete nameByAdapter[adapter];
delete isDirectAPY[adapter];
delete adapterToVault[adapter];
// remove from dynamic list (swap & pop)
uint256 idx = adapterIndex[adapter];
uint256 lastIdx = allAdapters.length - 1;
if (idx != lastIdx) {
address lastAdapter = allAdapters[lastIdx];
allAdapters[idx] = lastAdapter;
adapterIndex[lastAdapter] = idx;
}
allAdapters.pop();
delete adapterIndex[adapter];
emit AdapterUnregistered(name, adapter);
}
// ============ Core Price Update (SECURED) ============
/**
* @notice Update price for a protocol vault
* @dev Now restricted to keepers with rate limiting and timestamp tracking
* @param protocol The protocol vault address to update
*/
function updateProtocolPrice(address protocol)
external
onlyKeeper
whenNotPaused
rateLimited(protocol)
{
require(protocol != address(0), "Invalid protocol");
uint256 price = _getCurrentPrice(protocol);
require(price != 0, "Invalid price");
// Update with timestamp tracking
uint256 newIndex = (currentIndex[protocol] + 1) % WEEK_SIZE;
priceHistory[protocol][newIndex] = PricePoint({
price: price,
timestamp: block.timestamp
});
currentIndex[protocol] = newIndex;
// Update rate limit tracker
lastProtocolUpdate[protocol] = block.timestamp;
// Mark as initialized after full week
if (!initialized[protocol] && _hasFullWeekData(protocol)) {
initialized[protocol] = true;
emit ProtocolInitialized(protocol);
}
emit PriceUpdated(protocol, price, block.timestamp);
}
/**
* @notice Batch update prices for efficiency
* @param protocols Array of protocol addresses to update
*/
function batchUpdatePrices(address[] calldata protocols)
external
onlyKeeper
whenNotPaused
{
for (uint256 i = 0; i < protocols.length; i++) {
if (block.timestamp >= lastProtocolUpdate[protocols[i]] + MIN_UPDATE_INTERVAL) {
_updatePrice(protocols[i]);
}
}
}
function _updatePrice(address protocol) private {
uint256 price = _getCurrentPrice(protocol);
if (price == 0) return;
uint256 newIndex = (currentIndex[protocol] + 1) % WEEK_SIZE;
priceHistory[protocol][newIndex] = PricePoint({
price: price,
timestamp: block.timestamp
});
currentIndex[protocol] = newIndex;
lastProtocolUpdate[protocol] = block.timestamp;
if (!initialized[protocol] && _hasFullWeekData(protocol)) {
initialized[protocol] = true;
emit ProtocolInitialized(protocol);
}
emit PriceUpdated(protocol, price, block.timestamp);
}
// ============ APY Calculation (FIXED WITH TIMESTAMPS) ============
/**
* @notice Get APY for an adapter
* @param adapter The adapter address
* @return apy The current APY in basis points
*/
function getAPY(address adapter) external view returns (uint256 apy) {
require(registeredAdapters[adapter], "Adapter not registered");
if (useManualAPY[adapter]) {
return manualAPY[adapter];
}
if (isDirectAPY[adapter]) {
string memory name = nameByAdapter[adapter];
if (keccak256(bytes(name)) == keccak256(bytes("Aave"))) {
return getAaveAPY();
} else if (keccak256(bytes(name)) == keccak256(bytes("Compound"))) {
return getCompoundAPY();
}
}
address vault = adapterToVault[adapter];
require(vault != address(0), "No vault mapping");
return getHistoricalAPY(vault);
}
/**
* @notice Calculate time-weighted APY from historical data
* @dev FIXED: Now uses actual timestamps instead of assuming 7-day spacing
* @param protocol The protocol vault address
* @return apy The calculated APY in basis points
*/
function getHistoricalAPY(address protocol) public view returns (uint256 apy) {
if (!initialized[protocol]) return 0;
uint256 current = currentIndex[protocol];
uint256 weekAgo = (current + 1) % WEEK_SIZE;
PricePoint memory currentPoint = priceHistory[protocol][current];
PricePoint memory oldPoint = priceHistory[protocol][weekAgo];
// Ensure we have valid data
if (oldPoint.price == 0 || currentPoint.price <= oldPoint.price) return 0;
if (oldPoint.timestamp == 0 || currentPoint.timestamp <= oldPoint.timestamp) return 0;
// Calculate actual time elapsed
uint256 timeElapsed = currentPoint.timestamp - oldPoint.timestamp;
// Require at least 6 days of data to prevent manipulation
if (timeElapsed < 6 days) return 0;
// Calculate price change
uint256 priceChange = currentPoint.price - oldPoint.price;
// Calculate return over the period
uint256 periodReturn = (priceChange * 10000) / oldPoint.price;
// Annualize based on actual time elapsed
// APY = (periodReturn * SECONDS_PER_YEAR) / timeElapsed
apy = (periodReturn * SECONDS_PER_YEAR) / timeElapsed;
return apy;
}
function getAaveAPY() public view returns (uint256 apy) {
IAavePool pool = IAavePool(AAVE_POOL);
IAavePool.ReserveData memory data = pool.getReserveData(USDC);
return data.currentLiquidityRate / 1e23;
}
function getCompoundAPY() public view returns (uint256 apy) {
ICompoundComet comet = ICompoundComet(COMPOUND_COMET);
uint256 utilization = comet.getUtilization();
uint256 supplyRate = comet.getSupplyRate(utilization);
return (supplyRate * SECONDS_PER_YEAR) / 1e14;
}
// ============ Initialization Functions ============
/**
* @notice Load historical prices (compatibility function)
* @param protocol The protocol vault address
* @param prices Array of 7 historical prices
*/
function loadHistoricalPrices(address protocol, uint256[7] memory prices) external onlyOwner {
require(protocol != address(0), "Invalid protocol");
require(!initialized[protocol], "Already initialized");
uint256 startTime = block.timestamp - 7 days;
for (uint256 i = 0; i < WEEK_SIZE; i++) {
require(prices[i] > 0, "Invalid price");
priceHistory[protocol][i] = PricePoint({
price: prices[i],
timestamp: startTime + (i * 1 days)
});
}
currentIndex[protocol] = 6;
lastProtocolUpdate[protocol] = block.timestamp - 1 days;
initialized[protocol] = true;
emit HistoricalDataLoaded(protocol, prices);
emit ProtocolInitialized(protocol);
}
/**
* @notice Update daily prices (compatibility function)
*/
function updateDailyPrices() external onlyKeeper whenNotPaused {
// Update known protocols if rate limit allows
if (block.timestamp >= lastProtocolUpdate[MORPHO_VAULT] + MIN_UPDATE_INTERVAL) {
_updatePrice(MORPHO_VAULT);
}
if (block.timestamp >= lastProtocolUpdate[YEARN_VAULT] + MIN_UPDATE_INTERVAL) {
_updatePrice(YEARN_VAULT);
}
if (block.timestamp >= lastProtocolUpdate[VESPER_VAULT] + MIN_UPDATE_INTERVAL) {
_updatePrice(VESPER_VAULT);
}
}
/**
* @notice Manual price update for testing (owner only)
* @param protocol The protocol vault address
* @param price The price to set
*/
function updatePriceManual(address protocol, uint256 price) external onlyOwner {
require(protocol != address(0), "Invalid protocol");
require(price != 0, "Invalid price");
require(!initialized[protocol], "Already initialized");
uint256 idx = currentIndex[protocol];
priceHistory[protocol][idx] = PricePoint({
price: price,
timestamp: block.timestamp
});
currentIndex[protocol] = (idx + 1) % WEEK_SIZE;
// Auto-initialize after 7 manual updates
bool hasFullData = true;
for (uint i = 0; i < WEEK_SIZE; i++) {
if (priceHistory[protocol][i].price == 0) {
hasFullData = false;
break;
}
}
if (hasFullData && !initialized[protocol]) {
initialized[protocol] = true;
emit ProtocolInitialized(protocol);
}
emit PriceUpdated(protocol, price, block.timestamp);
}
/**
* @notice Load historical prices with timestamps (owner only)
* @param protocol The protocol vault address
* @param prices Array of 7 historical prices
* @param timestamps Array of 7 timestamps
*/
function loadHistoricalPricesWithTimestamps(
address protocol,
uint256[7] memory prices,
uint256[7] memory timestamps
) external onlyOwner {
require(protocol != address(0), "Invalid protocol");
require(!initialized[protocol], "Already initialized");
// Validate timestamps are increasing
for (uint256 i = 1; i < WEEK_SIZE; i++) {
require(timestamps[i] > timestamps[i-1], "Timestamps must increase");
require(prices[i] > 0, "Invalid price");
}
// Load data
for (uint256 i = 0; i < WEEK_SIZE; i++) {
priceHistory[protocol][i] = PricePoint({
price: prices[i],
timestamp: timestamps[i]
});
}
currentIndex[protocol] = 6;
lastProtocolUpdate[protocol] = timestamps[6];
initialized[protocol] = true;
emit HistoricalDataLoaded(protocol, prices);
emit ProtocolInitialized(protocol);
}
/**
* @notice Set manual APY override for testing
* @param adapter The adapter address
* @param apy The manual APY in basis points
*/
function setManualAPY(address adapter, uint256 apy) external onlyOwner {
require(registeredAdapters[adapter], "Adapter not registered");
require(apy <= 100000, "APY too high");
manualAPY[adapter] = apy;
useManualAPY[adapter] = true;
emit ManualAPYSet(adapter, apy);
emit ManualAPYToggled(adapter, true);
}
function setUseManualAPY(address adapter, bool useManual) external onlyOwner {
require(registeredAdapters[adapter], "Adapter not registered");
useManualAPY[adapter] = useManual;
emit ManualAPYToggled(adapter, useManual);
}
// ============ View Functions ============
function isInitialized(address protocol) external view returns (bool) {
return initialized[protocol];
}
function getLastUpdateTime(address protocol) external view returns (uint256) {
return lastProtocolUpdate[protocol];
}
function getRegisteredAdapters() external view returns (address[] memory) {
return allAdapters;
}
function canUpdateProtocol(address protocol) external view returns (bool) {
return block.timestamp >= lastProtocolUpdate[protocol] + MIN_UPDATE_INTERVAL;
}
function getPriceHistory(address protocol) external view returns (uint256[7] memory prices) {
for (uint256 i = 0; i < WEEK_SIZE; i++) {
prices[i] = priceHistory[protocol][i].price;
}
return prices;
}
function getPriceHistoryWithTimestamps(address protocol) external view returns (
uint256[7] memory prices,
uint256[7] memory timestamps
) {
for (uint256 i = 0; i < WEEK_SIZE; i++) {
prices[i] = priceHistory[protocol][i].price;
timestamps[i] = priceHistory[protocol][i].timestamp;
}
}
// ============ Internal Functions ============
function _getCurrentPrice(address protocol) private view returns (uint256) {
if (protocol == MORPHO_VAULT) {
return _getMorphoPrice();
} else if (protocol == YEARN_VAULT) {
return _getYearnPrice();
} else if (protocol == VESPER_VAULT) {
return _getVesperPrice();
}
return 0;
}
function _getMorphoPrice() private view returns (uint256) {
IMetaMorpho vault = IMetaMorpho(MORPHO_VAULT);
uint256 totalAssets = vault.totalAssets();
uint256 totalSupply = vault.totalSupply();
if (totalSupply == 0) return PRICE_DECIMALS;
return (totalAssets * PRICE_DECIMALS) / totalSupply;
}
function _getYearnPrice() private view returns (uint256) {
IYearnVault vault = IYearnVault(YEARN_VAULT);
uint256 pricePerShare = vault.pricePerShare();
return pricePerShare * 1e12; // Scale from 6 to 18 decimals
}
function _getVesperPrice() private view returns (uint256) {
IVesperPool pool = IVesperPool(VESPER_VAULT);
uint256 pricePerShare = pool.getPricePerShare();
return pricePerShare * 1e12; // Scale from 6 to 18 decimals
}
function _hasFullWeekData(address protocol) private view returns (bool) {
uint256 oldestTimestamp = priceHistory[protocol][0].timestamp;
uint256 newestTimestamp = priceHistory[protocol][6].timestamp;
// Require at least 6 days of data
if (newestTimestamp - oldestTimestamp < 6 days) return false;
// All prices must be non-zero
for (uint256 i = 0; i < WEEK_SIZE; i++) {
if (priceHistory[protocol][i].price == 0) return false;
}
return true;
}
}
// Minimal interfaces
interface IMetaMorpho {
function totalAssets() external view returns (uint256);
function totalSupply() external view returns (uint256);
}
interface IYearnVault {
function pricePerShare() external view returns (uint256);
}"
},
"src/interfaces/IAPYOracle.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title IAPYOracle
* @notice Interface for the APY Oracle contract that provides APY data for all adapters
* @dev Supports both direct protocol queries and historical price-based calculations
*/
interface IAPYOracle {
// Events
event APYOracleInitialized(address indexed oracle);
event PriceUpdated(address indexed protocol, uint256 price, uint256 timestamp);
event ManualAPYSet(address indexed adapter, uint256 apy);
event ManualAPYToggled(address indexed adapter, bool useManual);
event HistoricalDataLoaded(address indexed protocol, uint256[7] prices);
event ProtocolInitialized(address indexed protocol);
// Errors
error InvalidAddress();
error NotInitialized();
error AlreadyInitialized();
error UpdateTooSoon();
error InvalidPrice();
error InvalidAPY();
error InvalidProtocol();
/**
* @notice Get the current APY for a given adapter
* @param adapter The adapter address to get APY for
* @return apy The current APY in basis points (100 = 1%)
*/
function getAPY(address adapter) external view returns (uint256 apy);
/**
* @notice Get Aave protocol APY directly from the pool
* @return apy The current Aave supply APY in basis points
*/
function getAaveAPY() external view returns (uint256 apy);
/**
* @notice Get Compound protocol APY directly from the comet
* @return apy The current Compound supply APY in basis points
*/
function getCompoundAPY() external view returns (uint256 apy);
/**
* @notice Calculate APY from historical price data
* @param protocol The protocol address to calculate APY for
* @return apy The calculated APY based on 7-day price history
*/
function getHistoricalAPY(address protocol) external view returns (uint256 apy);
/**
* @notice Update price for a protocol (keeper function)
* @param protocol The protocol address to update price for
*/
function updateProtocolPrice(address protocol) external;
/**
* @notice Manually update price for testing
* @param protocol The protocol address
* @param price The new price to set
*/
function updatePriceManual(address protocol, uint256 price) external;
/**
* @notice Load historical prices for initialization
* @param protocol The protocol address
* @param prices Array of 7 historical prices (oldest to newest)
*/
function loadHistoricalPrices(address protocol, uint256[7] memory prices) external;
/**
* @notice Set manual APY override for testing
* @param adapter The adapter address
* @param apy The manual APY to set
*/
function setManualAPY(address adapter, uint256 apy) external;
/**
* @notice Toggle manual APY override
* @param adapter The adapter address
* @param useManual Whether to use manual APY
*/
function setUseManualAPY(address adapter, bool useManual) external;
/**
* @notice Check if a protocol is initialized with price history
* @param protocol The protocol address to check
* @return initialized Whether the protocol has been initialized
*/
function isInitialized(address protocol) external view returns (bool initialized);
/**
* @notice Get the last update timestamp for a protocol
* @param protocol The protocol address
* @return timestamp The last update timestamp
*/
function getLastUpdateTime(address protocol) external view returns (uint256 timestamp);
/**
* @notice Get the current price history for a protocol
* @param protocol The protocol address
* @return prices The 7-day price history array
*/
function getPriceHistory(address protocol) external view returns (uint256[7] memory prices);
/**
* @notice Update prices for all protocols (keeper batch function)
*/
function updateDailyPrices() external;
}"
},
"src/interfaces/external/IAavePool.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface IAavePool {
struct ReserveData {
uint256 configuration;
uint128 liquidityIndex;
uint128 currentLiquidityRate;
uint128 variableBorrowIndex;
uint128 currentVariableBorrowRate;
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
uint16 id;
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
uint128 accruedToTreasury;
uint128 unbacked;
uint128 isolationModeTotalDebt;
}
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
function getReserveData(address asset) external view returns (ReserveData memory);
}
interface IAToken {
function balanceOf(address user) external view returns (uint256);
function scaledBalanceOf(address user) external view returns (uint256);
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
function totalSupply() external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
}"
},
"src/interfaces/external/ICompoundComet.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface ICompoundComet {
function supply(address asset, uint256 amount) external;
function withdraw(address asset, uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
function getUtilization() external view returns (uint256);
function getSupplyRate(uint256 utilization) external view returns (uint256);
function baseTokenPriceFeed() external view returns (address);
function numAssets() external view returns (uint8);
function getAssetInfo(uint8 i) external view returns (AssetInfo memory);
function totalsBasic() external view returns (TotalsBasic memory);
struct AssetInfo {
uint8 offset;
address asset;
address priceFeed;
uint64 scale;
uint64 borrowCollateralFactor;
uint64 liquidateCollateralFactor;
uint64 liquidationFactor;
uint128 supplyCap;
}
struct TotalsBasic {
uint64 baseSupplyIndex;
uint64 baseBorrowIndex;
uint64 trackingSupplyIndex;
uint64 trackingBorrowIndex;
uint104 totalSupplyBase;
uint104 totalBorrowBase;
uint40 lastAccrualTime;
uint8 pauseFlags;
}
}"
},
"src/interfaces/IVesperPool.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
/**
* @title IVesperPool
* @notice Interface for Vesper Finance pool contracts
* @dev Vesper uses 18 decimals internally for all calculations
*/
interface IVesperPool {
/**
* @notice Deposit underlying tokens and receive pool shares
* @param amount Amount of underlying tokens to deposit
*/
function deposit(uint256 amount) external;
/**
* @notice Withdraw by burning pool shares
* @param shares Amount of pool shares to burn
* @dev Note: This takes share amount, not underlying amount
*/
function withdraw(uint256 shares) external;
/**
* @notice Get the current price per share
* @return Price per share in 18 decimals
*/
function getPricePerShare() external view returns (uint256);
/**
* @notice Get the total value of all assets in the pool
* @return Total value in underlying token decimals
*/
function totalValue() external view returns (uint256);
/**
* @notice Get the total supply of pool shares
* @return Total supply of shares
*/
function totalSupply() external view returns (uint256);
/**
* @notice Get the balance of pool shares for an account
* @param account Address to check balance for
* @return Balance of pool shares
*/
function balanceOf(address account) external view returns (uint256);
/**
* @notice Convert underlying amount to 18 decimals
* @param amount Amount in underlying token decimals
* @return Amount in 18 decimals
*/
function convertTo18(uint256 amount) external view returns (uint256);
/**
* @notice Convert from 18 decimals to underlying decimals
* @param amount Amount in 18 decimals
* @return Amount in underlying token decimals
*/
function convertFrom18(uint256 amount) external view returns (uint256);
/**
* @notice Get the underlying token address
* @return Address of the underlying token
*/
function token() external view returns (address);
}"
}
},
"settings": {
"remappings": [
"forge-std/=lib/forge-std/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 100
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}
}}
Submitted on: 2025-10-18 12:55:33
Comments
Log in to comment.
No comments yet.