Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
ChainlinkOracle
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 999999 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.8.21; import {IChainlinkOracle} from "./interfaces/IChainlinkOracle.sol"; import {IOracle} from "../lib/morpho-blue/src/interfaces/IOracle.sol"; import {AggregatorV3Interface, ChainlinkDataFeedLib} from "./libraries/ChainlinkDataFeedLib.sol"; import {IERC4626, VaultLib} from "./libraries/VaultLib.sol"; import {ErrorsLib} from "./libraries/ErrorsLib.sol"; import {Math} from "../lib/openzeppelin-contracts/contracts/utils/math/Math.sol"; /// @title ChainlinkOracle /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Morpho Blue oracle using Chainlink-compliant feeds. contract ChainlinkOracle is IChainlinkOracle { using Math for uint256; using VaultLib for IERC4626; using ChainlinkDataFeedLib for AggregatorV3Interface; /* IMMUTABLES */ /// @inheritdoc IChainlinkOracle IERC4626 public immutable VAULT; /// @inheritdoc IChainlinkOracle uint256 public immutable VAULT_CONVERSION_SAMPLE; /// @inheritdoc IChainlinkOracle AggregatorV3Interface public immutable BASE_FEED_1; /// @inheritdoc IChainlinkOracle AggregatorV3Interface public immutable BASE_FEED_2; /// @inheritdoc IChainlinkOracle AggregatorV3Interface public immutable QUOTE_FEED_1; /// @inheritdoc IChainlinkOracle AggregatorV3Interface public immutable QUOTE_FEED_2; /// @inheritdoc IChainlinkOracle uint256 public immutable SCALE_FACTOR; /* CONSTRUCTOR */ /// @dev Here is the list of assumptions that guarantees the oracle behaves as expected: /// - Feeds are either Chainlink-compliant or the address zero. /// - Feeds have the same behavioral assumptions as Chainlink's. /// - Feeds are set in the correct order. /// - Decimals passed as argument are correct. /// - The vault's sample shares quoted as assets and the base feed prices don't overflow when multiplied. /// - The quote feed prices don't overflow when multiplied. /// - The vault, if set, is ERC4626-compliant. /// @param vault Vault. Pass address zero to omit this parameter. /// @param baseFeed1 First base feed. Pass address zero if the price = 1. /// @param baseFeed2 Second base feed. Pass address zero if the price = 1. /// @param quoteFeed1 First quote feed. Pass address zero if the price = 1. /// @param quoteFeed2 Second quote feed. Pass address zero if the price = 1. /// @param vaultConversionSample The sample amount of vault shares used to convert to the underlying asset. /// Pass 1 if the oracle does not use a vault. Should be chosen such that converting `vaultConversionSample` to /// assets has enough precision. /// @param baseTokenDecimals Base token decimals. /// @param quoteTokenDecimals Quote token decimals. constructor( IERC4626 vault, AggregatorV3Interface baseFeed1, AggregatorV3Interface baseFeed2, AggregatorV3Interface quoteFeed1, AggregatorV3Interface quoteFeed2, uint256 vaultConversionSample, uint256 baseTokenDecimals, uint256 quoteTokenDecimals ) { // The ERC4626 vault parameter is used to price `VAULT_CONVERSION_SAMPLE` of its shares, so it requires dividing // by that number, hence the division by `VAULT_CONVERSION_SAMPLE` in the `SCALE_FACTOR` definition. // Verify that vault = address(0) => vaultConversionSample = 1. require( address(vault) != address(0) || vaultConversionSample == 1, ErrorsLib.VAULT_CONVERSION_SAMPLE_IS_NOT_ONE ); require(vaultConversionSample != 0, ErrorsLib.VAULT_CONVERSION_SAMPLE_IS_ZERO); VAULT = vault; VAULT_CONVERSION_SAMPLE = vaultConversionSample; BASE_FEED_1 = baseFeed1; BASE_FEED_2 = baseFeed2; QUOTE_FEED_1 = quoteFeed1; QUOTE_FEED_2 = quoteFeed2; // In the following comment, we explain the general case (where we assume that no feed is the address zero) // how to scale the output price as Morpho Blue expects, given the input feed prices. // Similar explanations would hold in the case where some of the feeds are the address zero. // Let B1, B2, Q1, Q2, C be 5 assets, each respectively having dB1, dB2, dQ1, dQ2, dC decimals. // Let pB1 and pB2 be the base prices, and pQ1 and pQ2 the quote prices, so that: // - pB1 is the quantity of 1e(dB2) assets B2 that can be exchanged for 1e(dB1) assets B1. // - pB2 is the quantity of 1e(dC) assets C that can be exchanged for 1e(dB2) assets B2. // - pQ1 is the quantity of 1e(dQ2) assets Q2 that can be exchanged for 1e(dQ1) assets Q1. // - pQ2 is the quantity of 1e(dC) assets C that can be exchanged for 1e(dQ2) assets B2. // Morpho Blue expects `price()` to be the quantity of 1 asset Q1 that can be exchanged for 1 asset B1, // scaled by 1e36: // 1e36 * (pB1 * 1e(dB2 - dB1)) * (pB2 * 1e(dC - dB2)) / ((pQ1 * 1e(dQ2 - dQ1)) * (pQ2 * 1e(dC - dQ2))) // = 1e36 * (pB1 * 1e(-dB1) * pB2) / (pQ1 * 1e(-dQ1) * pQ2) // Let fpB1, fpB2, fpQ1, fpQ2 be the feed precision of the respective prices pB1, pB2, pQ1, pQ2. // Chainlink feeds return pB1 * 1e(fpB1), pB2 * 1e(fpB2), pQ1 * 1e(fpQ1) and pQ2 * 1e(fpQ2). // Based on the implementation of `price()` below, the value of `SCALE_FACTOR` should thus satisfy: // (pB1 * 1e(fpB1)) * (pB2 * 1e(fpB2)) * SCALE_FACTOR / ((pQ1 * 1e(fpQ1)) * (pQ2 * 1e(fpQ2))) // = 1e36 * (pB1 * 1e(-dB1) * pB2) / (pQ1 * 1e(-dQ1) * pQ2) // So SCALE_FACTOR = 1e36 * 1e(-dB1) * 1e(dQ1) * 1e(-fpB1) * 1e(-fpB2) * 1e(fpQ1) * 1e(fpQ2) // = 1e(36 + dQ1 + fpQ1 + fpQ2 - dB1 - fpB1 - fpB2) SCALE_FACTOR = 10 ** ( 36 + quoteTokenDecimals + quoteFeed1.getDecimals() + quoteFeed2.getDecimals() - baseTokenDecimals - baseFeed1.getDecimals() - baseFeed2.getDecimals() ) / vaultConversionSample; } /* PRICE */ /// @inheritdoc IOracle function price() external view returns (uint256) { return SCALE_FACTOR.mulDiv( VAULT.getAssets(VAULT_CONVERSION_SAMPLE) * BASE_FEED_1.getPrice() * BASE_FEED_2.getPrice(), QUOTE_FEED_1.getPrice() * QUOTE_FEED_2.getPrice() ); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title IOracle /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Interface that oracles used by Morpho must implement. /// @dev It is the user's responsibility to select markets with safe oracles. interface IOracle { /// @notice Returns the price of 1 asset of collateral token quoted in 1 asset of loan token, scaled by 1e36. /// @dev It corresponds to the price of 10**(collateral token decimals) assets of collateral token quoted in /// 10**(loan token decimals) assets of loan token with `36 + loan token decimals - collateral token decimals` /// decimals of precision. function price() external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ 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 subtraction of two unsigned integers, with an overflow flag. */ 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. */ 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. */ 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. */ 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 largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; /// @dev From /// https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol 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); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import {IERC4626} from "./IERC4626.sol"; import {AggregatorV3Interface} from "./AggregatorV3Interface.sol"; import {IOracle} from "../../lib/morpho-blue/src/interfaces/IOracle.sol"; /// @title IChainlinkOracle /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Interface of ChainlinkOracle. interface IChainlinkOracle is IOracle { /// @notice Returns the address of the ERC4626 vault. function VAULT() external view returns (IERC4626); /// @notice Returns the vault conversion sample. function VAULT_CONVERSION_SAMPLE() external view returns (uint256); /// @notice Returns the address of the first Chainlink base feed. function BASE_FEED_1() external view returns (AggregatorV3Interface); /// @notice Returns the address of the second Chainlink base feed. function BASE_FEED_2() external view returns (AggregatorV3Interface); /// @notice Returns the address of the first Chainlink quote feed. function QUOTE_FEED_1() external view returns (AggregatorV3Interface); /// @notice Returns the address of the second Chainlink quote feed. function QUOTE_FEED_2() external view returns (AggregatorV3Interface); /// @notice Returns the price scale factor, calculated at contract creation. function SCALE_FACTOR() external view returns (uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; interface IERC4626 { function convertToAssets(uint256) external view returns (uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; import {ErrorsLib} from "./ErrorsLib.sol"; /// @title ChainlinkDataFeedLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing functions to interact with a Chainlink-compliant feed. library ChainlinkDataFeedLib { /// @dev Performs safety checks and returns the latest price of a `feed`. /// @dev When `feed` is the address zero, returns 1. /// @dev Notes on safety checks: /// - L2s are not supported. /// - Staleness is not checked because it's assumed that the Chainlink feed keeps its promises on this. /// - The price is not checked to be in the min/max bounds because it's assumed that the Chainlink feed keeps its /// promises on this. function getPrice(AggregatorV3Interface feed) internal view returns (uint256) { if (address(feed) == address(0)) return 1; (, int256 answer,,,) = feed.latestRoundData(); require(answer >= 0, ErrorsLib.NEGATIVE_ANSWER); return uint256(answer); } /// @dev Returns the number of decimals of a `feed`. /// @dev When `feed` is the address zero, returns 0. function getDecimals(AggregatorV3Interface feed) internal view returns (uint256) { if (address(feed) == address(0)) return 0; return feed.decimals(); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @title ErrorsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing error messages. library ErrorsLib { /// @notice Thrown when the answer returned by a Chainlink feed is negative. string constant NEGATIVE_ANSWER = "negative answer"; /// @notice Thrown when the vault conversion sample is 0. string constant VAULT_CONVERSION_SAMPLE_IS_ZERO = "vault conversion sample is zero"; /// @notice Thrown when the vault conversion sample is not 1 while vault = address(0). string constant VAULT_CONVERSION_SAMPLE_IS_NOT_ONE = "vault conversion sample is not one"; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {IERC4626} from "../interfaces/IERC4626.sol"; /// @title VaultLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing functions to price shares of an ERC4626 vault. library VaultLib { /// @dev Converts `shares` into the corresponding assets on the `vault`. /// @dev When `vault` is the address zero, returns 1. function getAssets(IERC4626 vault, uint256 shares) internal view returns (uint256) { if (address(vault) == address(0)) return 1; return vault.convertToAssets(shares); } }
{ "remappings": [ "@morpho-blue-oracles/=lib/morpho-blue-oracles/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@uniswap/v3-core/=lib/v3-core/", "@uniswap/v3-periphery/=lib/v3-periphery/", "ds-auth/=lib/dss-psm/lib/dss/lib/ds-token/lib/ds-auth/src/", "ds-math/=lib/dss-psm/lib/dss/lib/ds-token/lib/ds-math/src/", "ds-note/=lib/dss-psm/lib/dss/lib/ds-value/lib/ds-thing/lib/ds-note/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "ds-thing/=lib/dss-psm/lib/dss/lib/ds-value/lib/ds-thing/src/", "ds-token/=lib/dss-psm/lib/dss/lib/ds-token/src/", "ds-value/=lib/dss-psm/lib/dss/lib/ds-value/src/", "dss-interfaces/=lib/dss-psm/lib/dss-interfaces/src/", "dss-psm/=lib/dss-psm/src/", "dss/=lib/dss-psm/lib/dss/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "morpho-blue-oracles/=lib/morpho-blue-oracles/src/", "morpho-blue/=lib/morpho-blue/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "v3-core/=lib/v3-core/", "v3-periphery/=lib/v3-periphery/contracts/" ], "optimizer": { "enabled": true, "runs": 999999 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC4626","name":"vault","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"baseFeed1","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"baseFeed2","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"quoteFeed1","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"quoteFeed2","type":"address"},{"internalType":"uint256","name":"vaultConversionSample","type":"uint256"},{"internalType":"uint256","name":"baseTokenDecimals","type":"uint256"},{"internalType":"uint256","name":"quoteTokenDecimals","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"BASE_FEED_1","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_FEED_2","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_FEED_1","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE_FEED_2","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT","outputs":[{"internalType":"contract IERC4626","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_CONVERSION_SAMPLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101606040818152346200029d57819062000cfb8038038091620000248286620002a2565b8439610100938491810103126200029d5781516001600160a01b038116929091908383036200029d576200005b60208201620002c6565b9062000069838201620002c6565b6200007760608301620002c6565b916200008660808201620002c6565b9260a08201519460e060c084015193015198159788159862000291575b87516001600160401b03996060820191908b8311828410176200027b5762000101928b52602282527f7661756c7420636f6e76657273696f6e2073616d706c65206973206e6f74206f6020830152616e6560f01b8b830152620002db565b861598885189810191818310908311176200027b576200014f918a52601f81527f7661756c7420636f6e76657273696f6e2073616d706c65206973207a65726f0060208201528a15620002db565b6080528560a0528060c0528360e052818a5261012098858a5260240194856024116200026557620001aa620001b794620001b1620001b793620001a3620001aa620001be9b620001a3620001aa9a62000361565b9062000345565b9162000361565b62000353565b9062000353565b92604d841162000265576200024f5761014092600a0a04825251916108fd9384620003fe85396080518481816102d8015261048f015260a05184818161018e01526102b7015260c05184818160c30152610301015260e051848181610135015261033001525183818161035c015261042101525182818161025301526103850152518181816101e601526103ac0152f35b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b600187149850620000a3565b600080fd5b601f909101601f19168101906001600160401b038211908210176200027b57604052565b51906001600160a01b03821682036200029d57565b15620002e45750565b6040519062461bcd60e51b82528160208060048301528251908160248401526000935b8285106200032b575050604492506000838284010152601f80199101168101030190fd5b848101820151868601604401529381019385935062000307565b919082018092116200026557565b919082039182116200026557565b6001600160a01b03168015620003f75760206004916040519283809263313ce56760e01b82525afa908115620003eb57600091620003a1575b5060ff1690565b6020813d8211620003e2575b81620003bc60209383620002a2565b81010312620003de57519060ff82168203620003db575060ff6200039a565b80fd5b5080fd5b3d9150620003ad565b6040513d6000823e3d90fd5b5060009056fe60806040818152600436101561001457600080fd5b600091823560e01c908163411557d1146104455750806356095e11146103d7578063a035b1fe14610277578063acfbd39e14610209578063ce4b5bbe146101b1578063d6c843ca14610159578063dc53858c146100eb5763f50a47181461007a57600080fd5b346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e757602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020906103d061035461032b6102fc7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610821565b6103257f000000000000000000000000000000000000000000000000000000000000000061067c565b906104b3565b6103257f000000000000000000000000000000000000000000000000000000000000000061067c565b6103a96103807f000000000000000000000000000000000000000000000000000000000000000061067c565b6103257f000000000000000000000000000000000000000000000000000000000000000061067c565b907f00000000000000000000000000000000000000000000000000000000000000006104f5565b9051908152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b8390346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e75760209073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b818102929181159184041417156104c657565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9091828202917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848209938380861095039480860395146105b357848311156105895782910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050809250156105c1570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761063157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b519069ffffffffffffffffffff8216820361067757565b600080fd5b73ffffffffffffffffffffffffffffffffffffffff16801561081b5760049060a06040918251938480927ffeaf968c0000000000000000000000000000000000000000000000000000000082525afa918215610810576000926107bf575b50805181810181811067ffffffffffffffff821117610631578252600f81526020917f6e6567617469766520616e737765720000000000000000000000000000000000838301526000841261072f5750505090565b5180927f08c379a000000000000000000000000000000000000000000000000000000000825280600483015282519283602484015260005b8481106107a8575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201610767565b909160a0823d8211610808575b816107d960a093836105f0565b8101031261080557506107eb81610660565b506107fd608060208301519201610660565b5090386106da565b80fd5b3d91506107cc565b50513d6000823e3d90fd5b50600190565b73ffffffffffffffffffffffffffffffffffffffff169081156108c0576020906024604051809481937f07a2d13a00000000000000000000000000000000000000000000000000000000835260048301525afa9081156108b457600091610886575090565b906020823d82116108ac575b8161089f602093836105f0565b8101031261080557505190565b3d9150610892565b6040513d6000823e3d90fd5b505060019056fea2646970667358221220f0e801f174784fd63e7aff6322b9324303f07cc93dcccc96a411e9348869440664736f6c634300081500330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fdfd9c85ad200c506cf9e21f1fd8dd01932fbb23000000000000000000000000f4030086522a5beea4988f8ca5b36dbc97bee88c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006
Deployed Bytecode
0x60806040818152600436101561001457600080fd5b600091823560e01c908163411557d1146104455750806356095e11146103d7578063a035b1fe14610277578063acfbd39e14610209578063ce4b5bbe146101b1578063d6c843ca14610159578063dc53858c146100eb5763f50a47181461007a57600080fd5b346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000fdfd9c85ad200c506cf9e21f1fd8dd01932fbb23168152f35b5080fd5b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f4030086522a5beea4988f8ca5b36dbc97bee88c168152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e757602090517f00000000000000000000000000000000000000000000000000000000000000018152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e757602090517f0000000000000000000000000000000000000000000000000de0b6b3a76400008152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020906103d061035461032b6102fc7f00000000000000000000000000000000000000000000000000000000000000017f0000000000000000000000000000000000000000000000000000000000000000610821565b6103257f000000000000000000000000fdfd9c85ad200c506cf9e21f1fd8dd01932fbb2361067c565b906104b3565b6103257f000000000000000000000000f4030086522a5beea4988f8ca5b36dbc97bee88c61067c565b6103a96103807f000000000000000000000000000000000000000000000000000000000000000061067c565b6103257f000000000000000000000000000000000000000000000000000000000000000061067c565b907f0000000000000000000000000000000000000000000000000de0b6b3a76400006104f5565b9051908152f35b50346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e7576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b8390346100e757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100e75760209073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b818102929181159184041417156104c657565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9091828202917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff848209938380861095039480860395146105b357848311156105895782910981600003821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b60046040517f227bc153000000000000000000000000000000000000000000000000000000008152fd5b5050809250156105c1570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761063157604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b519069ffffffffffffffffffff8216820361067757565b600080fd5b73ffffffffffffffffffffffffffffffffffffffff16801561081b5760049060a06040918251938480927ffeaf968c0000000000000000000000000000000000000000000000000000000082525afa918215610810576000926107bf575b50805181810181811067ffffffffffffffff821117610631578252600f81526020917f6e6567617469766520616e737765720000000000000000000000000000000000838301526000841261072f5750505090565b5180927f08c379a000000000000000000000000000000000000000000000000000000000825280600483015282519283602484015260005b8481106107a8575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201610767565b909160a0823d8211610808575b816107d960a093836105f0565b8101031261080557506107eb81610660565b506107fd608060208301519201610660565b5090386106da565b80fd5b3d91506107cc565b50513d6000823e3d90fd5b50600190565b73ffffffffffffffffffffffffffffffffffffffff169081156108c0576020906024604051809481937f07a2d13a00000000000000000000000000000000000000000000000000000000835260048301525afa9081156108b457600091610886575090565b906020823d82116108ac575b8161089f602093836105f0565b8101031261080557505190565b3d9150610892565b6040513d6000823e3d90fd5b505060019056fea2646970667358221220f0e801f174784fd63e7aff6322b9324303f07cc93dcccc96a411e9348869440664736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fdfd9c85ad200c506cf9e21f1fd8dd01932fbb23000000000000000000000000f4030086522a5beea4988f8ca5b36dbc97bee88c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000006
-----Decoded View---------------
Arg [0] : vault (address): 0x0000000000000000000000000000000000000000
Arg [1] : baseFeed1 (address): 0xfdFD9C85aD200c506Cf9e21F1FD8dd01932FBB23
Arg [2] : baseFeed2 (address): 0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c
Arg [3] : quoteFeed1 (address): 0x0000000000000000000000000000000000000000
Arg [4] : quoteFeed2 (address): 0x0000000000000000000000000000000000000000
Arg [5] : vaultConversionSample (uint256): 1
Arg [6] : baseTokenDecimals (uint256): 8
Arg [7] : quoteTokenDecimals (uint256): 6
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 000000000000000000000000fdfd9c85ad200c506cf9e21f1fd8dd01932fbb23
Arg [2] : 000000000000000000000000f4030086522a5beea4988f8ca5b36dbc97bee88c
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000006
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.