SimpleOracle

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "smart-contracts-public/src/pricing/oracles/SimpleOracle.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import "../../external/AggregatorV3Interface.sol";
import "../../pricing/IPriceOracle.sol";

/**
 * @title SimpleOracle
 * @notice Direct Chainlink price feed wrapper for any asset (stable or volatile)
 * @dev Handles staleness checks and optional price bounds for stablecoins
 *      Returns prices in WAD format (18 decimals) for direct use
 */
contract SimpleOracle is IPriceOracle {
    // Custom errors
    error InvalidPriceFeed();
    error InvalidStalenessPeriod();
    error InvalidPriceBounds();

    // Constants
    uint256 private constant WAD = 1e18;

    // Immutable state
    AggregatorV3Interface public immutable priceFeed;
    uint32 public immutable stalenessPeriod;
    uint256 public immutable minPrice; // 0 = no minimum
    uint256 public immutable maxPrice; // 0 = no maximum

    /**
     * @param _priceFeed Chainlink price feed address
     * @param _stalenessPeriod Maximum age of price data in seconds
     * @param _minPrice Minimum acceptable price in WAD format (0 for no minimum)
     * @param _maxPrice Maximum acceptable price in WAD format (0 for no maximum)
     */
    constructor(address _priceFeed, uint32 _stalenessPeriod, uint256 _minPrice, uint256 _maxPrice) {
        if (_priceFeed == address(0)) revert InvalidPriceFeed();
        if (_stalenessPeriod == 0) revert InvalidStalenessPeriod();
        if (_minPrice > _maxPrice && _maxPrice != 0) revert InvalidPriceBounds();

        priceFeed = AggregatorV3Interface(_priceFeed);
        stalenessPeriod = _stalenessPeriod;
        minPrice = _minPrice;
        maxPrice = _maxPrice;
    }

    /**
     * @notice Get latest price with validation
     * @return PriceInfo containing price in WAD format (18 decimals) and status
     */
    function latestPriceInfo() external view override returns (PriceInfo memory) {
        (uint80 roundId, int256 price,, uint256 updatedAt, uint80 answeredInRound) =
            priceFeed.latestRoundData();

        // Check staleness
        if (block.timestamp - updatedAt > stalenessPeriod) {
            return PriceInfo(0, PriceStatus.STALE);
        }

        // Check for invalid price or stale round
        if (price <= 0 || answeredInRound < roundId) {
            return PriceInfo(0, PriceStatus.INVALID);
        }

        // Get actual decimals from the price feed
        uint8 feedDecimals = priceFeed.decimals();

        // Scale price to WAD (18 decimals) based on actual feed decimals
        uint256 wadPrice;
        if (feedDecimals <= 18) {
            wadPrice = uint256(price) * (10 ** (18 - feedDecimals));
        } else {
            wadPrice = uint256(price) / (10 ** (feedDecimals - 18));
        }

        // Check minimum bound (if set) - bounds are now in WAD format
        if (minPrice > 0 && wadPrice < minPrice) {
            return PriceInfo(0, PriceStatus.INVALID);
        }

        // Check maximum bound and cap if needed (if set) - bounds are in WAD format
        if (maxPrice > 0 && wadPrice > maxPrice) {
            return PriceInfo(maxPrice, PriceStatus.CAPPED);
        }

        return PriceInfo(wadPrice, PriceStatus.VALID);
    }

    /**
     * @notice Get price decimals (always 18 for WAD format)
     * @return Always returns 18 as prices are in WAD format
     */
    function decimals() external pure override returns (uint8) {
        return 18;
    }
}
"
    },
    "smart-contracts-public/src/external/AggregatorV3Interface.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

interface AggregatorV3Interface {
    function decimals() external view returns (uint8);

    function description() external view returns (string memory);

    function version() external view returns (uint256);

    function getRoundData(uint80 _roundId)
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );
}
"
    },
    "smart-contracts-public/src/pricing/IPriceOracle.sol": {
      "content": "pragma solidity 0.8.30;

/**
 * @title IPriceOracle
 * @notice Standardized price oracle interface returning WAD‑scaled prices with a status code.
 * @dev Prices MUST be scaled to 1e18 (WAD). Implementations can surface status information such as
 * validity, staleness, capping, or circuit breaker activation.
 */
interface IPriceOracle {
    enum PriceStatus {
        VALID,
        CAPPED,
        INVALID,
        STALE,
        VOLATILE,
        CIRCUIT_BREAKER
    }

    struct PriceInfo {
        uint256 price;
        PriceStatus status;
    }

    /**
     * @notice Retrieves the latest price information for the configured token
     * @return PriceInfo Struct containing the price and its status
     */
    function latestPriceInfo() external view returns (PriceInfo memory);

    /**
     * @notice Retrieves the number of decimals for the token's price feed
     * @return uint8 Number of decimals
     */
    function decimals() external view returns (uint8);
}
"
    }
  },
  "settings": {
    "remappings": [
      "@chainlink/=smart-contracts-public/lib/chainlink/",
      "@openzeppelin/contracts/=smart-contracts-public/lib/openzeppelin-contracts/contracts/",
      "@openzeppelin/contracts-upgradeable/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/contracts/",
      "forge-std/=smart-contracts-public/lib/forge-std/src/",
      "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
      "chainlink/=smart-contracts-public/lib/chainlink/",
      "erc4626-tests/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
      "halmos-cheatcodes/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts-upgradeable/=smart-contracts-public/lib/openzeppelin-contracts-upgradeable/",
      "openzeppelin-contracts/=smart-contracts-public/lib/openzeppelin-contracts/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 500
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": true
  }
}}

Tags:
Proxy, Upgradeable, Factory, Oracle|addr:0x906a94ca3275243459fdb22324b242be4c65c87c|verified:true|block:23477486|tx:0x91ee7f1c9550d656f5a11f5a2b29c05068d65f1a70e29957aa69e41b3709e0c9|first_check:1759255678

Submitted on: 2025-09-30 20:07:58

Comments

Log in to comment.

No comments yet.