Source Code
Overview
S Balance
S Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ChainlinkInfrequentOracle
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {BaseAdapter, Errors, IPriceOracle} from "../BaseAdapter.sol";
import {AggregatorV3Interface} from "./AggregatorV3Interface.sol";
import {ScaleUtils, Scale} from "../../lib/ScaleUtils.sol";
/// @title ChainlinkInfrequentOracle
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice PriceOracle adapter for Chainlink push-based price feeds.
/// @dev Integration Note: `maxStaleness` is an immutable parameter set in the constructor.
/// If the aggregator's heartbeat changes, this adapter may exhibit unintended behavior.
/// Modified from `ChainlinkOracle` to allow larger values for `maxStaleness`.
contract ChainlinkInfrequentOracle is BaseAdapter {
/// @inheritdoc IPriceOracle
string public constant name = "ChainlinkInfrequentOracle";
/// @notice The minimum permitted value for `maxStaleness`.
uint256 internal constant MAX_STALENESS_LOWER_BOUND = 1 minutes;
/// @notice The maximum permitted value for `maxStaleness`.
uint256 internal constant MAX_STALENESS_UPPER_BOUND = type(uint256).max;
/// @notice The address of the base asset corresponding to the feed.
address public immutable base;
/// @notice The address of the quote asset corresponding to the feed.
address public immutable quote;
/// @notice The address of the Chainlink price feed.
/// @dev https://docs.chain.link/data-feeds/price-feeds/addresses
address public immutable feed;
/// @notice The maximum allowed age of the price.
/// @dev Reverts if block.timestamp - updatedAt > maxStaleness.
uint256 public immutable maxStaleness;
/// @notice The scale factors used for decimal conversions.
Scale internal immutable scale;
/// @notice Deploy a ChainlinkOracle.
/// @param _base The address of the base asset corresponding to the feed.
/// @param _quote The address of the quote asset corresponding to the feed.
/// @param _feed The address of the Chainlink price feed.
/// @param _maxStaleness The maximum allowed age of the price.
/// @dev Consider setting `_maxStaleness` to slightly more than the feed's heartbeat
/// to account for possible network delays when the heartbeat is triggered.
constructor(address _base, address _quote, address _feed, uint256 _maxStaleness) {
if (_maxStaleness < MAX_STALENESS_LOWER_BOUND || _maxStaleness > MAX_STALENESS_UPPER_BOUND) {
revert Errors.PriceOracle_InvalidConfiguration();
}
base = _base;
quote = _quote;
feed = _feed;
maxStaleness = _maxStaleness;
// The scale factor is used to correctly convert decimals.
uint8 baseDecimals = _getDecimals(base);
uint8 quoteDecimals = _getDecimals(quote);
uint8 feedDecimals = AggregatorV3Interface(feed).decimals();
scale = ScaleUtils.calcScale(baseDecimals, quoteDecimals, feedDecimals);
}
/// @notice Get the quote from the Chainlink feed.
/// @param inAmount The amount of `base` to convert.
/// @param _base The token that is being priced.
/// @param _quote The token that is the unit of account.
/// @return The converted amount using the Chainlink feed.
function _getQuote(uint256 inAmount, address _base, address _quote) internal view override returns (uint256) {
bool inverse = ScaleUtils.getDirectionOrRevert(_base, base, _quote, quote);
(, int256 answer,, uint256 updatedAt,) = AggregatorV3Interface(feed).latestRoundData();
if (answer <= 0) revert Errors.PriceOracle_InvalidAnswer();
uint256 staleness = block.timestamp - updatedAt;
if (staleness > maxStaleness) revert Errors.PriceOracle_TooStale(staleness, maxStaleness);
uint256 price = uint256(answer);
return ScaleUtils.calcOutAmount(inAmount, price, scale, inverse);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {IPriceOracle} from "../interfaces/IPriceOracle.sol";
import {Errors} from "../lib/Errors.sol";
/// @title BaseAdapter
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Abstract adapter with virtual bid/ask pricing.
abstract contract BaseAdapter is IPriceOracle {
// @dev Addresses <= 0x00..00ffffffff are considered to have 18 decimals without dispatching a call.
// This avoids collisions between ISO 4217 representations and (future) precompiles.
uint256 internal constant ADDRESS_RESERVED_RANGE = 0xffffffff;
/// @inheritdoc IPriceOracle
function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256) {
return _getQuote(inAmount, base, quote);
}
/// @inheritdoc IPriceOracle
/// @dev Does not support true bid/ask pricing.
function getQuotes(uint256 inAmount, address base, address quote) external view returns (uint256, uint256) {
uint256 outAmount = _getQuote(inAmount, base, quote);
return (outAmount, outAmount);
}
/// @notice Determine the decimals of an asset.
/// @param asset ERC20 token address or other asset.
/// @dev Oracles can use ERC-7535, ISO 4217 or other conventions to represent non-ERC20 assets as addresses.
/// Integrator Note: `_getDecimals` will return 18 if `asset` is:
/// - any address <= 0x00000000000000000000000000000000ffffffff (4294967295)
/// - an EOA or a to-be-deployed contract (which may implement `decimals()` after deployment).
/// - a contract that does not implement `decimals()`.
/// @return The decimals of the asset.
function _getDecimals(address asset) internal view returns (uint8) {
if (uint160(asset) <= ADDRESS_RESERVED_RANGE) return 18;
(bool success, bytes memory data) = asset.staticcall(abi.encodeCall(IERC20.decimals, ()));
return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
}
/// @notice Return the quote for the given price query.
/// @dev Must be overridden in the inheriting contract.
function _getQuote(uint256, address, address) internal view virtual returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title AggregatorV3Interface
/// @author smartcontractkit (https://github.com/smartcontractkit/chainlink/blob/e87b83cd78595c09061c199916c4bb9145e719b7/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol)
/// @notice Partial interface for Chainlink Data Feeds.
interface AggregatorV3Interface {
/// @notice Returns the feed's decimals.
/// @return The decimals of the feed.
function decimals() external view returns (uint8);
/// @notice Get data about the latest round.
/// @return roundId The round ID from the aggregator for which the data was retrieved.
/// @return answer The answer for the given round.
/// @return startedAt The timestamp when the round was started.
/// (Only some AggregatorV3Interface implementations return meaningful values)
/// @return updatedAt The timestamp when the round last was updated (i.e. answer was last computed).
/// @return answeredInRound is the round ID of the round in which the answer was computed.
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.8.0;
import {FixedPointMathLib} from "@solady/utils/FixedPointMathLib.sol";
import {Errors} from "./Errors.sol";
type Scale is uint256;
/// @title ScaleUtils
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Utilities for handling decimal conversion of unit price feeds.
library ScaleUtils {
uint256 internal constant PRICE_SCALE_MASK = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
/// @notice The maximum allowed exponent for Scale components.
/// @dev 38 is the largest integer exponent of 10 that fits in 128 bits.
uint256 internal constant MAX_EXPONENT = 38;
/// @notice Create a `Scale` by packing 2 powers of 10.
/// @dev Upper 128 bits occupied by 10^feedExponent.
/// Lower 128 bits occupied by 10^priceExponent.
/// @param priceExponent The power for `priceScale = 10**priceExponent`.
/// @param feedExponent The power for `feedScale = 10**feedExponent`.
/// @return The two scale factors packed in `Scale`.
function from(uint8 priceExponent, uint8 feedExponent) internal pure returns (Scale) {
if (priceExponent > MAX_EXPONENT || feedExponent > MAX_EXPONENT) {
revert Errors.PriceOracle_Overflow();
}
return Scale.wrap((10 ** feedExponent << 128) | 10 ** priceExponent);
}
/// @notice Calculate the direction of pricing, or revert if no match.
/// @param givenBase The base asset supplied by the caller.
/// @param base The base asset in the price oracle adapter.
/// @param givenQuote The quote asset supplied by the caller.
/// @param quote The quote asset in the price oracle adapter.
/// @return False if base/quote, true if quote/base else revert.
function getDirectionOrRevert(address givenBase, address base, address givenQuote, address quote)
internal
pure
returns (bool)
{
if (givenBase == base && givenQuote == quote) return false;
if (givenBase == quote && givenQuote == base) return true;
revert Errors.PriceOracle_NotSupported(givenBase, givenQuote);
}
/// @notice Calculate the scale factors for converting a unit price.
/// @param baseDecimals The decimals of the base asset.
/// @param quoteDecimals The decimals of the quote asset.
/// @param feedDecimals The decimals of the feed, already incorporated into the price.
/// @return The scale factors used for price conversions.
function calcScale(uint8 baseDecimals, uint8 quoteDecimals, uint8 feedDecimals) internal pure returns (Scale) {
return from(quoteDecimals, feedDecimals + baseDecimals);
}
/// @notice Convert the price by applying scale factors.
/// @param inAmount The amount of `base` to convert.
/// @param unitPrice The unit price reported by the feed.
/// @param scale The scale factors returned by `calcScale`.
/// @param inverse Whether to price base/quote or quote/base.
/// @return The resulting outAmount.
function calcOutAmount(uint256 inAmount, uint256 unitPrice, Scale scale, bool inverse)
internal
pure
returns (uint256)
{
uint256 priceScale = Scale.unwrap(scale) & PRICE_SCALE_MASK;
uint256 feedScale = Scale.unwrap(scale) >> 128;
if (inverse) {
// (inAmount * feedScale) / (priceScale * unitPrice)
return FixedPointMathLib.fullMulDiv(inAmount, feedScale, priceScale * unitPrice);
} else {
// (inAmount * priceScale * unitPrice) / feedScale
return FixedPointMathLib.fullMulDiv(inAmount, priceScale * unitPrice, feedScale);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
/// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
/// is the new allowance.
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice Returns the amount of tokens in existence.
function totalSupply() external view returns (uint256);
/// @notice Returns the amount of tokens owned by `account`.
function balanceOf(address account) external view returns (uint256);
/// @notice Moves `amount` tokens from the caller's account to `to`.
function transfer(address to, uint256 amount) external returns (bool);
/// @notice Returns the remaining number of tokens that `spender` is allowed
/// to spend on behalf of `owner`
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
/// `amount` is then deducted from the caller's allowance.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
/// @notice Returns the name of the token.
function name() external view returns (string memory);
/// @notice Returns the symbol of the token.
function symbol() external view returns (string memory);
/// @notice Returns the decimals places of the token.
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; /// @title IPriceOracle /// @custom:security-contact [email protected] /// @author Euler Labs (https://www.eulerlabs.com/) /// @notice Common PriceOracle interface. interface IPriceOracle { /// @notice Get the name of the oracle. /// @return The name of the oracle. function name() external view returns (string memory); /// @notice One-sided price: How much quote token you would get for inAmount of base token, assuming no price spread. /// @param inAmount The amount of `base` to convert. /// @param base The token that is being priced. /// @param quote The token that is the unit of account. /// @return outAmount The amount of `quote` that is equivalent to `inAmount` of `base`. function getQuote(uint256 inAmount, address base, address quote) external view returns (uint256 outAmount); /// @notice Two-sided price: How much quote token you would get/spend for selling/buying inAmount of base token. /// @param inAmount The amount of `base` to convert. /// @param base The token that is being priced. /// @param quote The token that is the unit of account. /// @return bidOutAmount The amount of `quote` you would get for selling `inAmount` of `base`. /// @return askOutAmount The amount of `quote` you would spend for buying `inAmount` of `base`. function getQuotes(uint256 inAmount, address base, address quote) external view returns (uint256 bidOutAmount, uint256 askOutAmount); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @title Errors /// @custom:security-contact [email protected] /// @author Euler Labs (https://www.eulerlabs.com/) /// @notice Collects common errors in PriceOracles. library Errors { /// @notice The external feed returned an invalid answer. error PriceOracle_InvalidAnswer(); /// @notice The configuration parameters for the PriceOracle are invalid. error PriceOracle_InvalidConfiguration(); /// @notice The base/quote path is not supported. /// @param base The address of the base asset. /// @param quote The address of the quote asset. error PriceOracle_NotSupported(address base, address quote); /// @notice The quote cannot be completed due to overflow. error PriceOracle_Overflow(); /// @notice The price is too stale. /// @param staleness The time elapsed since the price was updated. /// @param maxStaleness The maximum time elapsed since the last price update. error PriceOracle_TooStale(uint256 staleness, uint256 maxStaleness); /// @notice The method can only be called by the governor. error Governance_CallerNotGovernor(); }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
int256 wad = int256(WAD);
int256 p = x;
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (w >> 63 == 0) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == 0) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != 0);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c != 0) {
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Least significant 256 bits of the product.
result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
let mm := mulmod(x, y, not(0))
// Most significant 256 bits of the product.
let p1 := sub(mm, add(result, lt(mm, result)))
// Handle non-overflow cases, 256 by 256 division.
if iszero(p1) {
if iszero(d) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
result := div(result, d)
break
}
// Make sure the result is less than `2**256`. Also prevents `d == 0`.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
// Compute remainder using mulmod.
let r := mulmod(x, y, d)
// `t` is the least significant bit of `d`.
// Always greater or equal to 1.
let t := and(d, sub(0, d))
// Divide `d` by `t`, which is a power of two.
d := div(d, t)
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use 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.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
result :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(
mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
div(sub(result, r), t)
),
// inverse mod 2**256
mul(inv, sub(2, mul(d, inv)))
)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
result = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
result := add(result, 1)
if iszero(result) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if iszero(iszero(x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 9;
if (x <= type(uint256).max / 10 ** 36 - 1) {
x *= 10 ** 18;
z = 1;
}
z *= sqrt(x);
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`.
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
z = 10 ** 12;
if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) {
if (x >= type(uint256).max / 10 ** 36) {
x *= 10 ** 18;
z = 10 ** 6;
} else {
x *= 10 ** 36;
z = 1;
}
}
z *= cbrt(x);
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}{
"remappings": [
"lib/euler-price-oracle:@openzeppelin/contracts/=lib/euler-price-oracle/lib/openzeppelin-contracts/contracts/",
"lib/euler-earn:@openzeppelin/=lib/euler-earn/lib/openzeppelin-contracts/",
"lib/euler-earn:@openzeppelin-upgradeable/=lib/euler-earn/lib/openzeppelin-contracts-upgradeable/contracts/",
"lib/euler-earn:ethereum-vault-connector/=lib/euler-earn/lib/ethereum-vault-connector/src/",
"lib/layerzero-devtools/packages/oft-evm/contracts:@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts/contracts/",
"lib/layerzero-devtools/packages/oft-evm-upgradeable/contracts:@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"lib/layerzero-devtools/packages/oapp-evm-upgradeable/contracts:@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@layerzerolabs/oft-evm/=lib/layerzero-devtools/packages/oft-evm/",
"@layerzerolabs/oapp-evm/=lib/layerzero-devtools/packages/oapp-evm/",
"@layerzerolabs/oapp-evm-upgradeable/=lib/layerzero-devtools/packages/oapp-evm-upgradeable/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/protocol/",
"@layerzerolabs/lz-evm-messagelib-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/messagelib/",
"@layerzerolabs/lz-evm-oapp-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/oapp/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"ethereum-vault-connector/=lib/ethereum-vault-connector/src/",
"evc/=lib/ethereum-vault-connector/src/",
"evk/=lib/euler-vault-kit/src/",
"evk-test/=lib/euler-vault-kit/test/",
"euler-price-oracle/=lib/euler-price-oracle/src/",
"euler-price-oracle-test/=lib/euler-price-oracle/test/",
"fee-flow/=lib/fee-flow/src/",
"reward-streams/=lib/reward-streams/src/",
"@openzeppelin/=lib/openzeppelin-contracts/contracts/",
"euler-earn/=lib/euler-earn/src/",
"layerzero/oft-evm/=lib/layerzero-devtools/packages/oft-evm/contracts/",
"layerzero/oft-evm-upgradeable/=lib/layerzero-devtools/packages/oft-evm-upgradeable/contracts/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/",
"@axiom-crypto/v2-periphery/=lib/euler-price-oracle/lib/axiom-std/lib/axiom-v2-periphery/src/",
"@openzeppelin-upgradeable/=lib/euler-earn/lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@pendle/core-v2/=lib/euler-price-oracle/lib/pendle-core-v2-public/contracts/",
"@pyth/=lib/euler-price-oracle/lib/pyth-sdk-solidity/",
"@redstone/evm-connector/=lib/euler-price-oracle/lib/redstone-oracles-monorepo/packages/evm-connector/contracts/",
"@solady/=lib/euler-price-oracle/lib/solady/src/",
"@uniswap/v3-core/=lib/euler-price-oracle/lib/v3-core/",
"@uniswap/v3-periphery/=lib/euler-price-oracle/lib/v3-periphery/",
"ERC4626/=lib/euler-earn/lib/properties/lib/ERC4626/contracts/",
"axiom-std/=lib/euler-price-oracle/lib/axiom-std/src/",
"axiom-v2-periphery/=lib/euler-price-oracle/lib/axiom-v2-periphery/src/",
"crytic-properties/=lib/euler-earn/lib/properties/contracts/",
"ds-test/=lib/ethereum-vault-connector/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"euler-vault-kit/=lib/euler-vault-kit/",
"forge-gas-snapshot/=lib/euler-vault-kit/lib/permit2/lib/forge-gas-snapshot/src/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"layerzero-devtools/=lib/layerzero-devtools/packages/toolbox-foundry/src/",
"layerzero-v2/=lib/layerzero-v2/",
"morpho-blue-irm/=lib/morpho-blue-irm/src/",
"morpho-blue/=lib/morpho-blue-irm/lib/morpho-blue/",
"native-token-transfers/=lib/native-token-transfers/",
"openzeppelin/=lib/ethereum-vault-connector/lib/openzeppelin-contracts/contracts/",
"pendle-core-v2-public/=lib/euler-price-oracle/lib/pendle-core-v2-public/contracts/",
"permit2/=lib/euler-vault-kit/lib/permit2/",
"properties/=lib/euler-earn/lib/properties/contracts/",
"pyth-sdk-solidity/=lib/euler-price-oracle/lib/pyth-sdk-solidity/",
"redstone-oracles-monorepo/=lib/euler-price-oracle/lib/",
"solady/=lib/euler-price-oracle/lib/solady/src/",
"solmate/=lib/fee-flow/lib/solmate/src/",
"v3-core/=lib/euler-price-oracle/lib/v3-core/contracts/",
"v3-periphery/=lib/euler-price-oracle/lib/v3-periphery/contracts/",
"wormhole-solidity-sdk/=lib/native-token-transfers/evm/lib/wormhole-solidity-sdk/src/"
],
"optimizer": {
"enabled": true,
"runs": 20000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_base","type":"address"},{"internalType":"address","name":"_quote","type":"address"},{"internalType":"address","name":"_feed","type":"address"},{"internalType":"uint256","name":"_maxStaleness","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"PriceOracle_InvalidAnswer","type":"error"},{"inputs":[],"name":"PriceOracle_InvalidConfiguration","type":"error"},{"inputs":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"PriceOracle_NotSupported","type":"error"},{"inputs":[],"name":"PriceOracle_Overflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"staleness","type":"uint256"},{"internalType":"uint256","name":"maxStaleness","type":"uint256"}],"name":"PriceOracle_TooStale","type":"error"},{"inputs":[],"name":"base","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"name":"getQuotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxStaleness","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quote","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61012060405234801562000011575f80fd5b5060405162000cd638038062000cd6833981016040819052620000349162000299565b603c8110806200004157505f5b1562000060576040516301a4c16560e21b815260040160405180910390fd5b6001600160a01b03808516608081905284821660a05290831660c05260e08290525f906200008e906200012d565b90505f620000a460a0516200012d60201b60201c565b90505f60c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000e6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200010c9190620002e8565b90506200011b8383836200020d565b61010052506200047895505050505050565b5f63ffffffff826001600160a01b0316116200014b57506012919050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290515f9182916001600160a01b038616916200018f9162000311565b5f60405180830381855afa9150503d805f8114620001c9576040519150601f19603f3d011682016040523d82523d5f602084013e620001ce565b606091505b5091509150818015620001e2575080516020145b620001ef57601262000205565b80806020019051810190620002059190620002e8565b949350505050565b5f62000205836200021f868562000353565b5f60268360ff16118062000236575060268260ff16115b1562000255576040516302950f9560e51b815260040160405180910390fd5b6200026283600a62000468565b60806200027184600a62000468565b901b1790505b92915050565b80516001600160a01b038116811462000294575f80fd5b919050565b5f805f8060808587031215620002ad575f80fd5b620002b8856200027d565b9350620002c8602086016200027d565b9250620002d8604086016200027d565b6060959095015193969295505050565b5f60208284031215620002f9575f80fd5b815160ff811681146200030a575f80fd5b9392505050565b5f82515f5b8181101562000332576020818601810151858301520162000316565b505f920191825250919050565b634e487b7160e01b5f52601160045260245ffd5b60ff81811683821601908111156200027757620002776200033f565b600181815b80851115620003af57815f19048211156200039357620003936200033f565b80851615620003a157918102915b93841c939080029062000374565b509250929050565b5f82620003c75750600162000277565b81620003d557505f62000277565b8160018114620003ee5760028114620003f95762000419565b600191505062000277565b60ff8411156200040d576200040d6200033f565b50506001821b62000277565b5060208310610133831016604e8410600b84101617156200043e575081810a62000277565b6200044a83836200036f565b805f19048211156200046057620004606200033f565b029392505050565b5f6200030a60ff841683620003b7565b60805160a05160c05160e051610100516107fe620004d85f395f6103c201525f818161016c01528181610334015261038901525f818160f9015261025a01525f81816101a1015261023001525f8181610145015261020e01526107fe5ff3fe608060405234801561000f575f80fd5b506004361061007a575f3560e01c80635001f3b5116100585780635001f3b51461014057806387cf469614610167578063999b93af1461019c578063ae68676c146101c3575f80fd5b80630579e61f1461007e57806306fdde03146100ab57806337a7b7d8146100f4575b5f80fd5b61009161008c366004610663565b6101d6565b604080519283526020830191909152015b60405180910390f35b6100e76040518060400160405280601981526020017f436861696e6c696e6b496e6672657175656e744f7261636c650000000000000081525081565b6040516100a2919061069c565b61011b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100a2565b61011b7f000000000000000000000000000000000000000000000000000000000000000081565b61018e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100a2565b61011b7f000000000000000000000000000000000000000000000000000000000000000081565b61018e6101d1366004610663565b6101f0565b5f805f6101e4868686610206565b96879650945050505050565b5f6101fc848484610206565b90505b9392505050565b5f80610254847f0000000000000000000000000000000000000000000000000000000000000000857f00000000000000000000000000000000000000000000000000000000000000006103f4565b90505f807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156102c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102e5919061071f565b509350509250505f8213610325576040517fd743df6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6103308242610798565b90507f00000000000000000000000000000000000000000000000000000000000000008111156103ba576040517fa6e68d63000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000060248201526044015b60405180910390fd5b826103e789827f000000000000000000000000000000000000000000000000000000000000000088610534565b9998505050505050505050565b5f8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614801561045b57508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b1561046757505f61052c565b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156104cd57508373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b156104da5750600161052c565b6040517f4ca22af000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8087166004830152841660248201526044016103b1565b949350505050565b5f6fffffffffffffffffffffffffffffffff8316608084901c831561057057610567878261056289866107b1565b610580565b9250505061052c565b6105678761057e88856107b1565b835b8282027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83850981811082019003806105ce57826105c55763ae47f7025f526004601cfd5b508190046101ff565b8083116105e25763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461065e575f80fd5b919050565b5f805f60608486031215610675575f80fd5b833592506106856020850161063b565b91506106936040850161063b565b90509250925092565b5f602080835283518060208501525f5b818110156106c8578581018301518582016040015282016106ac565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b805169ffffffffffffffffffff8116811461065e575f80fd5b5f805f805f60a08688031215610733575f80fd5b61073c86610706565b945060208601519350604086015192506060860151915061075f60808701610706565b90509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156107ab576107ab61076b565b92915050565b80820281158282048414176107ab576107ab61076b56fea2646970667358221220bbc39c409d4697c843913afb02e2a76062f903f0e904eb2b5790988f5a21482e64736f6c63430008180033000000000000000000000000be27993204ec64238f71a527b4c4d5f4949034c30000000000000000000000000000000000000000000000000000000000000348000000000000000000000000575ad5f473fc1a7b8b2ace86988e6df156483b0300000000000000000000000000000000000000000000000000000000bbf81e00
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061007a575f3560e01c80635001f3b5116100585780635001f3b51461014057806387cf469614610167578063999b93af1461019c578063ae68676c146101c3575f80fd5b80630579e61f1461007e57806306fdde03146100ab57806337a7b7d8146100f4575b5f80fd5b61009161008c366004610663565b6101d6565b604080519283526020830191909152015b60405180910390f35b6100e76040518060400160405280601981526020017f436861696e6c696e6b496e6672657175656e744f7261636c650000000000000081525081565b6040516100a2919061069c565b61011b7f000000000000000000000000575ad5f473fc1a7b8b2ace86988e6df156483b0381565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100a2565b61011b7f000000000000000000000000be27993204ec64238f71a527b4c4d5f4949034c381565b61018e7f00000000000000000000000000000000000000000000000000000000bbf81e0081565b6040519081526020016100a2565b61011b7f000000000000000000000000000000000000000000000000000000000000034881565b61018e6101d1366004610663565b6101f0565b5f805f6101e4868686610206565b96879650945050505050565b5f6101fc848484610206565b90505b9392505050565b5f80610254847f000000000000000000000000be27993204ec64238f71a527b4c4d5f4949034c3857f00000000000000000000000000000000000000000000000000000000000003486103f4565b90505f807f000000000000000000000000575ad5f473fc1a7b8b2ace86988e6df156483b0373ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156102c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102e5919061071f565b509350509250505f8213610325576040517fd743df6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6103308242610798565b90507f00000000000000000000000000000000000000000000000000000000bbf81e008111156103ba576040517fa6e68d63000000000000000000000000000000000000000000000000000000008152600481018290527f00000000000000000000000000000000000000000000000000000000bbf81e0060248201526044015b60405180910390fd5b826103e789827f000000000000d3c21bcecceda100000000000000000000000de0b6b3a764000088610534565b9998505050505050505050565b5f8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614801561045b57508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b1561046757505f61052c565b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156104cd57508373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b156104da5750600161052c565b6040517f4ca22af000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8087166004830152841660248201526044016103b1565b949350505050565b5f6fffffffffffffffffffffffffffffffff8316608084901c831561057057610567878261056289866107b1565b610580565b9250505061052c565b6105678761057e88856107b1565b835b8282027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83850981811082019003806105ce57826105c55763ae47f7025f526004601cfd5b508190046101ff565b8083116105e25763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461065e575f80fd5b919050565b5f805f60608486031215610675575f80fd5b833592506106856020850161063b565b91506106936040850161063b565b90509250925092565b5f602080835283518060208501525f5b818110156106c8578581018301518582016040015282016106ac565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b805169ffffffffffffffffffff8116811461065e575f80fd5b5f805f805f60a08688031215610733575f80fd5b61073c86610706565b945060208601519350604086015192506060860151915061075f60808701610706565b90509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156107ab576107ab61076b565b92915050565b80820281158282048414176107ab576107ab61076b56fea2646970667358221220bbc39c409d4697c843913afb02e2a76062f903f0e904eb2b5790988f5a21482e64736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000be27993204ec64238f71a527b4c4d5f4949034c30000000000000000000000000000000000000000000000000000000000000348000000000000000000000000575ad5f473fc1a7b8b2ace86988e6df156483b0300000000000000000000000000000000000000000000000000000000bbf81e00
-----Decoded View---------------
Arg [0] : _base (address): 0xBe27993204Ec64238F71A527B4c4D5F4949034C3
Arg [1] : _quote (address): 0x0000000000000000000000000000000000000348
Arg [2] : _feed (address): 0x575Ad5F473FC1a7B8B2ACe86988E6df156483b03
Arg [3] : _maxStaleness (uint256): 3153600000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000be27993204ec64238f71a527b4c4d5f4949034c3
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000348
Arg [2] : 000000000000000000000000575ad5f473fc1a7b8b2ace86988e6df156483b03
Arg [3] : 00000000000000000000000000000000000000000000000000000000bbf81e00
Deployed Bytecode Sourcemap
735:3191:3:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1003:215:1;;;;;;:::i;:::-;;:::i;:::-;;;;722:25:8;;;778:2;763:18;;756:34;;;;695:18;1003:215:1;;;;;;;;824:57:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;1506:29::-;;;;;;;;1589:42:8;1577:55;;;1559:74;;1547:2;1532:18;1506:29:3;1413:226:8;1234:29:3;;;;;1663:37;;;;;;;;1790:25:8;;;1778:2;1763:18;1663:37:3;1644:177:8;1343:30:3;;;;;759:153:1;;;;;;:::i;:::-;;:::i;1003:215::-;1092:7;1101;1120:17;1140:32;1150:8;1160:4;1166:5;1140:9;:32::i;:::-;1120:52;;;-1:-1:-1;1003:215:1;-1:-1:-1;;;;;1003:215:1:o;759:153::-;847:7;873:32;883:8;893:4;899:5;873:9;:32::i;:::-;866:39;;759:153;;;;;;:::o;3287:637:3:-;3387:7;3406:12;3421:59;3453:5;3460:4;3466:6;3474:5;3421:31;:59::i;:::-;3406:74;;3494:13;3510:17;3554:4;3532:43;;;:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3491:86;;;;;;;3601:1;3591:6;:11;3587:58;;3611:34;;;;;;;;;;;;;;3587:58;3655:17;3675:27;3693:9;3675:15;:27;:::i;:::-;3655:47;;3728:12;3716:9;:24;3712:89;;;3749:52;;;;;;;;722:25:8;;;3788:12:3;763:18:8;;;756:34;695:18;;3749:52:3;;;;;;;;3712:89;3836:6;3860:57;3885:8;3836:6;3902:5;3909:7;3860:24;:57::i;:::-;3853:64;3287:637;-1:-1:-1;;;;;;;;;3287:637:3:o;1829:368:6:-;1974:4;2011;1998:17;;:9;:17;;;:40;;;;;2033:5;2019:19;;:10;:19;;;1998:40;1994:58;;;-1:-1:-1;2047:5:6;2040:12;;1994:58;2079:5;2066:18;;:9;:18;;;:40;;;;;2102:4;2088:18;;:10;:18;;;2066:40;2062:57;;;-1:-1:-1;2115:4:6;2108:11;;2062:57;2136:54;;;;;2994:42:8;3063:15;;;2136:54:6;;;3045:34:8;3115:15;;3095:18;;;3088:43;2957:18;;2136:54:6;2810:327:8;1829:368:6;;;;;;;:::o;3090:645::-;3224:7;470:66;3268:38;;3359:3;3336:26;;;3372:357;;;;3471:73;3500:8;3510:9;3521:22;3534:9;3521:10;:22;:::i;:::-;3471:28;:73::i;:::-;3464:80;;;;;;3372:357;3645:73;3674:8;3684:22;3697:9;3684:10;:22;:::i;:::-;3708:9;20285:3569:0;20897:9;;;20995:6;20904:1;20901;20982:20;21110:14;;;21098:27;;21090:36;;;21211:278;;21257:1;21247:153;;21299:10;21293:4;21286:24;21373:4;21367;21360:18;21247:153;-1:-1:-1;21431:14:0;;;21466:5;;21211:278;21610:2;21607:1;21604:9;21594:149;;21650:10;21644:4;21637:24;21720:4;21714;21707:18;21594:149;22000:1;21997;21994;21987:15;22148:1;22144:9;;;22137:17;;22239:9;;;;;23559:13;;;23551:22;;;23583:9;;;;23579:17;;;23598:1;23575:25;23547:54;23635:14;;23631:22;23515:164;22614:1;22621;22617:9;;22610:17;;22896:11;;;22889:19;;22880:29;22969:11;;;22962:19;;22953:29;23043:11;;;23036:19;;23027:29;23117:11;;;23110:19;;23101:29;23191:11;;;23184:19;;23175:29;23767:11;;;23760:19;;;23751:29;23273:529;20285:3569;;;;;:::o;14:196:8:-;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;111:93;14:196;;;:::o;215:328::-;292:6;300;308;361:2;349:9;340:7;336:23;332:32;329:52;;;377:1;374;367:12;329:52;413:9;400:23;390:33;;442:38;476:2;465:9;461:18;442:38;:::i;:::-;432:48;;499:38;533:2;522:9;518:18;499:38;:::i;:::-;489:48;;215:328;;;;;:::o;801:607::-;913:4;942:2;971;960:9;953:21;1003:6;997:13;1046:6;1041:2;1030:9;1026:18;1019:34;1071:1;1081:140;1095:6;1092:1;1089:13;1081:140;;;1190:14;;;1186:23;;1180:30;1156:17;;;1175:2;1152:26;1145:66;1110:10;;1081:140;;;1085:3;1270:1;1265:2;1256:6;1245:9;1241:22;1237:31;1230:42;1399:2;1329:66;1324:2;1316:6;1312:15;1308:88;1297:9;1293:104;1289:113;1281:121;;;;801:607;;;;:::o;1826:179::-;1904:13;;1957:22;1946:34;;1936:45;;1926:73;;1995:1;1992;1985:12;2010:473;2113:6;2121;2129;2137;2145;2198:3;2186:9;2177:7;2173:23;2169:33;2166:53;;;2215:1;2212;2205:12;2166:53;2238:39;2267:9;2238:39;:::i;:::-;2228:49;;2317:2;2306:9;2302:18;2296:25;2286:35;;2361:2;2350:9;2346:18;2340:25;2330:35;;2405:2;2394:9;2390:18;2384:25;2374:35;;2428:49;2472:3;2461:9;2457:19;2428:49;:::i;:::-;2418:59;;2010:473;;;;;;;;:::o;2488:184::-;2540:77;2537:1;2530:88;2637:4;2634:1;2627:15;2661:4;2658:1;2651:15;2677:128;2744:9;;;2765:11;;;2762:37;;;2779:18;;:::i;:::-;2677:128;;;;:::o;3142:168::-;3215:9;;;3246;;3263:15;;;3257:22;;3243:37;3233:71;;3284:18;;:::i
Swarm Source
ipfs://bbc39c409d4697c843913afb02e2a76062f903f0e904eb2b5790988f5a21482e
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.