// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.9.0;
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: MIT
pragma solidity >=0.8.13;
import { MAX_UINT40 } from "../Common.sol";
import { uMAX_SD1x18 } from "../sd1x18/Constants.sol";
import { SD1x18 } from "../sd1x18/ValueType.sol";
import { SD59x18 } from "../sd59x18/ValueType.sol";
import { UD2x18 } from "../ud2x18/ValueType.sol";
import { UD60x18 } from "../ud60x18/ValueType.sol";
import { PRBMath_UD2x18_IntoSD1x18_Overflow, PRBMath_UD2x18_IntoUint40_Overflow } from "./Errors.sol";
import { UD2x18 } from "./ValueType.sol";
/// @notice Casts an UD2x18 number into SD1x18.
/// - x must be less than or equal to `uMAX_SD1x18`.
function intoSD1x18(UD2x18 x) pure returns (SD1x18 result) {
uint64 xUint = UD2x18.unwrap(x);
if (xUint > uint64(uMAX_SD1x18)) {
revert PRBMath_UD2x18_IntoSD1x18_Overflow(x);
}
result = SD1x18.wrap(int64(xUint));
}
/// @notice Casts an UD2x18 number into SD59x18.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of SD59x18.
function intoSD59x18(UD2x18 x) pure returns (SD59x18 result) {
result = SD59x18.wrap(int256(uint256(UD2x18.unwrap(x))));
}
/// @notice Casts an UD2x18 number into UD60x18.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of UD60x18.
function intoUD60x18(UD2x18 x) pure returns (UD60x18 result) {
result = UD60x18.wrap(UD2x18.unwrap(x));
}
/// @notice Casts an UD2x18 number into uint128.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of uint128.
function intoUint128(UD2x18 x) pure returns (uint128 result) {
result = uint128(UD2x18.unwrap(x));
}
/// @notice Casts an UD2x18 number into uint256.
/// @dev There is no overflow check because the domain of UD2x18 is a subset of uint256.
function intoUint256(UD2x18 x) pure returns (uint256 result) {
result = uint256(UD2x18.unwrap(x));
}
/// @notice Casts an UD2x18 number into uint40.
/// @dev Requirements:
/// - x must be less than or equal to `MAX_UINT40`.
function intoUint40(UD2x18 x) pure returns (uint40 result) {
uint64 xUint = UD2x18.unwrap(x);
if (xUint > uint64(MAX_UINT40)) {
revert PRBMath_UD2x18_IntoUint40_Overflow(x);
}
result = uint40(xUint);
}
/// @notice Alias for the `wrap` function.
function ud2x18(uint64 x) pure returns (UD2x18 result) {
result = UD2x18.wrap(x);
}
/// @notice Unwrap an UD2x18 number into uint64.
function unwrap(UD2x18 x) pure returns (uint64 result) {
result = UD2x18.unwrap(x);
}
/// @notice Wraps an uint64 number into the UD2x18 value type.
function wrap(uint64 x) pure returns (UD2x18 result) {
result = UD2x18.wrap(x);
}
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;
import "../interfaces/IChainlinkRelayer.sol";
import "foundry-chainlink-toolkit/src/interfaces/feeds/AggregatorV3Interface.sol";
import { UD60x18, ud, intoUint256 } from "prb/math/UD60x18.sol";
/**
* @notice The minimal subset of the SortedOracles interface needed by the
* relayer.
* @dev SortedOracles is a Solidity 5.13 contract, thus we can't import the
* interface directly, so we use a minimal hand-copied one.
* See https://github.com/mento-protocol/mento-core/blob/develop/contracts/common/SortedOracles.sol
*/
interface ISortedOraclesMin {
function report(
address rateFeedId,
uint256 value,
address lesserKey,
address greaterKey
) external;
function getRates(address rateFeedId)
external
returns (
address[] memory,
uint256[] memory,
uint256[] memory
);
function medianTimestamp(address rateFeedId) external view returns (uint256);
function getTokenReportExpirySeconds(address rateFeedId) external view returns (uint256);
function removeExpiredReports(address rateFeedId, uint256 n) external;
}
/**
* @title ChainlinkRelayer
* @notice The ChainlinkRelayer relays rate feed data from a Chainlink price feed, or
* an aggregation of multiple Chainlink price feeds to the SortedOracles contract.
* A separate instance should be deployed for each rate feed.
* @dev Assumes that it is the only reporter for the given SortedOracles feed.
* This contract aggregates multiple Chainlink price feeds in order to provide derived rate feeds
* to the rest of the protocol. This is needed because it is more efficient for oracle providers
* to report FX rates against the dollar and crypto-asset rates against the dollar,
* instead of all possible combinations.
* For example, for the Philippine Peso, Chainlink reports PHP/USD, but does not report CELO/PHP
* which is required to pay for gas in a PHP stable token. But using both PHP/USD and CELO/USD,
* one can create a path: CELO/USD * inverse(PHP/USD) = CELO/PHP.
* Because of this we can provide up to four Chainlink price sources with inversion settings
* to the relayer, a price path. The path segments are chained through multiplication and
* inversion to derive the rate.
*/
contract ChainlinkRelayerV1 is IChainlinkRelayer {
/**
* @notice The number of digits after the decimal point in FixidityLib values, as used by SortedOracles.
* @dev See contracts/common/FixidityLib.sol
*/
uint256 private constant UD60X18_TO_FIXIDITY_SCALE = 1e6; // 10 ** (24 - 18)
/// @notice The rateFeedId this relayer relays for.
address public immutable rateFeedId;
/// @notice The address of the SortedOracles contract to report to.
address public immutable sortedOracles;
/**
* @dev We store an array of up to four IChainlinkRelayer.ChainlinkAggregator structs
* in the following immutable variables.
* aggregator<i> stores the i-th ChainlinkAggregator.aggregator member.
* invert<i> stores the i-th ChainlinkAggregator.invert member.
* aggregatorCount stores the length of the array.
* These are built back up into an in-memory array in the buildAggregatorArray function.
*/
/// @notice The addresses of the Chainlink aggregators this contract fetches data from.
address private immutable aggregator0;
address private immutable aggregator1;
address private immutable aggregator2;
address private immutable aggregator3;
/// @notice The invert setting for each aggregator, if true it flips the rate feed, i.e. CELO/USD -> USD/CELO.
bool private immutable invert0;
bool private immutable invert1;
bool private immutable invert2;
bool private immutable invert3;
/// @notice The number of aggregators provided during construction 1 <= aggregatorCount <= 4.
uint256 private immutable aggregatorCount;
/**
* @notice Maximum timestamp deviation allowed between all report timestamps pulled
* from the Chainlink aggregators.
* @dev Only relevant when aggregatorCount > 1.
*/
uint256 public immutable maxTimestampSpread;
/**
* @notice Human-readable description of the rate feed.
* @dev Should only be used off-chain for easier debugging / UI generation,
* thus the only storage related gas spend occurs in the constructor.
*/
string public rateFeedDescription;
/// @notice Used when an empty array of aggregators is passed into the constructor.
error NoAggregators();
/// @notice Used when more than four aggregators are passed into the constructor.
error TooManyAggregators();
/// @notice Used when there are more then 1 aggregators and the maxTimestampSpread is 0,
/// amd when there is only 1 aggregator and the maxTimestampSpread is not 0.
error InvalidMaxTimestampSpread();
/// @notice Used when a new price's timestamp is not newer than the most recent SortedOracles timestamp.
error TimestampNotNew();
/// @notice Used when a new price's timestamp would be considered expired by SortedOracles.
error ExpiredTimestamp();
/// @notice Used when a negative or zero price is returned by the Chainlink aggregator.
error InvalidPrice();
/**
* @notice Used when the spread between the earliest and latest timestamp
* of the aggregators is above the maximum allowed.
*/
error TimestampSpreadTooHigh();
/**
* @notice Used when trying to recover from a lesser/greater revert and there are
* too many existing reports in SortedOracles.
*/
error TooManyExistingReports();
/**
* @notice Used in the constructor when a ChainlinkAggregator
* has address(0) for an aggregator.
*/
error InvalidAggregator();
/**
* @notice Initializes the contract and sets immutable parameters.
* @param _rateFeedId ID of the rate feed this relayer instance relays for.
* @param _rateFeedDescription The human-readable description of the reported rate feed.
* @param _sortedOracles Address of the SortedOracles contract to relay to.
* @param _maxTimestampSpread Max difference in milliseconds between the earliest and
* latest timestamp of all aggregators in the price path.
* @param _aggregators Array of ChainlinkAggregator structs defining the price path.
*/
constructor(
address _rateFeedId,
string memory _rateFeedDescription,
address _sortedOracles,
uint256 _maxTimestampSpread,
ChainlinkAggregator[] memory _aggregators
) {
rateFeedId = _rateFeedId;
sortedOracles = _sortedOracles;
maxTimestampSpread = _maxTimestampSpread;
rateFeedDescription = _rateFeedDescription;
aggregatorCount = _aggregators.length;
if (aggregatorCount == 0) {
revert NoAggregators();
}
if (aggregatorCount > 4) {
revert TooManyAggregators();
}
if ((aggregatorCount > 1 && _maxTimestampSpread == 0) || (aggregatorCount == 1 && _maxTimestampSpread != 0)) {
revert InvalidMaxTimestampSpread();
}
ChainlinkAggregator[] memory aggregators = new ChainlinkAggregator[](4);
for (uint256 i = 0; i < _aggregators.length; i++) {
if (_aggregators[i].aggregator == address(0)) {
revert InvalidAggregator();
}
aggregators[i] = _aggregators[i];
}
aggregator0 = aggregators[0].aggregator;
aggregator1 = aggregators[1].aggregator;
aggregator2 = aggregators[2].aggregator;
aggregator3 = aggregators[3].aggregator;
invert0 = aggregators[0].invert;
invert1 = aggregators[1].invert;
invert2 = aggregators[2].invert;
invert3 = aggregators[3].invert;
}
/**
* @notice Get the Chainlink aggregators and their invert settings.
* @return An array of ChainlinkAggregator segments that compose the price path.
*/
function getAggregators() external view returns (ChainlinkAggregator[] memory) {
return buildAggregatorArray();
}
/**
* @notice Relays data from the configured Chainlink aggregator to SortedOracles.
* @dev Checks the price is non-negative (Chainlink uses `int256` rather than `uint256`.
* @dev Converts the price to a Fixidity value, as expected by SortedOracles.
* @dev Performs checks on the timestamp, will revert if any fails:
* - The most recent Chainlink timestamp should be strictly newer than the most
* recent timestamp in SortedOracles.
* - The most recent Chainlink timestamp should not be considered expired by SortedOracles.
* - The spread between aggregator timestamps is less than the maxTimestampSpread.
*/
function relay() external {
ISortedOraclesMin _sortedOracles = ISortedOraclesMin(sortedOracles);
ChainlinkAggregator[] memory aggregators = buildAggregatorArray();
(UD60x18 report, uint256 timestamp) = readChainlinkAggregator(aggregators[0]);
uint256 oldestChainlinkTs = timestamp;
uint256 newestChainlinkTs = timestamp;
UD60x18 nextReport;
for (uint256 i = 1; i < aggregators.length; i++) {
(nextReport, timestamp) = readChainlinkAggregator(aggregators[i]);
report = report.mul(nextReport);
oldestChainlinkTs = timestamp < oldestChainlinkTs ? timestamp : oldestChainlinkTs;
newestChainlinkTs = timestamp > newestChainlinkTs ? timestamp : newestChainlinkTs;
}
if (newestChainlinkTs - oldestChainlinkTs > maxTimestampSpread) {
revert TimestampSpreadTooHigh();
}
uint256 lastReportTs = _sortedOracles.medianTimestamp(rateFeedId);
if (lastReportTs > 0 && newestChainlinkTs <= lastReportTs) {
revert TimestampNotNew();
}
if (isTimestampExpired(newestChainlinkTs)) {
revert ExpiredTimestamp();
}
reportRate(intoUint256(report) * UD60X18_TO_FIXIDITY_SCALE);
}
/**
* @notice Report by looking up existing reports and building the lesser and greater keys.
* @dev Depending on the state in SortedOracles we can be in the:
* - Happy path: No reports, or a single report from this relayer.
* We can report with lesser and greater keys as address(0)
* - Unhappy path: There are reports from other oracles.
* We restrain this path by only computing lesser and greater keys when there is
* at most one report from a different oracle.
* We also attempt to expire reports in order to get back to the happy path.
* @param rate The rate to report.
*/
function reportRate(uint256 rate) internal {
(address[] memory oracles, uint256[] memory rates, ) = ISortedOraclesMin(sortedOracles).getRates(rateFeedId);
uint256 numRates = oracles.length;
if (numRates == 0 || (numRates == 1 && oracles[0] == address(this))) {
// Happy path: SortedOracles is empty, or there is a single report from this relayer.
ISortedOraclesMin(sortedOracles).report(rateFeedId, rate, address(0), address(0));
return;
}
if (numRates > 2 || (numRates == 2 && oracles[0] != address(this) && oracles[1] != address(this))) {
revert TooManyExistingReports();
}
// At this point we have ensured that either:
// - There is a single report from another oracle.
// - There are two reports and one is from this relayer.
address otherOracle;
uint256 otherRate;
if (numRates == 1 || oracles[0] != address(this)) {
otherOracle = oracles[0];
otherRate = rates[0];
} else {
otherOracle = oracles[1];
otherRate = rates[1];
}
address lesserKey;
address greaterKey;
if (otherRate < rate) {
lesserKey = otherOracle;
} else {
greaterKey = otherOracle;
}
ISortedOraclesMin(sortedOracles).report(rateFeedId, rate, lesserKey, greaterKey);
ISortedOraclesMin(sortedOracles).removeExpiredReports(rateFeedId, 1);
}
/**
* @notice Read and validate a Chainlink report from an aggregator.
* It inverts the value if necessary.
* @return price UD60x18 report value.
* @return timestamp uint256 timestamp of the report.
*/
function readChainlinkAggregator(ChainlinkAggregator memory aggCfg) internal view returns (UD60x18, uint256) {
(, int256 _price, , uint256 timestamp, ) = AggregatorV3Interface(aggCfg.aggregator).latestRoundData();
if (_price <= 0) {
revert InvalidPrice();
}
UD60x18 price = chainlinkToUD60x18(_price, aggCfg.aggregator);
if (aggCfg.invert) {
price = price.inv();
}
return (price, timestamp);
}
/**
* @notice Compose immutable variables into an in-memory array for better handling.
* @return aggregators An array of ChainlinkAggregator structs.
*/
function buildAggregatorArray() internal view returns (ChainlinkAggregator[] memory aggregators) {
aggregators = new ChainlinkAggregator[](aggregatorCount);
unchecked {
aggregators[0] = ChainlinkAggregator(aggregator0, invert0);
if (aggregatorCount > 1) {
aggregators[1] = ChainlinkAggregator(aggregator1, invert1);
if (aggregatorCount > 2) {
aggregators[2] = ChainlinkAggregator(aggregator2, invert2);
if (aggregatorCount > 3) {
aggregators[3] = ChainlinkAggregator(aggregator3, invert3);
}
}
}
}
}
/**
* @notice Checks if a Chainlink price's timestamp would be expired in SortedOracles.
* @param timestamp The timestamp returned by the Chainlink aggregator.
* @return `true` if expired based on SortedOracles expiry parameter.
*/
function isTimestampExpired(uint256 timestamp) internal view returns (bool) {
return block.timestamp - timestamp >= ISortedOraclesMin(sortedOracles).getTokenReportExpirySeconds(rateFeedId);
}
/**
* @notice Converts a Chainlink price to a UD60x18 value.
* @param price A price from the Chainlink aggregator.
* @return The converted UD60x18 value.
*/
function chainlinkToUD60x18(int256 price, address aggregator) internal view returns (UD60x18) {
uint256 chainlinkDecimals = uint256(AggregatorV3Interface(aggregator).decimals());
return ud(uint256(price) * 10**(18 - chainlinkDecimals));
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
/// Common mathematical functions used in both SD59x18 and UD60x18. Note that these global functions do not
/// always operate with SD59x18 and UD60x18 numbers.
/*//////////////////////////////////////////////////////////////////////////
CUSTOM ERRORS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Emitted when the ending result in the fixed-point version of `mulDiv` would overflow uint256.
error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);
/// @notice Emitted when the ending result in `mulDiv` would overflow uint256.
error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);
/// @notice Emitted when attempting to run `mulDiv` with one of the inputs `type(int256).min`.
error PRBMath_MulDivSigned_InputTooSmall();
/// @notice Emitted when the ending result in the signed version of `mulDiv` would overflow int256.
error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);
/*//////////////////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////////////////*/
/// @dev The maximum value an uint128 number can have.
uint128 constant MAX_UINT128 = type(uint128).max;
/// @dev The maximum value an uint40 number can have.
uint40 constant MAX_UINT40 = type(uint40).max;
/// @dev How many trailing decimals can be represented.
uint256 constant UNIT = 1e18;
/// @dev Largest power of two that is a divisor of `UNIT`.
uint256 constant UNIT_LPOTD = 262144;
/// @dev The `UNIT` number inverted mod 2^256.
uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;
/*//////////////////////////////////////////////////////////////////////////
FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
/// @notice Finds the zero-based index of the first one in the binary representation of x.
/// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set
///
/// Each of the steps in this implementation is equivalent to this high-level code:
///
/// ```solidity
/// if (x >= 2 ** 128) {
/// x >>= 128;
/// result += 128;
/// }
/// ```
///
/// Where 128 is swapped with each respective power of two factor. See the full high-level implementation here:
/// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
///
/// A list of the Yul instructions used below:
/// - "gt" is "greater than"
/// - "or" is the OR bitwise operator
/// - "shl" is "shift left"
/// - "shr" is "shift right"
///
/// @param x The uint256 number for which to find the index of the most significant bit.
/// @return result The index of the most significant bit as an uint256.
function msb(uint256 x) pure returns (uint256 result) {
// 2^128
assembly ("memory-safe") {
let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^64
assembly ("memory-safe") {
let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^32
assembly ("memory-safe") {
let factor := shl(5, gt(x, 0xFFFFFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^16
assembly ("memory-safe") {
let factor := shl(4, gt(x, 0xFFFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^8
assembly ("memory-safe") {
let factor := shl(3, gt(x, 0xFF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^4
assembly ("memory-safe") {
let factor := shl(2, gt(x, 0xF))
x := shr(factor, x)
result := or(result, factor)
}
// 2^2
assembly ("memory-safe") {
let factor := shl(1, gt(x, 0x3))
x := shr(factor, x)
result := or(result, factor)
}
// 2^1
// No need to shift x any more.
assembly ("memory-safe") {
let factor := gt(x, 0x1)
result := or(result, factor)
}
}
/// @notice Calculates floor(x*y÷denominator) with full precision.
///
/// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
///
/// Requirements:
/// - The denominator cannot be zero.
/// - The result must fit within uint256.
///
/// Caveats:
/// - This function does not work with fixed-point numbers.
///
/// @param x The multiplicand as an uint256.
/// @param y The multiplier as an uint256.
/// @param denominator The divisor as an uint256.
/// @return result The result as an uint256.
function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
// 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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
unchecked {
return prod0 / denominator;
}
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (prod1 >= denominator) {
revert PRBMath_MulDiv_Overflow(x, y, denominator);
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using the mulmod Yul instruction.
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.
unchecked {
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 lpotdod = denominator & (~denominator + 1);
assembly ("memory-safe") {
// Divide denominator by lpotdod.
denominator := div(denominator, lpotdod)
// Divide [prod1 prod0] by lpotdod.
prod0 := div(prod0, lpotdod)
// Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.
lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * lpotdod;
// 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;
}
}
/// @notice Calculates floor(x*y÷1e18) with full precision.
///
/// @dev Variant of `mulDiv` with constant folding, i.e. in which the denominator is always 1e18. Before returning the
/// final result, we add 1 if `(x * y) % UNIT >= HALF_UNIT`. Without this adjustment, 6.6e-19 would be truncated to 0
/// instead of being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717.
///
/// Requirements:
/// - The result must fit within uint256.
///
/// Caveats:
/// - The body is purposely left uncommented; to understand how this works, see the NatSpec comments in `mulDiv`.
/// - It is assumed that the result can never be `type(uint256).max` when x and y solve the following two equations:
/// 1. x * y = type(uint256).max * UNIT
/// 2. (x * y) % UNIT >= UNIT / 2
///
/// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
/// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
assembly ("memory-safe") {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 >= UNIT) {
revert PRBMath_MulDiv18_Overflow(x, y);
}
uint256 remainder;
assembly ("memory-safe") {
remainder := mulmod(x, y, UNIT)
}
if (prod1 == 0) {
unchecked {
return prod0 / UNIT;
}
}
assembly ("memory-safe") {
result := mul(
or(
div(sub(prod0, remainder), UNIT_LPOTD),
mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
),
UNIT_INVERSE
)
}
}
/// @notice Calculates floor(x*y÷denominator) with full precision.
///
/// @dev An extension of `mulDiv` for signed numbers. Works by computing the signs and the absolute values separately.
///
/// Requirements:
/// - None of the inputs can be `type(int256).min`.
/// - The result must fit within int256.
///
/// @param x The multiplicand as an int256.
/// @param y The multiplier as an int256.
/// @param denominator The divisor as an int256.
/// @return result The result as an int256.
function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
revert PRBMath_MulDivSigned_InputTooSmall();
}
// Get hold of the absolute values of x, y and the denominator.
uint256 absX;
uint256 absY;
uint256 absD;
unchecked {
absX = x < 0 ? uint256(-x) : uint256(x);
absY = y < 0 ? uint256(-y) : uint256(y);
absD = denominator < 0 ? uint256(-denominator) : uint256(denominator);
}
// Compute the absolute value of (x*y)÷denominator. The result must fit within int256.
uint256 rAbs = mulDiv(absX, absY, absD);
if (rAbs > uint256(type(int256).max)) {
revert PRBMath_MulDivSigned_Overflow(x, y);
}
// Get the signs of x, y and the denominator.
uint256 sx;
uint256 sy;
uint256 sd;
assembly ("memory-safe") {
// This works thanks to two's complement.
// "sgt" stands for "signed greater than" and "sub(0,1)" is max uint256.
sx := sgt(x, sub(0, 1))
sy := sgt(y, sub(0, 1))
sd := sgt(denominator, sub(0, 1))
}
// XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
// If there are, the result should be negative. Otherwise, it should be positive.
unchecked {
result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);
}
}
/// @notice Calculates the binary exponent of x using the binary fraction method.
/// @dev Has to use 192.64-bit fixed-point numbers.
/// See https://ethereum.stackexchange.com/a/96594/24693.
/// @param x The exponent as an unsigned 192.64-bit fixed-point number.
/// @return result The result as an unsigned 60.18-decimal fixed-point number.
function prbExp2(uint256 x) pure returns (uint256 result) {
unchecked {
// Start from 0.5 in the 192.64-bit fixed-point format.
result = 0x800000000000000000000000000000000000000000000000;
// Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows
// because the initial result is 2^191 and all magic factors are less than 2^65.
if (x & 0xFF00000000000000 > 0) {
if (x & 0x8000000000000000 > 0) {
result = (result * 0x16A09E667F3BCC909) >> 64;
}
if (x & 0x4000000000000000 > 0) {
result = (result * 0x1306FE0A31B7152DF) >> 64;
}
if (x & 0x2000000000000000 > 0) {
result = (result * 0x1172B83C7D517ADCE) >> 64;
}
if (x & 0x1000000000000000 > 0) {
result = (result * 0x10B5586CF9890F62A) >> 64;
}
if (x & 0x800000000000000 > 0) {
result = (result * 0x1059B0D31585743AE) >> 64;
}
if (x & 0x400000000000000 > 0) {
result = (result * 0x102C9A3E778060EE7) >> 64;
}
if (x & 0x200000000000000 > 0) {
result = (result * 0x10163DA9FB33356D8) >> 64;
}
if (x & 0x100000000000000 > 0) {
result = (result * 0x100B1AFA5ABCBED61) >> 64;
}
}
if (x & 0xFF000000000000 > 0) {
if (x & 0x80000000000000 > 0) {
result = (result * 0x10058C86DA1C09EA2) >> 64;
}
if (x & 0x40000000000000 > 0) {
result = (result * 0x1002C605E2E8CEC50) >> 64;
}
if (x & 0x20000000000000 > 0) {
result = (result * 0x100162F3904051FA1) >> 64;
}
if (x & 0x10000000000000 > 0) {
result = (result * 0x1000B175EFFDC76BA) >> 64;
}
if (x & 0x8000000000000 > 0) {
result = (result * 0x100058BA01FB9F96D) >> 64;
}
if (x & 0x4000000000000 > 0) {
result = (result * 0x10002C5CC37DA9492) >> 64;
}
if (x & 0x2000000000000 > 0) {
result = (result * 0x1000162E525EE0547) >> 64;
}
if (x & 0x1000000000000 > 0) {
result = (result * 0x10000B17255775C04) >> 64;
}
}
if (x & 0xFF0000000000 > 0) {
if (x & 0x800000000000 > 0) {
result = (result * 0x1000058B91B5BC9AE) >> 64;
}
if (x & 0x400000000000 > 0) {
result = (result * 0x100002C5C89D5EC6D) >> 64;
}
if (x & 0x200000000000 > 0) {
result = (result * 0x10000162E43F4F831) >> 64;
}
if (x & 0x100000000000 > 0) {
result = (result * 0x100000B1721BCFC9A) >> 64;
}
if (x & 0x80000000000 > 0) {
result = (result * 0x10000058B90CF1E6E) >> 64;
}
if (x & 0x40000000000 > 0) {
result = (result * 0x1000002C5C863B73F) >> 64;
}
if (x & 0x20000000000 > 0) {
result = (result * 0x100000162E430E5A2) >> 64;
}
if (x & 0x10000000000 > 0) {
result = (result * 0x1000000B172183551) >> 64;
}
}
if (x & 0xFF00000000 > 0) {
if (x & 0x8000000000 > 0) {
result = (result * 0x100000058B90C0B49) >> 64;
}
if (x & 0x4000000000 > 0) {
result = (result * 0x10000002C5C8601CC) >> 64;
}
if (x & 0x2000000000 > 0) {
result = (result * 0x1000000162E42FFF0) >> 64;
}
if (x & 0x1000000000 > 0) {
result = (result * 0x10000000B17217FBB) >> 64;
}
if (x & 0x800000000 > 0) {
result = (result * 0x1000000058B90BFCE) >> 64;
}
if (x & 0x400000000 > 0) {
result = (result * 0x100000002C5C85FE3) >> 64;
}
if (x & 0x200000000 > 0) {
result = (result * 0x10000000162E42FF1) >> 64;
}
if (x & 0x100000000 > 0) {
result = (result * 0x100000000B17217F8) >> 64;
}
}
if (x & 0xFF00000000 > 0) {
if (x & 0x80000000 > 0) {
result = (result * 0x10000000058B90BFC) >> 64;
}
if (x & 0x40000000 > 0) {
result = (result * 0x1000000002C5C85FE) >> 64;
}
if (x & 0x20000000 > 0) {
result = (result * 0x100000000162E42FF) >> 64;
}
if (x & 0x10000000 > 0) {
result = (result * 0x1000000000B17217F) >> 64;
}
if (x & 0x8000000 > 0) {
result = (result * 0x100000000058B90C0) >> 64;
}
if (x & 0x4000000 > 0) {
result = (result * 0x10000000002C5C860) >> 64;
}
if (x & 0x2000000 > 0) {
result = (result * 0x1000000000162E430) >> 64;
}
if (x & 0x1000000 > 0) {
result = (result * 0x10000000000B17218) >> 64;
}
}
if (x & 0xFF0000 > 0) {
if (x & 0x800000 > 0) {
result = (result * 0x1000000000058B90C) >> 64;
}
if (x & 0x400000 > 0) {
result = (result * 0x100000000002C5C86) >> 64;
}
if (x & 0x200000 > 0) {
result = (result * 0x10000000000162E43) >> 64;
}
if (x & 0x100000 > 0) {
result = (result * 0x100000000000B1721) >> 64;
}
if (x & 0x80000 > 0) {
result = (result * 0x10000000000058B91) >> 64;
}
if (x & 0x40000 > 0) {
result = (result * 0x1000000000002C5C8) >> 64;
}
if (x & 0x20000 > 0) {
result = (result * 0x100000000000162E4) >> 64;
}
if (x & 0x10000 > 0) {
result = (result * 0x1000000000000B172) >> 64;
}
}
if (x & 0xFF00 > 0) {
if (x & 0x8000 > 0) {
result = (result * 0x100000000000058B9) >> 64;
}
if (x & 0x4000 > 0) {
result = (result * 0x10000000000002C5D) >> 64;
}
if (x & 0x2000 > 0) {
result = (result * 0x1000000000000162E) >> 64;
}
if (x & 0x1000 > 0) {
result = (result * 0x10000000000000B17) >> 64;
}
if (x & 0x800 > 0) {
result = (result * 0x1000000000000058C) >> 64;
}
if (x & 0x400 > 0) {
result = (result * 0x100000000000002C6) >> 64;
}
if (x & 0x200 > 0) {
result = (result * 0x10000000000000163) >> 64;
}
if (x & 0x100 > 0) {
result = (result * 0x100000000000000B1) >> 64;
}
}
if (x & 0xFF > 0) {
if (x & 0x80 > 0) {
result = (result * 0x10000000000000059) >> 64;
}
if (x & 0x40 > 0) {
result = (result * 0x1000000000000002C) >> 64;
}
if (x & 0x20 > 0) {
result = (result * 0x10000000000000016) >> 64;
}
if (x & 0x10 > 0) {
result = (result * 0x1000000000000000B) >> 64;
}
if (x & 0x8 > 0) {
result = (result * 0x10000000000000006) >> 64;
}
if (x & 0x4 > 0) {
result = (result * 0x10000000000000003) >> 64;
}
if (x & 0x2 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
if (x & 0x1 > 0) {
result = (result * 0x10000000000000001) >> 64;
}
}
// We're doing two things at the same time:
//
// 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for
// the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191
// rather than 192.
// 2. Convert the result to the unsigned 60.18-decimal fixed-point format.
//
// This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n".
result *= UNIT;
result >>= (191 - (x >> 64));
}
}
/// @notice Calculates the square root of x, rounding down if x is not a perfect square.
/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
/// Credits to OpenZeppelin for the explanations in code comments below.
///
/// Caveats:
/// - This function does not work with fixed-point numbers.
///
/// @param x The uint256 number for which to calculate the square root.
/// @return result The result as an uint256.
function prbSqrt(uint256 x) pure returns (uint256 result) {
if (x == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of x.
//
// We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
//
// $$
// msb(x) <= x <= 2*msb(x)$
// $$
//
// We write $msb(x)$ as $2^k$ and we get:
//
// $$
// k = log_2(x)
// $$
//
// Thus we can write the initial inequality as:
//
// $$
// 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\
// sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\
// 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
// $$
//
// Consequently, $2^{log_2(x) /2}` is a good first approximation of sqrt(x) with at least one correct bit.
uint256 xAux = uint256(x);
result = 1;
if (xAux >= 2 ** 128) {
xAux >>= 128;
result <<= 64;
}
if (xAux >= 2 ** 64) {
xAux >>= 64;
result <<= 32;
}
if (xAux >= 2 ** 32) {
xAux >>= 32;
result <<= 16;
}
if (xAux >= 2 ** 16) {
xAux >>= 16;
result <<= 8;
}
if (xAux >= 2 ** 8) {
xAux >>= 8;
result <<= 4;
}
if (xAux >= 2 ** 4) {
xAux >>= 4;
result <<= 2;
}
if (xAux >= 2 ** 2) {
result <<= 1;
}
// At this point, `result` is an estimation with at least one bit of precision. We know the true value has at
// most 128 bits, 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 + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
result = (result + x / result) >> 1;
// Round down the result in case x is not a perfect square.
uint256 roundedDownResult = x / result;
if (result >= roundedDownResult) {
result = roundedDownResult;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { UD2x18 } from "./ValueType.sol";
/// @dev Euler's number as an UD2x18 number.
UD2x18 constant E = UD2x18.wrap(2_718281828459045235);
/// @dev The maximum value an UD2x18 number can have.
uint64 constant uMAX_UD2x18 = 18_446744073709551615;
UD2x18 constant MAX_UD2x18 = UD2x18.wrap(uMAX_UD2x18);
/// @dev PI as an UD2x18 number.
UD2x18 constant PI = UD2x18.wrap(3_141592653589793238);
/// @dev The unit amount that implies how many trailing decimals can be represented.
uint256 constant uUNIT = 1e18;
UD2x18 constant UNIT = UD2x18.wrap(1e18);
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { uMAX_UD60x18, uUNIT } from "./Constants.sol";
import { PRBMath_UD60x18_Convert_Overflow } from "./Errors.sol";
import { UD60x18 } from "./ValueType.sol";
/// @notice Converts an UD60x18 number to a simple integer by dividing it by `UNIT`. Rounds towards zero in the process.
/// @dev Rounds down in the process.
/// @param x The UD60x18 number to convert.
/// @return result The same number in basic integer form.
function convert(UD60x18 x) pure returns (uint256 result) {
result = UD60x18.unwrap(x) / uUNIT;
}
/// @notice Converts a simple integer to UD60x18 by multiplying it by `UNIT`.
///
/// @dev Requirements:
/// - x must be less than or equal to `MAX_UD60x18` divided by `UNIT`.
///
/// @param x The basic integer to convert.
/// @param result The same number converted to UD60x18.
function convert(uint256 x) pure returns (UD60x18 result) {
if (x > uMAX_UD60x18 / uUNIT) {
revert PRBMath_UD60x18_Convert_Overflow(x);
}
unchecked {
result = UD60x18.wrap(x * uUNIT);
}
}
/// @notice Alias for the `convert` function defined above.
/// @dev Here for backward compatibility. Will be removed in V4.
function fromUD60x18(UD60x18 x) pure returns (uint256 result) {
result = convert(x);
}
/// @notice Alias for the `convert` function defined above.
/// @dev Here for backward compatibility. Will be removed in V4.
function toUD60x18(uint256 x) pure returns (UD60x18 result) {
result = convert(x);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { SD1x18 } from "./ValueType.sol";
/// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in UD2x18.
error PRBMath_SD1x18_ToUD2x18_Underflow(SD1x18 x);
/// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in UD60x18.
error PRBMath_SD1x18_ToUD60x18_Underflow(SD1x18 x);
/// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint128.
error PRBMath_SD1x18_ToUint128_Underflow(SD1x18 x);
/// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint256.
error PRBMath_SD1x18_ToUint256_Underflow(SD1x18 x);
/// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Overflow(SD1x18 x);
/// @notice Emitted when trying to cast a SD1x18 number that doesn't fit in uint40.
error PRBMath_SD1x18_ToUint40_Underflow(SD1x18 x);
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { unwrap, wrap } from "./Casting.sol";
import { UD60x18 } from "./ValueType.sol";
/// @notice Implements the checked addition operation (+) in the UD60x18 type.
function add(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(unwrap(x) + unwrap(y));
}
/// @notice Implements the AND (&) bitwise operation in the UD60x18 type.
function and(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
result = wrap(unwrap(x) & bits);
}
/// @notice Implements the equal operation (==) in the UD60x18 type.
function eq(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = unwrap(x) == unwrap(y);
}
/// @notice Implements the greater than operation (>) in the UD60x18 type.
function gt(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = unwrap(x) > unwrap(y);
}
/// @notice Implements the greater than or equal to operation (>=) in the UD60x18 type.
function gte(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = unwrap(x) >= unwrap(y);
}
/// @notice Implements a zero comparison check function in the UD60x18 type.
function isZero(UD60x18 x) pure returns (bool result) {
// This wouldn't work if x could be negative.
result = unwrap(x) == 0;
}
/// @notice Implements the left shift operation (<<) in the UD60x18 type.
function lshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
result = wrap(unwrap(x) << bits);
}
/// @notice Implements the lower than operation (<) in the UD60x18 type.
function lt(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = unwrap(x) < unwrap(y);
}
/// @notice Implements the lower than or equal to operation (<=) in the UD60x18 type.
function lte(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = unwrap(x) <= unwrap(y);
}
/// @notice Implements the checked modulo operation (%) in the UD60x18 type.
function mod(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(unwrap(x) % unwrap(y));
}
/// @notice Implements the not equal operation (!=) in the UD60x18 type
function neq(UD60x18 x, UD60x18 y) pure returns (bool result) {
result = unwrap(x) != unwrap(y);
}
/// @notice Implements the OR (|) bitwise operation in the UD60x18 type.
function or(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(unwrap(x) | unwrap(y));
}
/// @notice Implements the right shift operation (>>) in the UD60x18 type.
function rshift(UD60x18 x, uint256 bits) pure returns (UD60x18 result) {
result = wrap(unwrap(x) >> bits);
}
/// @notice Implements the checked subtraction operation (-) in the UD60x18 type.
function sub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(unwrap(x) - unwrap(y));
}
/// @notice Implements the unchecked addition operation (+) in the UD60x18 type.
function uncheckedAdd(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
unchecked {
result = wrap(unwrap(x) + unwrap(y));
}
}
/// @notice Implements the unchecked subtraction operation (-) in the UD60x18 type.
function uncheckedSub(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
unchecked {
result = wrap(unwrap(x) - unwrap(y));
}
}
/// @notice Implements the XOR (^) bitwise operation in the UD60x18 type.
function xor(UD60x18 x, UD60x18 y) pure returns (UD60x18 result) {
result = wrap(unwrap(x) ^ unwrap(y));
}
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.5.13 <0.9;
pragma experimental ABIEncoderV2;
interface IChainlinkRelayer {
/**
* @notice Struct used to represent a segment in the price path.
* @member aggregator The address of the Chainlink aggregator.
* @member invert Wether to invert the aggregator's price feed, i.e. convert CELO/USD to USD/CELO.
*/
struct ChainlinkAggregator {
address aggregator;
bool invert;
}
function rateFeedId() external returns (address);
function rateFeedDescription() external returns (string memory);
function sortedOracles() external returns (address);
function getAggregators() external returns (ChainlinkAggregator[] memory);
function maxTimestampSpread() external returns (uint256);
function relay() external;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import { MAX_UINT128, MAX_UINT40, msb, mulDiv, mulDiv18, prbExp2, prbSqrt } from "../Common.sol";
import {
uHALF_UNIT,
uLOG2_10,
uLOG2_E,
uMAX_SD59x18,
uMAX_WHOLE_SD59x18,
uMIN_SD59x18,
uMIN_WHOLE_SD59x18,
UNIT,
uUNIT,
ZERO
} from "./Constants.sol";
import {
PRBMath_SD59x18_Abs_MinSD59x18,
PRBMath_SD59x18_Ceil_Overflow,
PRBMath_SD59x18_Div_InputTooSmall,
PRBMath_SD59x18_Div_Overflow,
PRBMath_SD59x18_Exp_InputTooBig,
PRBMath_SD59x18_Exp2_InputTooBig,
PRBMath_SD59x18_Floor_Underflow,
PRBMath_SD59x18_Gm_Overflow,
PRBMath_SD59x18_Gm_NegativeProduct,
PRBMath_SD59x18_Log_InputTooSmall,
PRBMath_SD59x18_Mul_InputTooSmall,
PRBMath_SD59x18_Mul_Overflow,
PRBMath_SD59x18_Powu_Overflow,
PRBMath_SD59x18_Sqrt_NegativeInput,
PRBMath_SD59x18_Sqrt_Overflow
} from "./Errors.sol";
import { unwrap, wrap } from "./Helpers.sol";
import { SD59x18 } from "./ValueType.sol";
/// @notice Calculate the absolute value of x.
///
/// @dev Requirements:
/// - x must be greater than `MIN_SD59x18`.
///
/// @param x The SD59x18 number for which to calculate the absolute value.
/// @param result The absolute value of x as an SD59x18 number.
function abs(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt == uMIN_SD59x18) {
revert PRBMath_SD59x18_Abs_MinSD59x18();
}
result = xInt < 0 ? wrap(-xInt) : x;
}
/// @notice Calculates the arithmetic average of x and y, rounding towards zero.
/// @param x The first operand as an SD59x18 number.
/// @param y The second operand as an SD59x18 number.
/// @return result The arithmetic average as an SD59x18 number.
function avg(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
int256 yInt = unwrap(y);
unchecked {
// This is equivalent to "x / 2 + y / 2" but faster.
// This operation can never overflow.
int256 sum = (xInt >> 1) + (yInt >> 1);
if (sum < 0) {
// If at least one of x and y is odd, we add 1 to the result, since shifting negative numbers to the right rounds
// down to infinity. The right part is equivalent to "sum + (x % 2 == 1 || y % 2 == 1)" but faster.
assembly ("memory-safe") {
result := add(sum, and(or(xInt, yInt), 1))
}
} else {
// We need to add 1 if both x and y are odd to account for the double 0.5 remainder that is truncated after shifting.
result = wrap(sum + (xInt & yInt & 1));
}
}
}
/// @notice Yields the smallest whole SD59x18 number greater than or equal to x.
///
/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x must be less than or equal to `MAX_WHOLE_SD59x18`.
///
/// @param x The SD59x18 number to ceil.
/// @param result The least number greater than or equal to x, as an SD59x18 number.
function ceil(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt > uMAX_WHOLE_SD59x18) {
revert PRBMath_SD59x18_Ceil_Overflow(x);
}
int256 remainder = xInt % uUNIT;
if (remainder == 0) {
result = x;
} else {
unchecked {
// Solidity uses C fmod style, which returns a modulus with the same sign as x.
int256 resultInt = xInt - remainder;
if (xInt > 0) {
resultInt += uUNIT;
}
result = wrap(resultInt);
}
}
}
/// @notice Divides two SD59x18 numbers, returning a new SD59x18 number. Rounds towards zero.
///
/// @dev This is a variant of `mulDiv` that works with signed numbers. Works by computing the signs and the absolute values
/// separately.
///
/// Requirements:
/// - All from `Common.mulDiv`.
/// - None of the inputs can be `MIN_SD59x18`.
/// - The denominator cannot be zero.
/// - The result must fit within int256.
///
/// Caveats:
/// - All from `Common.mulDiv`.
///
/// @param x The numerator as an SD59x18 number.
/// @param y The denominator as an SD59x18 number.
/// @param result The quotient as an SD59x18 number.
function div(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
int256 yInt = unwrap(y);
if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {
revert PRBMath_SD59x18_Div_InputTooSmall();
}
// Get hold of the absolute values of x and y.
uint256 xAbs;
uint256 yAbs;
unchecked {
xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);
yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);
}
// Compute the absolute value (x*UNIT)÷y. The resulting value must fit within int256.
uint256 resultAbs = mulDiv(xAbs, uint256(uUNIT), yAbs);
if (resultAbs > uint256(uMAX_SD59x18)) {
revert PRBMath_SD59x18_Div_Overflow(x, y);
}
// Check if x and y have the same sign. This works thanks to two's complement; the left-most bit is the sign bit.
bool sameSign = (xInt ^ yInt) > -1;
// If the inputs don't have the same sign, the result should be negative. Otherwise, it should be positive.
unchecked {
result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));
}
}
/// @notice Calculates the natural exponent of x.
///
/// @dev Based on the formula:
///
/// $$
/// e^x = 2^{x * log_2{e}}
/// $$
///
/// Requirements:
/// - All from `log2`.
/// - x must be less than 133.084258667509499441.
///
/// Caveats:
/// - All from `exp2`.
/// - For any x less than -41.446531673892822322, the result is zero.
///
/// @param x The exponent as an SD59x18 number.
/// @return result The result as an SD59x18 number.
function exp(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
// Without this check, the value passed to `exp2` would be less than -59.794705707972522261.
if (xInt < -41_446531673892822322) {
return ZERO;
}
// Without this check, the value passed to `exp2` would be greater than 192.
if (xInt >= 133_084258667509499441) {
revert PRBMath_SD59x18_Exp_InputTooBig(x);
}
unchecked {
// Do the fixed-point multiplication inline to save gas.
int256 doubleUnitProduct = xInt * uLOG2_E;
result = exp2(wrap(doubleUnitProduct / uUNIT));
}
}
/// @notice Calculates the binary exponent of x using the binary fraction method.
///
/// @dev Based on the formula:
///
/// $$
/// 2^{-x} = \frac{1}{2^x}
/// $$
///
/// See https://ethereum.stackexchange.com/q/79903/24693.
///
/// Requirements:
/// - x must be 192 or less.
/// - The result must fit within `MAX_SD59x18`.
///
/// Caveats:
/// - For any x less than -59.794705707972522261, the result is zero.
///
/// @param x The exponent as an SD59x18 number.
/// @return result The result as an SD59x18 number.
function exp2(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt < 0) {
// 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero.
if (xInt < -59_794705707972522261) {
return ZERO;
}
unchecked {
// Do the fixed-point inversion $1/2^x$ inline to save gas. 1e36 is UNIT * UNIT.
result = wrap(1e36 / unwrap(exp2(wrap(-xInt))));
}
} else {
// 2^192 doesn't fit within the 192.64-bit format used internally in this function.
if (xInt >= 192e18) {
revert PRBMath_SD59x18_Exp2_InputTooBig(x);
}
unchecked {
// Convert x to the 192.64-bit fixed-point format.
uint256 x_192x64 = uint256((xInt << 64) / uUNIT);
// It is safe to convert the result to int256 with no checks because the maximum input allowed in this function is 192.
result = wrap(int256(prbExp2(x_192x64)));
}
}
}
/// @notice Yields the greatest whole SD59x18 number less than or equal to x.
///
/// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
/// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
///
/// Requirements:
/// - x must be greater than or equal to `MIN_WHOLE_SD59x18`.
///
/// @param x The SD59x18 number to floor.
/// @param result The greatest integer less than or equal to x, as an SD59x18 number.
function floor(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt < uMIN_WHOLE_SD59x18) {
revert PRBMath_SD59x18_Floor_Underflow(x);
}
int256 remainder = xInt % uUNIT;
if (remainder == 0) {
result = x;
} else {
unchecked {
// Solidity uses C fmod style, which returns a modulus with the same sign as x.
int256 resultInt = xInt - remainder;
if (xInt < 0) {
resultInt -= uUNIT;
}
result = wrap(resultInt);
}
}
}
/// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right.
/// of the radix point for negative numbers.
/// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part
/// @param x The SD59x18 number to get the fractional part of.
/// @param result The fractional part of x as an SD59x18 number.
function frac(SD59x18 x) pure returns (SD59x18 result) {
result = wrap(unwrap(x) % uUNIT);
}
/// @notice Calculates the geometric mean of x and y, i.e. sqrt(x * y), rounding down.
///
/// @dev Requirements:
/// - x * y must fit within `MAX_SD59x18`, lest it overflows.
/// - x * y must not be negative, since this library does not handle complex numbers.
///
/// @param x The first operand as an SD59x18 number.
/// @param y The second operand as an SD59x18 number.
/// @return result The result as an SD59x18 number.
function gm(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
int256 yInt = unwrap(y);
if (xInt == 0 || yInt == 0) {
return ZERO;
}
unchecked {
// Equivalent to "xy / x != y". Checking for overflow this way is faster than letting Solidity do it.
int256 xyInt = xInt * yInt;
if (xyInt / xInt != yInt) {
revert PRBMath_SD59x18_Gm_Overflow(x, y);
}
// The product must not be negative, since this library does not handle complex numbers.
if (xyInt < 0) {
revert PRBMath_SD59x18_Gm_NegativeProduct(x, y);
}
// We don't need to multiply the result by `UNIT` here because the x*y product had picked up a factor of `UNIT`
// during multiplication. See the comments within the `prbSqrt` function.
uint256 resultUint = prbSqrt(uint256(xyInt));
result = wrap(int256(resultUint));
}
}
/// @notice Calculates 1 / x, rounding toward zero.
///
/// @dev Requirements:
/// - x cannot be zero.
///
/// @param x The SD59x18 number for which to calculate the inverse.
/// @return result The inverse as an SD59x18 number.
function inv(SD59x18 x) pure returns (SD59x18 result) {
// 1e36 is UNIT * UNIT.
result = wrap(1e36 / unwrap(x));
}
/// @notice Calculates the natural logarithm of x.
///
/// @dev Based on the formula:
///
/// $$
/// ln{x} = log_2{x} / log_2{e}$$.
/// $$
///
/// Requirements:
/// - All from `log2`.
///
/// Caveats:
/// - All from `log2`.
/// - This doesn't return exactly 1 for 2.718281828459045235, for that more fine-grained precision is needed.
///
/// @param x The SD59x18 number for which to calculate the natural logarithm.
/// @return result The natural logarithm as an SD59x18 number.
function ln(SD59x18 x) pure returns (SD59x18 result) {
// Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)
// can return is 195.205294292027477728.
result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_E);
}
/// @notice Calculates the common logarithm of x.
///
/// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common
/// logarithm based on the formula:
///
/// $$
/// log_{10}{x} = log_2{x} / log_2{10}
/// $$
///
/// Requirements:
/// - All from `log2`.
///
/// Caveats:
/// - All from `log2`.
///
/// @param x The SD59x18 number for which to calculate the common logarithm.
/// @return result The common logarithm as an SD59x18 number.
function log10(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt < 0) {
revert PRBMath_SD59x18_Log_InputTooSmall(x);
}
// Note that the `mul` in this block is the assembly mul operation, not the SD59x18 `mul`.
// prettier-ignore
assembly ("memory-safe") {
switch x
case 1 { result := mul(uUNIT, sub(0, 18)) }
case 10 { result := mul(uUNIT, sub(1, 18)) }
case 100 { result := mul(uUNIT, sub(2, 18)) }
case 1000 { result := mul(uUNIT, sub(3, 18)) }
case 10000 { result := mul(uUNIT, sub(4, 18)) }
case 100000 { result := mul(uUNIT, sub(5, 18)) }
case 1000000 { result := mul(uUNIT, sub(6, 18)) }
case 10000000 { result := mul(uUNIT, sub(7, 18)) }
case 100000000 { result := mul(uUNIT, sub(8, 18)) }
case 1000000000 { result := mul(uUNIT, sub(9, 18)) }
case 10000000000 { result := mul(uUNIT, sub(10, 18)) }
case 100000000000 { result := mul(uUNIT, sub(11, 18)) }
case 1000000000000 { result := mul(uUNIT, sub(12, 18)) }
case 10000000000000 { result := mul(uUNIT, sub(13, 18)) }
case 100000000000000 { result := mul(uUNIT, sub(14, 18)) }
case 1000000000000000 { result := mul(uUNIT, sub(15, 18)) }
case 10000000000000000 { result := mul(uUNIT, sub(16, 18)) }
case 100000000000000000 { result := mul(uUNIT, sub(17, 18)) }
case 1000000000000000000 { result := 0 }
case 10000000000000000000 { result := uUNIT }
case 100000000000000000000 { result := mul(uUNIT, 2) }
case 1000000000000000000000 { result := mul(uUNIT, 3) }
case 10000000000000000000000 { result := mul(uUNIT, 4) }
case 100000000000000000000000 { result := mul(uUNIT, 5) }
case 1000000000000000000000000 { result := mul(uUNIT, 6) }
case 10000000000000000000000000 { result := mul(uUNIT, 7) }
case 100000000000000000000000000 { result := mul(uUNIT, 8) }
case 1000000000000000000000000000 { result := mul(uUNIT, 9) }
case 10000000000000000000000000000 { result := mul(uUNIT, 10) }
case 100000000000000000000000000000 { result := mul(uUNIT, 11) }
case 1000000000000000000000000000000 { result := mul(uUNIT, 12) }
case 10000000000000000000000000000000 { result := mul(uUNIT, 13) }
case 100000000000000000000000000000000 { result := mul(uUNIT, 14) }
case 1000000000000000000000000000000000 { result := mul(uUNIT, 15) }
case 10000000000000000000000000000000000 { result := mul(uUNIT, 16) }
case 100000000000000000000000000000000000 { result := mul(uUNIT, 17) }
case 1000000000000000000000000000000000000 { result := mul(uUNIT, 18) }
case 10000000000000000000000000000000000000 { result := mul(uUNIT, 19) }
case 100000000000000000000000000000000000000 { result := mul(uUNIT, 20) }
case 1000000000000000000000000000000000000000 { result := mul(uUNIT, 21) }
case 10000000000000000000000000000000000000000 { result := mul(uUNIT, 22) }
case 100000000000000000000000000000000000000000 { result := mul(uUNIT, 23) }
case 1000000000000000000000000000000000000000000 { result := mul(uUNIT, 24) }
case 10000000000000000000000000000000000000000000 { result := mul(uUNIT, 25) }
case 100000000000000000000000000000000000000000000 { result := mul(uUNIT, 26) }
case 1000000000000000000000000000000000000000000000 { result := mul(uUNIT, 27) }
case 10000000000000000000000000000000000000000000000 { result := mul(uUNIT, 28) }
case 100000000000000000000000000000000000000000000000 { result := mul(uUNIT, 29) }
case 1000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 30) }
case 10000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 31) }
case 100000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 32) }
case 1000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 33) }
case 10000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 34) }
case 100000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 35) }
case 1000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 36) }
case 10000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 37) }
case 100000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 38) }
case 1000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 39) }
case 10000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 40) }
case 100000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 41) }
case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 42) }
case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 43) }
case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 44) }
case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 45) }
case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 46) }
case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 47) }
case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 48) }
case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 49) }
case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 50) }
case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 51) }
case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 52) }
case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 53) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 54) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 55) }
case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 56) }
case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 57) }
case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(uUNIT, 58) }
default {
result := uMAX_SD59x18
}
}
if (unwrap(result) == uMAX_SD59x18) {
unchecked {
// Do the fixed-point division inline to save gas.
result = wrap((unwrap(log2(x)) * uUNIT) / uLOG2_10);
}
}
}
/// @notice Calculates the binary logarithm of x.
///
/// @dev Based on the iterative approximation algorithm.
/// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
///
/// Requirements:
/// - x must be greater than zero.
///
/// Caveats:
/// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.
///
/// @param x The SD59x18 number for which to calculate the binary logarithm.
/// @return result The binary logarithm as an SD59x18 number.
function log2(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt <= 0) {
revert PRBMath_SD59x18_Log_InputTooSmall(x);
}
unchecked {
// This works because of:
//
// $$
// log_2{x} = -log_2{\frac{1}{x}}
// $$
int256 sign;
if (xInt >= uUNIT) {
sign = 1;
} else {
sign = -1;
// Do the fixed-point inversion inline to save gas. The numerator is UNIT * UNIT.
xInt = 1e36 / xInt;
}
// Calculate the integer part of the logarithm and add it to the result and finally calculate $y = x * 2^(-n)$.
uint256 n = msb(uint256(xInt / uUNIT));
// This is the integer part of the logarithm as an SD59x18 number. The operation can't overflow
// because n is maximum 255, UNIT is 1e18 and sign is either 1 or -1.
int256 resultInt = int256(n) * uUNIT;
// This is $y = x * 2^{-n}$.
int256 y = xInt >> n;
// If y is 1, the fractional part is zero.
if (y == uUNIT) {
return wrap(resultInt * sign);
}
// Calculate the fractional part via the iterative approximation.
// The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
int256 DOUBLE_UNIT = 2e18;
for (int256 delta = uHALF_UNIT; delta > 0; delta >>= 1) {
y = (y * y) / uUNIT;
// Is $y^2 > 2$ and so in the range [2,4)?
if (y >= DOUBLE_UNIT) {
// Add the 2^{-m} factor to the logarithm.
resultInt = resultInt + delta;
// Corresponds to z/2 on Wikipedia.
y >>= 1;
}
}
resultInt *= sign;
result = wrap(resultInt);
}
}
/// @notice Multiplies two SD59x18 numbers together, returning a new SD59x18 number.
///
/// @dev This is a variant of `mulDiv` that works with signed numbers and employs constant folding, i.e. the denominator
/// is always 1e18.
///
/// Requirements:
/// - All from `Common.mulDiv18`.
/// - None of the inputs can be `MIN_SD59x18`.
/// - The result must fit within `MAX_SD59x18`.
///
/// Caveats:
/// - To understand how this works in detail, see the NatSpec comments in `Common.mulDivSigned`.
///
/// @param x The multiplicand as an SD59x18 number.
/// @param y The multiplier as an SD59x18 number.
/// @return result The product as an SD59x18 number.
function mul(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
int256 yInt = unwrap(y);
if (xInt == uMIN_SD59x18 || yInt == uMIN_SD59x18) {
revert PRBMath_SD59x18_Mul_InputTooSmall();
}
// Get hold of the absolute values of x and y.
uint256 xAbs;
uint256 yAbs;
unchecked {
xAbs = xInt < 0 ? uint256(-xInt) : uint256(xInt);
yAbs = yInt < 0 ? uint256(-yInt) : uint256(yInt);
}
uint256 resultAbs = mulDiv18(xAbs, yAbs);
if (resultAbs > uint256(uMAX_SD59x18)) {
revert PRBMath_SD59x18_Mul_Overflow(x, y);
}
// Check if x and y have the same sign. This works thanks to two's complement; the left-most bit is the sign bit.
bool sameSign = (xInt ^ yInt) > -1;
// If the inputs have the same sign, the result should be negative. Otherwise, it should be positive.
unchecked {
result = wrap(sameSign ? int256(resultAbs) : -int256(resultAbs));
}
}
/// @notice Raises x to the power of y.
///
/// @dev Based on the formula:
///
/// $$
/// x^y = 2^{log_2{x} * y}
/// $$
///
/// Requirements:
/// - All from `exp2`, `log2` and `mul`.
/// - x cannot be zero.
///
/// Caveats:
/// - All from `exp2`, `log2` and `mul`.
/// - Assumes 0^0 is 1.
///
/// @param x Number to raise to given power y, as an SD59x18 number.
/// @param y Exponent to raise x to, as an SD59x18 number
/// @return result x raised to power y, as an SD59x18 number.
function pow(SD59x18 x, SD59x18 y) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
int256 yInt = unwrap(y);
if (xInt == 0) {
result = yInt == 0 ? UNIT : ZERO;
} else {
if (yInt == uUNIT) {
result = x;
} else {
result = exp2(mul(log2(x), y));
}
}
}
/// @notice Raises x (an SD59x18 number) to the power y (unsigned basic integer) using the famous algorithm
/// algorithm "exponentiation by squaring".
///
/// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring
///
/// Requirements:
/// - All from `abs` and `Common.mulDiv18`.
/// - The result must fit within `MAX_SD59x18`.
///
/// Caveats:
/// - All from `Common.mulDiv18`.
/// - Assumes 0^0 is 1.
///
/// @param x The base as an SD59x18 number.
/// @param y The exponent as an uint256.
/// @return result The result as an SD59x18 number.
function powu(SD59x18 x, uint256 y) pure returns (SD59x18 result) {
uint256 xAbs = uint256(unwrap(abs(x)));
// Calculate the first iteration of the loop in advance.
uint256 resultAbs = y & 1 > 0 ? xAbs : uint256(uUNIT);
// Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
uint256 yAux = y;
for (yAux >>= 1; yAux > 0; yAux >>= 1) {
xAbs = mulDiv18(xAbs, xAbs);
// Equivalent to "y % 2 == 1" but faster.
if (yAux & 1 > 0) {
resultAbs = mulDiv18(resultAbs, xAbs);
}
}
// The result must fit within `MAX_SD59x18`.
if (resultAbs > uint256(uMAX_SD59x18)) {
revert PRBMath_SD59x18_Powu_Overflow(x, y);
}
unchecked {
// Is the base negative and the exponent an odd number?
int256 resultInt = int256(resultAbs);
bool isNegative = unwrap(x) < 0 && y & 1 == 1;
if (isNegative) {
resultInt = -resultInt;
}
result = wrap(resultInt);
}
}
/// @notice Calculates the square root of x, rounding down. Only the positive root is returned.
/// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
///
/// Requirements:
/// - x cannot be negative, since this library does not handle complex numbers.
/// - x must be less than `MAX_SD59x18` divided by `UNIT`.
///
/// @param x The SD59x18 number for which to calculate the square root.
/// @return result The result as an SD59x18 number.
function sqrt(SD59x18 x) pure returns (SD59x18 result) {
int256 xInt = unwrap(x);
if (xInt < 0) {
revert PRBMath_SD59x18_Sqrt_NegativeInput(x);
}
if (xInt > uMAX_SD59x18 / uUNIT) {
revert PRBMath_SD59x18_Sqrt_Overflow(x);
}
unchecked {
// Multiply x by `UNIT` to account for the factor of `UNIT` that is picked up when multiplying two SD59x18
// numbers together (in this case, the two numbers are both the square root).
uint256 resultUint = prbSqrt(uint256(xInt * uUNIT));
result = wrap(int256(resultUint));
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import "./ud60x18/Casting.sol";
import "./ud60x18/Constants.sol";
import "./ud60x18/Conversions.sol";
import "./ud60x18/Errors.sol";
import "./ud60x18/Helpers.sol";
import "./ud60x18/Math.sol";
import "./ud60x18/ValueType.sol";
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;
import "./Casting.sol" as C;
/// @notice The signed 1.18-decimal fixed-point number representation, which can have up to 1 digit and up to 18 decimals.
/// The values of this are bound by the minimum and the maximum values permitted by the underlying Solidity type int64.
/// This is useful when end users want to use int64 to save gas, e.g. with tight variable packing in contract storage.
type SD1x18 is int64;
/*//////////////////////////////////////////////////////////////////////////
CASTING
//////////////////////////////////////////////////////////////////////////*/
using { C.intoSD59x18, C.intoUD2x18, C.intoUD60x18, C.intoUint256, C.intoUint128, C.intoUint40, C.unwrap } for SD1x18 global;
{
"compilationTarget": {
"lib/mento-core-2.5.0/contracts/oracles/ChainlinkRelayerV1.sol": "ChainlinkRelayerV1"
},
"evmVersion": "paris",
"libraries": {
"lib/mento-core-2.0.0/contracts/common/linkedlists/AddressLinkedList.sol:AddressLinkedList": "0x6200f54d73491d56b8d7a975c9ee18efb4d518df",
"lib/mento-core-2.0.0/contracts/common/linkedlists/AddressSortedLinkedListWithMedian.sol:AddressSortedLinkedListWithMedian": "0xed477a99035d0c1e11369f1d7a4e587893cc002b"
},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": [
":@chainlink/contracts/=lib/mento-core-2.5.0/lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/",
":@openzeppelin/=lib/mento-core-2.5.0/lib/foundry-chainlink-toolkit/lib/openzeppelin-contracts/",
":@prb/test/=lib/mento-core-2.5.0/lib/prb-math/lib/prb-test/src/",
":celo-foundry/=lib/celo-foundry/src/",
":chainlink-brownie-contracts/=lib/mento-core-2.5.0/lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",
":contracts/=contracts/",
":ds-test/=lib/celo-foundry/lib/forge-std/lib/ds-test/src/",
":forge-std-next/=lib/forge-std-next/src/",
":forge-std/=lib/celo-foundry/lib/forge-std/src/",
":foundry-chainlink-toolkit/=lib/mento-core-2.5.0/lib/foundry-chainlink-toolkit/",
":mento-core-2.0.0/=lib/mento-core-2.0.0/contracts/",
":mento-core-2.1.0/=lib/mento-core-2.1.0/contracts/",
":mento-core-2.2.0/=lib/mento-core-2.2.0/contracts/",
":mento-core-2.3.1/=lib/mento-core-2.3.1/contracts/",
":mento-core-2.5.0/=lib/mento-core-2.5.0/contracts/",
":openzeppelin-contracts-next/=lib/mento-core-2.3.1/lib/openzeppelin-contracts-next/",
":openzeppelin-contracts-upgradeable/=lib/mento-core-2.3.1/lib/openzeppelin-contracts-upgradeable/",
":openzeppelin-contracts/=lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/",
":openzeppelin-solidity/=lib/mento-core-2.0.0/lib/openzeppelin-contracts/",
":prb-math/=lib/mento-core-2.5.0/lib/prb-math/src/",
":prb-test/=lib/mento-core-2.5.0/lib/prb-math/lib/prb-test/src/",
":prb/math/=lib/mento-core-2.5.0/lib/prb-math/src/",
":safe-contracts/=lib/mento-core-2.3.1/lib/safe-contracts/",
":src/=lib/mento-core-2.5.0/lib/prb-math/src/",
":test/=lib/mento-core-2.0.0/test/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_rateFeedId","type":"address"},{"internalType":"string","name":"_rateFeedDescription","type":"string"},{"internalType":"address","name":"_sortedOracles","type":"address"},{"internalType":"uint256","name":"_maxTimestampSpread","type":"uint256"},{"components":[{"internalType":"address","name":"aggregator","type":"address"},{"internalType":"bool","name":"invert","type":"bool"}],"internalType":"struct IChainlinkRelayer.ChainlinkAggregator[]","name":"_aggregators","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExpiredTimestamp","type":"error"},{"inputs":[],"name":"InvalidAggregator","type":"error"},{"inputs":[],"name":"InvalidMaxTimestampSpread","type":"error"},{"inputs":[],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"NoAggregators","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"name":"PRBMath_MulDiv18_Overflow","type":"error"},{"inputs":[],"name":"TimestampNotNew","type":"error"},{"inputs":[],"name":"TimestampSpreadTooHigh","type":"error"},{"inputs":[],"name":"TooManyAggregators","type":"error"},{"inputs":[],"name":"TooManyExistingReports","type":"error"},{"inputs":[],"name":"getAggregators","outputs":[{"components":[{"internalType":"address","name":"aggregator","type":"address"},{"internalType":"bool","name":"invert","type":"bool"}],"internalType":"struct IChainlinkRelayer.ChainlinkAggregator[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTimestampSpread","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateFeedDescription","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateFeedId","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sortedOracles","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]