ETH Price: $2,416.06 (-0.01%)

Contract

0xbE19cC5654e30dAF04AD3B5E06213D70F4e882eE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Cache Decimals180323132023-08-31 4:57:23401 days ago1693457843IN
0xbE19cC56...0F4e882eE
0 ETH0.0007763516.31400115
Cache Decimals180323102023-08-31 4:56:47401 days ago1693457807IN
0xbE19cC56...0F4e882eE
0 ETH0.0008384615.83602361
Cache Decimals180323072023-08-31 4:56:11401 days ago1693457771IN
0xbE19cC56...0F4e882eE
0 ETH0.0008204215.48235088
Cache Decimals180323042023-08-31 4:55:35401 days ago1693457735IN
0xbE19cC56...0F4e882eE
0 ETH0.0008188815.42774104
Cache Decimals180323012023-08-31 4:54:59401 days ago1693457699IN
0xbE19cC56...0F4e882eE
0 ETH0.0008195215.44577248
0x60806040180322982023-08-31 4:54:23401 days ago1693457663IN
 Create: OETHOracleRouter
0 ETH0.0124427723.51163053

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
OETHOracleRouter

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 8 : OracleRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../interfaces/chainlink/AggregatorV3Interface.sol";
import { IOracle } from "../interfaces/IOracle.sol";
import { Helpers } from "../utils/Helpers.sol";
import { StableMath } from "../utils/StableMath.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

// @notice Abstract functionality that is shared between various Oracle Routers
abstract contract OracleRouterBase is IOracle {
    using StableMath for uint256;
    using SafeCast for int256;

    uint256 internal constant MIN_DRIFT = 0.7e18;
    uint256 internal constant MAX_DRIFT = 1.3e18;
    address internal constant FIXED_PRICE =
        0x0000000000000000000000000000000000000001;
    // Maximum allowed staleness buffer above normal Oracle maximum staleness
    uint256 internal constant STALENESS_BUFFER = 1 days;
    mapping(address => uint8) internal decimalsCache;

    /**
     * @dev The price feed contract to use for a particular asset along with
     *      maximum data staleness
     * @param asset address of the asset
     * @return feedAddress address of the price feed for the asset
     * @return maxStaleness maximum acceptable data staleness duration
     */
    function feedMetadata(address asset)
        internal
        view
        virtual
        returns (address feedAddress, uint256 maxStaleness);

    /**
     * @notice Returns the total price in 18 digit unit for a given asset.
     * @param asset address of the asset
     * @return uint256 unit price for 1 asset unit, in 18 decimal fixed
     */
    function price(address asset)
        external
        view
        virtual
        override
        returns (uint256)
    {
        (address _feed, uint256 maxStaleness) = feedMetadata(asset);
        require(_feed != address(0), "Asset not available");
        require(_feed != FIXED_PRICE, "Fixed price feeds not supported");

        (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)
            .latestRoundData();

        require(
            updatedAt + maxStaleness >= block.timestamp,
            "Oracle price too old"
        );

        uint8 decimals = getDecimals(_feed);

        uint256 _price = _iprice.toUint256().scaleBy(18, decimals);
        if (shouldBePegged(asset)) {
            require(_price <= MAX_DRIFT, "Oracle: Price exceeds max");
            require(_price >= MIN_DRIFT, "Oracle: Price under min");
        }
        return _price;
    }

    function getDecimals(address _feed) internal view virtual returns (uint8) {
        uint8 decimals = decimalsCache[_feed];
        require(decimals > 0, "Oracle: Decimals not cached");
        return decimals;
    }

    /**
     * @notice Before an asset/feed price is fetches for the first time the
     *         decimals need to be cached. This is a gas optimization
     * @param asset address of the asset
     * @return uint8 corresponding asset decimals
     */
    function cacheDecimals(address asset) external returns (uint8) {
        (address _feed, ) = feedMetadata(asset);
        require(_feed != address(0), "Asset not available");
        require(_feed != FIXED_PRICE, "Fixed price feeds not supported");

        uint8 decimals = AggregatorV3Interface(_feed).decimals();
        decimalsCache[_feed] = decimals;
        return decimals;
    }

    function shouldBePegged(address _asset) internal view returns (bool) {
        string memory symbol = Helpers.getSymbol(_asset);
        bytes32 symbolHash = keccak256(abi.encodePacked(symbol));
        return
            symbolHash == keccak256(abi.encodePacked("DAI")) ||
            symbolHash == keccak256(abi.encodePacked("USDC")) ||
            symbolHash == keccak256(abi.encodePacked("USDT"));
    }
}

// @notice Oracle Router that denominates all prices in USD
contract OracleRouter is OracleRouterBase {
    /**
     * @dev The price feed contract to use for a particular asset along with
     *      maximum data staleness
     * @param asset address of the asset
     * @return feedAddress address of the price feed for the asset
     * @return maxStaleness maximum acceptable data staleness duration
     */
    function feedMetadata(address asset)
        internal
        pure
        virtual
        override
        returns (address feedAddress, uint256 maxStaleness)
    {
        /* + STALENESS_BUFFER is added in case Oracle for some reason doesn't
         * update on heartbeat and we add a generous buffer amount.
         */
        if (asset == 0x6B175474E89094C44Da98b954EedeAC495271d0F) {
            // https://data.chain.link/ethereum/mainnet/stablecoins/dai-usd
            // Chainlink: DAI/USD
            feedAddress = 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9;
            maxStaleness = 1 hours + STALENESS_BUFFER;
        } else if (asset == 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48) {
            // https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd
            // Chainlink: USDC/USD
            feedAddress = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0xdAC17F958D2ee523a2206206994597C13D831ec7) {
            // https://data.chain.link/ethereum/mainnet/stablecoins/usdt-usd
            // Chainlink: USDT/USD
            feedAddress = 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0xc00e94Cb662C3520282E6f5717214004A7f26888) {
            // https://data.chain.link/ethereum/mainnet/crypto-usd/comp-usd
            // Chainlink: COMP/USD
            feedAddress = 0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5;
            maxStaleness = 1 hours + STALENESS_BUFFER;
        } else if (asset == 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9) {
            // https://data.chain.link/ethereum/mainnet/crypto-usd/aave-usd
            // Chainlink: AAVE/USD
            feedAddress = 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9;
            maxStaleness = 1 hours + STALENESS_BUFFER;
        } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {
            // https://data.chain.link/ethereum/mainnet/crypto-usd/crv-usd
            // Chainlink: CRV/USD
            feedAddress = 0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33f;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {
            // Chainlink: CVX/USD
            feedAddress = 0xd962fC30A72A84cE50161031391756Bf2876Af5D;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else {
            revert("Asset not available");
        }
    }
}

// @notice Oracle Router that denominates all prices in ETH
contract OETHOracleRouter is OracleRouter {
    using StableMath for uint256;

    /**
     * @notice Returns the total price in 18 digit units for a given asset.
     *         This implementation does not (!) do range checks as the
     *         parent OracleRouter does.
     * @param asset address of the asset
     * @return uint256 unit price for 1 asset unit, in 18 decimal fixed
     */
    function price(address asset)
        external
        view
        virtual
        override
        returns (uint256)
    {
        (address _feed, uint256 maxStaleness) = feedMetadata(asset);
        if (_feed == FIXED_PRICE) {
            return 1e18;
        }
        require(_feed != address(0), "Asset not available");

        (, int256 _iprice, , uint256 updatedAt, ) = AggregatorV3Interface(_feed)
            .latestRoundData();

        require(
            updatedAt + maxStaleness >= block.timestamp,
            "Oracle price too old"
        );

        uint8 decimals = getDecimals(_feed);
        uint256 _price = uint256(_iprice).scaleBy(18, decimals);
        return _price;
    }

    /**
     * @dev The price feed contract to use for a particular asset along with
     *      maximum data staleness
     * @param asset address of the asset
     * @return feedAddress address of the price feed for the asset
     * @return maxStaleness maximum acceptable data staleness duration
     */
    function feedMetadata(address asset)
        internal
        pure
        virtual
        override
        returns (address feedAddress, uint256 maxStaleness)
    {
        if (asset == 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2) {
            // FIXED_PRICE: WETH/ETH
            feedAddress = FIXED_PRICE;
            maxStaleness = 0;
        } else if (asset == 0x5E8422345238F34275888049021821E8E08CAa1f) {
            // frxETH/ETH
            feedAddress = 0xC58F3385FBc1C8AD2c0C9a061D7c13b141D7A5Df;
            maxStaleness = 18 hours + STALENESS_BUFFER;
        } else if (asset == 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) {
            // https://data.chain.link/ethereum/mainnet/crypto-eth/steth-eth
            // Chainlink: stETH/ETH
            feedAddress = 0x86392dC19c0b719886221c78AB11eb8Cf5c52812;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0xae78736Cd615f374D3085123A210448E74Fc6393) {
            // https://data.chain.link/ethereum/mainnet/crypto-eth/reth-eth
            // Chainlink: rETH/ETH
            feedAddress = 0x536218f9E9Eb48863970252233c8F271f554C2d0;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0xD533a949740bb3306d119CC777fa900bA034cd52) {
            // https://data.chain.link/ethereum/mainnet/crypto-eth/crv-eth
            // Chainlink: CRV/ETH
            feedAddress = 0x8a12Be339B0cD1829b91Adc01977caa5E9ac121e;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B) {
            // https://data.chain.link/ethereum/mainnet/crypto-eth/cvx-eth
            // Chainlink: CVX/ETH
            feedAddress = 0xC9CbF687f43176B302F03f5e58470b77D07c61c6;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else if (asset == 0xBe9895146f7AF43049ca1c1AE358B0541Ea49704) {
            // https://data.chain.link/ethereum/mainnet/crypto-eth/cbeth-eth
            // Chainlink: cbETH/ETH
            feedAddress = 0xF017fcB346A1885194689bA23Eff2fE6fA5C483b;
            maxStaleness = 1 days + STALENESS_BUFFER;
        } else {
            revert("Asset not available");
        }
    }
}

File 2 of 8 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)

pragma solidity ^0.8.0;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 3 of 8 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 4 of 8 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

    function version() external view returns (uint256);

    // getRoundData and latestRoundData should both raise "No data present"
    // if they do not have data to report, instead of returning unset values
    // which could be misinterpreted as actual reported values.
    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
        );
}

File 5 of 8 : IBasicToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IBasicToken {
    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);
}

File 6 of 8 : IOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IOracle {
    /**
     * @dev returns the asset price in USD, in 8 decimal digits.
     *
     * The version of priceProvider deployed for OETH has 18 decimal digits
     */
    function price(address asset) external view returns (uint256);
}

File 7 of 8 : Helpers.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { IBasicToken } from "../interfaces/IBasicToken.sol";

library Helpers {
    /**
     * @notice Fetch the `symbol()` from an ERC20 token
     * @dev Grabs the `symbol()` from a contract
     * @param _token Address of the ERC20 token
     * @return string Symbol of the ERC20 token
     */
    function getSymbol(address _token) internal view returns (string memory) {
        string memory symbol = IBasicToken(_token).symbol();
        return symbol;
    }

    /**
     * @notice Fetch the `decimals()` from an ERC20 token
     * @dev Grabs the `decimals()` from a contract and fails if
     *      the decimal value does not live within a certain range
     * @param _token Address of the ERC20 token
     * @return uint256 Decimals of the ERC20 token
     */
    function getDecimals(address _token) internal view returns (uint256) {
        uint256 decimals = IBasicToken(_token).decimals();
        require(
            decimals >= 4 && decimals <= 18,
            "Token must have sufficient decimal places"
        );

        return decimals;
    }
}

File 8 of 8 : StableMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";

// Based on StableMath from Stability Labs Pty. Ltd.
// https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol

library StableMath {
    using SafeMath for uint256;

    /**
     * @dev Scaling unit for use in specific calculations,
     * where 1 * 10**18, or 1e18 represents a unit '1'
     */
    uint256 private constant FULL_SCALE = 1e18;

    /***************************************
                    Helpers
    ****************************************/

    /**
     * @dev Adjust the scale of an integer
     * @param to Decimals to scale to
     * @param from Decimals to scale from
     */
    function scaleBy(
        uint256 x,
        uint256 to,
        uint256 from
    ) internal pure returns (uint256) {
        if (to > from) {
            x = x.mul(10**(to - from));
        } else if (to < from) {
            // slither-disable-next-line divide-before-multiply
            x = x.div(10**(from - to));
        }
        return x;
    }

    /***************************************
               Precise Arithmetic
    ****************************************/

    /**
     * @dev Multiplies two precise units, and then truncates by the full scale
     * @param x Left hand input to multiplication
     * @param y Right hand input to multiplication
     * @return Result after multiplying the two inputs and then dividing by the shared
     *         scale unit
     */
    function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulTruncateScale(x, y, FULL_SCALE);
    }

    /**
     * @dev Multiplies two precise units, and then truncates by the given scale. For example,
     * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18
     * @param x Left hand input to multiplication
     * @param y Right hand input to multiplication
     * @param scale Scale unit
     * @return Result after multiplying the two inputs and then dividing by the shared
     *         scale unit
     */
    function mulTruncateScale(
        uint256 x,
        uint256 y,
        uint256 scale
    ) internal pure returns (uint256) {
        // e.g. assume scale = fullScale
        // z = 10e18 * 9e17 = 9e36
        uint256 z = x.mul(y);
        // return 9e36 / 1e18 = 9e18
        return z.div(scale);
    }

    /**
     * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result
     * @param x Left hand input to multiplication
     * @param y Right hand input to multiplication
     * @return Result after multiplying the two inputs and then dividing by the shared
     *          scale unit, rounded up to the closest base unit.
     */
    function mulTruncateCeil(uint256 x, uint256 y)
        internal
        pure
        returns (uint256)
    {
        // e.g. 8e17 * 17268172638 = 138145381104e17
        uint256 scaled = x.mul(y);
        // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17
        uint256 ceil = scaled.add(FULL_SCALE.sub(1));
        // e.g. 13814538111.399...e18 / 1e18 = 13814538111
        return ceil.div(FULL_SCALE);
    }

    /**
     * @dev Precisely divides two units, by first scaling the left hand operand. Useful
     *      for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)
     * @param x Left hand input to division
     * @param y Right hand input to division
     * @return Result after multiplying the left operand by the scale, and
     *         executing the division on the right hand input.
     */
    function divPrecisely(uint256 x, uint256 y)
        internal
        pure
        returns (uint256)
    {
        // e.g. 8e18 * 1e18 = 8e36
        uint256 z = x.mul(FULL_SCALE);
        // e.g. 8e36 / 10e18 = 8e17
        return z.div(y);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"cacheDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b5061089c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806336b6d9441461003b578063aea9107814610065575b600080fd5b61004e61004936600461062c565b610086565b60405160ff90911681526020015b60405180910390f35b61007861007336600461062c565b6101bf565b60405190815260200161005c565b60008061009283610312565b5090506001600160a01b0381166100c45760405162461bcd60e51b81526004016100bb906106c8565b60405180910390fd5b6001600160a01b0381166001141561011e5760405162461bcd60e51b815260206004820152601f60248201527f4669786564207072696365206665656473206e6f7420737570706f727465640060448201526064016100bb565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561015957600080fd5b505afa15801561016d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019191906106a5565b6001600160a01b03929092166000908152602081905260409020805460ff191660ff84161790555092915050565b60008060006101cd84610312565b90925090506001600160a01b038216600114156101f55750670de0b6b3a76400009392505050565b6001600160a01b03821661021b5760405162461bcd60e51b81526004016100bb906106c8565b600080836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561025757600080fd5b505afa15801561026b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028f9190610655565b509350509250504283826102a391906106f5565b10156102e85760405162461bcd60e51b815260206004820152601460248201527313dc9858db19481c1c9a58d9481d1bdbc81bdb1960621b60448201526064016100bb565b60006102f38561051d565b9050600061030684601260ff851661058c565b98975050505050505050565b60008073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03841614156103465750600190506000915091565b735e8422345238f34275888049021821e8e08caa1f6001600160a01b03841614156103985773c58f3385fbc1c8ad2c0c9a061d7c13b141d7a5df91506103916201518061fd206106f5565b9050915091565b73ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b03841614156103e1577386392dc19c0b719886221c78ab11eb8cf5c52812915061039162015180806106f5565b73ae78736cd615f374d3085123a210448e74fc63936001600160a01b038416141561042a5773536218f9e9eb48863970252233c8f271f554c2d0915061039162015180806106f5565b73d533a949740bb3306d119cc777fa900ba034cd526001600160a01b038416141561047357738a12be339b0cd1829b91adc01977caa5e9ac121e915061039162015180806106f5565b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b03841614156104bc5773c9cbf687f43176b302f03f5e58470b77d07c61c6915061039162015180806106f5565b73be9895146f7af43049ca1c1ae358b0541ea497046001600160a01b03841614156105055773f017fcb346a1885194689ba23eff2fe6fa5c483b915061039162015180806106f5565b60405162461bcd60e51b81526004016100bb906106c8565b6001600160a01b03811660009081526020819052604081205460ff16806105865760405162461bcd60e51b815260206004820152601b60248201527f4f7261636c653a20446563696d616c73206e6f7420636163686564000000000060448201526064016100bb565b92915050565b6000818311156105bc576105b56105a38385610839565b6105ae90600a610772565b85906105ee565b93506105e6565b818310156105e6576105e36105d18484610839565b6105dc90600a610772565b8590610601565b93505b509192915050565b60006105fa828461081a565b9392505050565b60006105fa828461070d565b805169ffffffffffffffffffff8116811461062757600080fd5b919050565b60006020828403121561063e57600080fd5b81356001600160a01b03811681146105fa57600080fd5b600080600080600060a0868803121561066d57600080fd5b6106768661060d565b94506020860151935060408601519250606086015191506106996080870161060d565b90509295509295909350565b6000602082840312156106b757600080fd5b815160ff811681146105fa57600080fd5b6020808252601390820152724173736574206e6f7420617661696c61626c6560681b604082015260600190565b6000821982111561070857610708610850565b500190565b60008261072a57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561076a57816000190482111561075057610750610850565b8085161561075d57918102915b93841c9390800290610734565b509250929050565b60006105fa838360008261078857506001610586565b8161079557506000610586565b81600181146107ab57600281146107b5576107d1565b6001915050610586565b60ff8411156107c6576107c6610850565b50506001821b610586565b5060208310610133831016604e8410600b84101617156107f4575081810a610586565b6107fe838361072f565b806000190482111561081257610812610850565b029392505050565b600081600019048311821515161561083457610834610850565b500290565b60008282101561084b5761084b610850565b500390565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220b66fc794fbca0536355abd67a782ac6a9194aaf7601c2523f308f0dd208ba4a664736f6c63430008070033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100365760003560e01c806336b6d9441461003b578063aea9107814610065575b600080fd5b61004e61004936600461062c565b610086565b60405160ff90911681526020015b60405180910390f35b61007861007336600461062c565b6101bf565b60405190815260200161005c565b60008061009283610312565b5090506001600160a01b0381166100c45760405162461bcd60e51b81526004016100bb906106c8565b60405180910390fd5b6001600160a01b0381166001141561011e5760405162461bcd60e51b815260206004820152601f60248201527f4669786564207072696365206665656473206e6f7420737570706f727465640060448201526064016100bb565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561015957600080fd5b505afa15801561016d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019191906106a5565b6001600160a01b03929092166000908152602081905260409020805460ff191660ff84161790555092915050565b60008060006101cd84610312565b90925090506001600160a01b038216600114156101f55750670de0b6b3a76400009392505050565b6001600160a01b03821661021b5760405162461bcd60e51b81526004016100bb906106c8565b600080836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561025757600080fd5b505afa15801561026b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028f9190610655565b509350509250504283826102a391906106f5565b10156102e85760405162461bcd60e51b815260206004820152601460248201527313dc9858db19481c1c9a58d9481d1bdbc81bdb1960621b60448201526064016100bb565b60006102f38561051d565b9050600061030684601260ff851661058c565b98975050505050505050565b60008073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03841614156103465750600190506000915091565b735e8422345238f34275888049021821e8e08caa1f6001600160a01b03841614156103985773c58f3385fbc1c8ad2c0c9a061d7c13b141d7a5df91506103916201518061fd206106f5565b9050915091565b73ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b03841614156103e1577386392dc19c0b719886221c78ab11eb8cf5c52812915061039162015180806106f5565b73ae78736cd615f374d3085123a210448e74fc63936001600160a01b038416141561042a5773536218f9e9eb48863970252233c8f271f554c2d0915061039162015180806106f5565b73d533a949740bb3306d119cc777fa900ba034cd526001600160a01b038416141561047357738a12be339b0cd1829b91adc01977caa5e9ac121e915061039162015180806106f5565b734e3fbd56cd56c3e72c1403e103b45db9da5b9d2b6001600160a01b03841614156104bc5773c9cbf687f43176b302f03f5e58470b77d07c61c6915061039162015180806106f5565b73be9895146f7af43049ca1c1ae358b0541ea497046001600160a01b03841614156105055773f017fcb346a1885194689ba23eff2fe6fa5c483b915061039162015180806106f5565b60405162461bcd60e51b81526004016100bb906106c8565b6001600160a01b03811660009081526020819052604081205460ff16806105865760405162461bcd60e51b815260206004820152601b60248201527f4f7261636c653a20446563696d616c73206e6f7420636163686564000000000060448201526064016100bb565b92915050565b6000818311156105bc576105b56105a38385610839565b6105ae90600a610772565b85906105ee565b93506105e6565b818310156105e6576105e36105d18484610839565b6105dc90600a610772565b8590610601565b93505b509192915050565b60006105fa828461081a565b9392505050565b60006105fa828461070d565b805169ffffffffffffffffffff8116811461062757600080fd5b919050565b60006020828403121561063e57600080fd5b81356001600160a01b03811681146105fa57600080fd5b600080600080600060a0868803121561066d57600080fd5b6106768661060d565b94506020860151935060408601519250606086015191506106996080870161060d565b90509295509295909350565b6000602082840312156106b757600080fd5b815160ff811681146105fa57600080fd5b6020808252601390820152724173736574206e6f7420617661696c61626c6560681b604082015260600190565b6000821982111561070857610708610850565b500190565b60008261072a57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561076a57816000190482111561075057610750610850565b8085161561075d57918102915b93841c9390800290610734565b509250929050565b60006105fa838360008261078857506001610586565b8161079557506000610586565b81600181146107ab57600281146107b5576107d1565b6001915050610586565b60ff8411156107c6576107c6610850565b50506001821b610586565b5060208310610133831016604e8410600b84101617156107f4575081810a610586565b6107fe838361072f565b806000190482111561081257610812610850565b029392505050565b600081600019048311821515161561083457610834610850565b500290565b60008282101561084b5761084b610850565b500390565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220b66fc794fbca0536355abd67a782ac6a9194aaf7601c2523f308f0dd208ba4a664736f6c63430008070033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.