Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
OrigamiCrossRateOracle
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (common/oracle/OrigamiCrossRateOracle.sol) import { IOrigamiOracle } from "contracts/interfaces/common/oracle/IOrigamiOracle.sol"; import { OrigamiOracleBase } from "contracts/common/oracle/OrigamiOracleBase.sol"; import { OrigamiMath } from "contracts/libraries/OrigamiMath.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; /** * @title OrigamiCrossRateOracle * @notice A derived cross rate oracle price, by dividing baseOracle / quotedOracle * @dev Both baseOracle and quotedOracle prices are checked against a valid range (eg a peg). * If outside of that range, the latestPrice() function will revert. */ contract OrigamiCrossRateOracle is OrigamiOracleBase { using OrigamiMath for uint256; /** * @notice The oracle used for the base asset price * ie the LHS in a XXX/YYY quote * @dev For [DAI/USDC] = [DAI/USD]/[USDC/USD], baseOracle would point to the [DAI/USD] oracle */ IOrigamiOracle public immutable baseAssetOracle; /** * @notice The oracle used for the quote asset price * ie the RHS in a XXX/YYY quote * @dev For [DAI/USDC] = [DAI/USD]/[USDC/USD], quotedOracle would point to the [USDC/USD] oracle */ IOrigamiOracle public immutable quoteAssetOracle; /** * @notice An oracle to lookup, used to ensure this reference price is valid and does not revert. * @dev Can be set to address(0) to disable the check */ IOrigamiOracle public immutable priceCheckOracle; /** * @notice Whether to multiply or to divide the two rates. */ bool public immutable multiply; constructor ( BaseOracleParams memory baseParams, address _baseAssetOracle, address _quoteAssetOracle, address _priceCheckOracle ) OrigamiOracleBase(baseParams) { baseAssetOracle = IOrigamiOracle(_baseAssetOracle); quoteAssetOracle = IOrigamiOracle(_quoteAssetOracle); priceCheckOracle = IOrigamiOracle(_priceCheckOracle); // This oracle handles either: // baseAsset/quoteAsset = baseAsset/crossAsset * crossAsset/quoteAsset // baseAsset/quoteAsset = baseAsset/crossAsset / quoteAsset/crossAsset // So apply checks that it all matches: // 1. The base asset must match the baseAssetOracle's base asset if (baseAssetOracle.baseAsset() != baseParams.baseAssetAddress) revert CommonEventsAndErrors.InvalidParam(); // 2. The quote asset and the cross asset must match the quoteAssetOracle, in either order. address _crossAsset = baseAssetOracle.quoteAsset(); if (!quoteAssetOracle.matchAssets(_crossAsset, baseParams.quoteAssetAddress)) revert CommonEventsAndErrors.InvalidParam(); multiply = quoteAsset == quoteAssetOracle.quoteAsset(); } /** * @notice Return the latest oracle price, to `decimals` precision * @dev This may still revert - eg if deemed stale, div by 0, negative price * @param priceType What kind of price - Spot or Historic * @param roundingMode Round the price at each intermediate step such that the final price rounds in the specified direction. */ function latestPrice( PriceType priceType, OrigamiMath.Rounding roundingMode ) public override view returns (uint256) { // check reference price is valid and does not revert if (address(priceCheckOracle) != address(0)) priceCheckOracle.latestPrice(priceType, roundingMode); // baseOracle (the numerator) price follows the requested roundingMode // So if roundDown, then we want the numerator to be lower (round down) uint256 _basePrice = baseAssetOracle.latestPrice( priceType, roundingMode ); if (multiply) { // Also the numerator - so follow the requested roundingMode uint256 _quotePrice = quoteAssetOracle.latestPrice( priceType, roundingMode ); return _basePrice.mulDiv(_quotePrice, precision, roundingMode); } else { // quotedOracle (the denominator) price follows the opposite roundingMode // So if roundDown, then we want the denominator to be higher (round up) uint256 _quotePrice = quoteAssetOracle.latestPrice( priceType, roundingMode == OrigamiMath.Rounding.ROUND_DOWN ? OrigamiMath.Rounding.ROUND_UP : OrigamiMath.Rounding.ROUND_DOWN ); if (_quotePrice == 0) revert InvalidPrice(address(quoteAssetOracle), int256(_quotePrice)); // Final price follows the requested roundingMode return _basePrice.mulDiv(precision, _quotePrice, roundingMode); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; // Common.sol // // Common mathematical functions needed by both SD59x18 and UD60x18. Note that these global functions do not // always operate with SD59x18 and UD60x18 numbers. /*////////////////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when the resultant value in {mulDiv} overflows uint256. error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator); /// @notice Thrown when the resultant value in {mulDiv18} overflows uint256. error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y); /// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`. error PRBMath_MulDivSigned_InputTooSmall(); /// @notice Thrown when the resultant value in {mulDivSigned} overflows int256. error PRBMath_MulDivSigned_Overflow(int256 x, int256 y); /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ /// @dev The maximum value a uint128 number can have. uint128 constant MAX_UINT128 = type(uint128).max; /// @dev The maximum value a uint40 number can have. uint40 constant MAX_UINT40 = type(uint40).max; /// @dev The unit number, which the decimal precision of the fixed-point types. uint256 constant UNIT = 1e18; /// @dev The unit number inverted mod 2^256. uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant /// bit in the binary representation of `UNIT`. uint256 constant UNIT_LPOTD = 262144; /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @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. /// @custom:smtchecker abstract-function-nondet function exp2(uint256 x) pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points: // // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65. // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1, // we know that `x & 0xFF` is also 1. 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 & 0xFF000000 > 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; } } // In the code snippet below, two operations are executed simultaneously: // // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1 // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192. // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format. // // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the, // integer part, $2^n$. result *= UNIT; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first 1 in the binary representation of x. /// /// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set /// /// Each step in this implementation is equivalent to this high-level code: /// /// ```solidity /// if (x >= 2 ** 128) { /// x >>= 128; /// result += 128; /// } /// ``` /// /// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here: /// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948 /// /// The Yul instructions used below are: /// /// - "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 a uint256. /// @custom:smtchecker abstract-function-nondet 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 x*y÷denominator with 512-bit precision. /// /// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - The denominator must not be zero. /// - The result must fit in uint256. /// /// @param x The multiplicand as a uint256. /// @param y The multiplier as a uint256. /// @param denominator The divisor as a uint256. /// @return result The result as a uint256. /// @custom:smtchecker abstract-function-nondet 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) } unchecked { // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow // because the denominator cannot be zero at this point in the function execution. The result is always >= 1. // For more detail, see https://cs.stackexchange.com/q/138556/92363. uint256 lpotdod = denominator & (~denominator + 1); uint256 flippedLpotdod; assembly ("memory-safe") { // Factor powers of two out of denominator. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one. // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits. // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693 flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * flippedLpotdod; // 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 x*y÷1e18 with 512-bit precision. /// /// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18. /// /// Notes: /// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}. /// - The result is rounded toward zero. /// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations: /// /// $$ /// \begin{cases} /// x * y = MAX\_UINT256 * UNIT \\ /// (x * y) \% UNIT \geq \frac{UNIT}{2} /// \end{cases} /// $$ /// /// Requirements: /// - Refer to the requirements in {mulDiv}. /// - The result must fit in uint256. /// /// @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. /// @custom:smtchecker abstract-function-nondet 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 == 0) { unchecked { return prod0 / UNIT; } } if (prod1 >= UNIT) { revert PRBMath_MulDiv18_Overflow(x, y); } uint256 remainder; assembly ("memory-safe") { remainder := mulmod(x, y, UNIT) 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 x*y÷denominator with 512-bit precision. /// /// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - Refer to the requirements in {mulDiv}. /// - None of the inputs can be `type(int256).min`. /// - The result must fit in 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. /// @custom:smtchecker abstract-function-nondet 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 xAbs; uint256 yAbs; uint256 dAbs; unchecked { xAbs = x < 0 ? uint256(-x) : uint256(x); yAbs = y < 0 ? uint256(-y) : uint256(y); dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of x*y÷denominator. The result must fit in int256. uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs); if (resultAbs > 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") { // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement. 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(resultAbs) : int256(resultAbs); } } /// @notice Calculates the square root of x using the Babylonian method. /// /// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Notes: /// - If x is not a perfect square, the result is rounded down. /// - Credits to OpenZeppelin for the explanations in comments below. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as a uint256. /// @custom:smtchecker abstract-function-nondet function sqrt(uint256 x) pure returns (uint256 result) { if (x == 0) { return 0; } // For our first guess, we calculate 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; // If x is not a perfect square, round the result toward zero. uint256 roundedResult = x / result; if (result >= roundedResult) { result = roundedResult; } } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (common/oracle/OrigamiOracleBase.sol) import { IOrigamiOracle } from "contracts/interfaces/common/oracle/IOrigamiOracle.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; import { OrigamiMath } from "contracts/libraries/OrigamiMath.sol"; /** * @title OrigamiOracleBase * @notice Common base logic for Origami Oracle's */ abstract contract OrigamiOracleBase is IOrigamiOracle { using OrigamiMath for uint256; /** * @notice The address used to reference the baseAsset for amount conversions */ address public immutable override baseAsset; /** * @notice The address used to reference the quoteAsset for amount conversions */ address public immutable override quoteAsset; /** * @notice The number of decimals of precision the oracle price is returned as */ uint8 public constant override decimals = 18; /** * @notice The precision that the cross rate oracle price is returned as: `10^decimals` */ uint256 public constant override precision = 1e18; /** * @notice When converting from baseAsset<->quoteAsset, the fixed point amounts * need to be scaled by this amount. */ uint256 public immutable override assetScalingFactor; /** * @notice A human readable description for this origami oracle */ string public override description; constructor(BaseOracleParams memory params) { description = params.description; baseAsset = params.baseAssetAddress; quoteAsset = params.quoteAssetAddress; if (params.quoteAssetDecimals > decimals + params.baseAssetDecimals) revert CommonEventsAndErrors.InvalidParam(); assetScalingFactor = 10 ** (decimals + params.baseAssetDecimals - params.quoteAssetDecimals); } /** * @notice Return the latest oracle price, to `decimals` precision * @dev This may still revert - eg if deemed stale, div by 0, negative price * @param priceType What kind of price - Spot or Historic * @param roundingMode Round the price at each intermediate step such that the final price rounds in the specified direction. */ function latestPrice( PriceType priceType, OrigamiMath.Rounding roundingMode ) public virtual override view returns (uint256 price); /** * @notice Same as `latestPrice()` but for two separate prices from this oracle */ function latestPrices( PriceType priceType1, OrigamiMath.Rounding roundingMode1, PriceType priceType2, OrigamiMath.Rounding roundingMode2 ) external virtual override view returns ( uint256 /*price1*/, uint256 /*price2*/, address /*oracleBaseAsset*/, address /*oracleQuoteAsset*/ ) { return ( latestPrice(priceType1, roundingMode1), latestPrice(priceType2, roundingMode2), baseAsset, quoteAsset ); } /** * @notice Convert either the baseAsset->quoteAsset or quoteAsset->baseAsset * @dev The `fromAssetAmount` needs to be in it's natural fixed point precision (eg USDC=6dp) * The `toAssetAmount` will also be returned in it's natural fixed point precision */ function convertAmount( address fromAsset, uint256 fromAssetAmount, PriceType priceType, OrigamiMath.Rounding roundingMode ) external override view returns (uint256 toAssetAmount) { if (fromAsset == baseAsset) { // The numerator needs to round in the same way to be conservative uint256 _price = latestPrice( priceType, roundingMode ); return fromAssetAmount.mulDiv( _price, assetScalingFactor, roundingMode ); } else if (fromAsset == quoteAsset) { // The denominator needs to round in the opposite way to be conservative uint256 _price = latestPrice( priceType, roundingMode == OrigamiMath.Rounding.ROUND_UP ? OrigamiMath.Rounding.ROUND_DOWN : OrigamiMath.Rounding.ROUND_UP ); if (_price == 0) revert InvalidPrice(address(this), int256(_price)); return fromAssetAmount.mulDiv( assetScalingFactor, _price, roundingMode ); } revert CommonEventsAndErrors.InvalidToken(fromAsset); } /** * @notice Match whether a pair of assets match the base and quote asset on this oracle, in either order */ function matchAssets(address asset1, address asset2) public view returns (bool) { return ( (asset1 == baseAsset && asset2 == quoteAsset) || (asset2 == baseAsset && asset1 == quoteAsset) ); } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (interfaces/common/oracle/IOrigamiOracle.sol) import { OrigamiMath } from "contracts/libraries/OrigamiMath.sol"; /** * @notice An oracle which returns prices for pairs of assets, where an asset * could refer to a token (eg DAI) or a currency (eg USD) * Convention is the same as the FX market. Given the DAI/USD pair: * - DAI = Base Asset (LHS of pair) * - USD = Quote Asset (RHS of pair) * This price defines how many USD you get if selling 1 DAI * * Further, an oracle can define two PriceType's: * - SPOT_PRICE: The latest spot price, for example from a chainlink oracle * - HISTORIC_PRICE: An expected (eg 1:1 peg) or calculated historic price (eg TWAP) * * For assets which do are not tokens (eg USD), an internal address reference will be used * since this is for internal purposes only */ interface IOrigamiOracle { error InvalidPrice(address oracle, int256 price); error InvalidOracleData(address oracle); error StalePrice(address oracle, uint256 lastUpdatedAt, int256 price); error UnknownPriceType(uint8 priceType); error BelowMinValidRange(address oracle, uint256 price, uint128 floor); error AboveMaxValidRange(address oracle, uint256 price, uint128 ceiling); event ValidPriceRangeSet(uint128 validFloor, uint128 validCeiling); enum PriceType { /// @notice The current spot price of this Oracle SPOT_PRICE, /// @notice The historic price of this Oracle. /// It may be a fixed expectation (eg DAI/USD would be fixed to 1) /// or use a TWAP or some other moving average, etc. HISTORIC_PRICE } /** * @dev Wrapped in a struct to remove stack-too-deep constraints */ struct BaseOracleParams { string description; address baseAssetAddress; uint8 baseAssetDecimals; address quoteAssetAddress; uint8 quoteAssetDecimals; } /** * @notice The address used to reference the baseAsset for amount conversions */ function baseAsset() external view returns (address); /** * @notice The address used to reference the quoteAsset for amount conversions */ function quoteAsset() external view returns (address); /** * @notice The number of decimals of precision the price is returned as */ function decimals() external view returns (uint8); /** * @notice The precision that the cross rate oracle price is returned as: `10^decimals` */ function precision() external view returns (uint256); /** * @notice When converting from baseAsset<->quoteAsset, the fixed point amounts * need to be scaled by this amount. */ function assetScalingFactor() external view returns (uint256); /** * @notice A human readable description for this oracle */ function description() external view returns (string memory); /** * @notice Return the latest oracle price, to `decimals` precision * @dev This may still revert - eg if deemed stale, div by 0, negative price * @param priceType What kind of price - Spot or Historic * @param roundingMode Round the price at each intermediate step such that the final price rounds in the specified direction. */ function latestPrice( PriceType priceType, OrigamiMath.Rounding roundingMode ) external view returns (uint256 price); /** * @notice Same as `latestPrice()` but for two separate prices from this oracle */ function latestPrices( PriceType priceType1, OrigamiMath.Rounding roundingMode1, PriceType priceType2, OrigamiMath.Rounding roundingMode2 ) external view returns ( uint256 price1, uint256 price2, address oracleBaseAsset, address oracleQuoteAsset ); /** * @notice Convert either the baseAsset->quoteAsset or quoteAsset->baseAsset * @dev The `fromAssetAmount` needs to be in it's natural fixed point precision (eg USDC=6dp) * The `toAssetAmount` will also be returned in it's natural fixed point precision */ function convertAmount( address fromAsset, uint256 fromAssetAmount, PriceType priceType, OrigamiMath.Rounding roundingMode ) external view returns (uint256 toAssetAmount); /** * @notice Match whether a pair of assets match the base and quote asset on this oracle, in either order */ function matchAssets(address asset1, address asset2) external view returns (bool); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (libraries/CommonEventsAndErrors.sol) /// @notice A collection of common events and errors thrown within the Origami contracts library CommonEventsAndErrors { error InsufficientBalance(address token, uint256 required, uint256 balance); error InvalidToken(address token); error InvalidParam(); error InvalidAddress(address addr); error InvalidAmount(address token, uint256 amount); error ExpectedNonZero(); error Slippage(uint256 minAmountExpected, uint256 actualAmount); error IsPaused(); error UnknownExecuteError(bytes returndata); error InvalidAccess(); error BreachedMaxTotalSupply(uint256 totalSupply, uint256 maxTotalSupply); event TokenRecovered(address indexed to, address indexed token, uint256 amount); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (libraries/OrigamiMath.sol) import { mulDiv as prbMulDiv, PRBMath_MulDiv_Overflow } from "@prb/math/src/Common.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; /** * @notice Utilities to operate on fixed point math multipliation and division * taking rounding into consideration */ library OrigamiMath { enum Rounding { ROUND_DOWN, ROUND_UP } uint256 public constant BASIS_POINTS_DIVISOR = 10_000; function scaleUp(uint256 amount, uint256 scalar) internal pure returns (uint256) { // Special case for scalar == 1, as it's common for token amounts to not need // scaling if decimal places are the same return scalar == 1 ? amount : amount * scalar; } function scaleDown( uint256 amount, uint256 scalar, Rounding roundingMode ) internal pure returns (uint256 result) { // Special case for scalar == 1, as it's common for token amounts to not need // scaling if decimal places are the same unchecked { if (scalar == 1) { result = amount; } else if (roundingMode == Rounding.ROUND_DOWN) { result = amount / scalar; } else { // ROUND_UP uses the same logic as OZ Math.ceilDiv() result = amount == 0 ? 0 : (amount - 1) / scalar + 1; } } } /** * @notice Calculates x * y / denominator with full precision, * rounding up */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding roundingMode ) internal pure returns (uint256 result) { result = prbMulDiv(x, y, denominator); if (roundingMode == Rounding.ROUND_UP) { if (mulmod(x, y, denominator) != 0) { if (result < type(uint256).max) { unchecked { result = result + 1; } } else { revert PRBMath_MulDiv_Overflow(x, y, denominator); } } } } function subtractBps( uint256 inputAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result) { uint256 numeratorBps; unchecked { numeratorBps = BASIS_POINTS_DIVISOR - basisPoints; } result = basisPoints < BASIS_POINTS_DIVISOR ? mulDiv( inputAmount, numeratorBps, BASIS_POINTS_DIVISOR, roundingMode ) : 0; } function addBps( uint256 inputAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result) { uint256 numeratorBps; unchecked { numeratorBps = BASIS_POINTS_DIVISOR + basisPoints; } // Round up for max amounts out expected result = mulDiv( inputAmount, numeratorBps, BASIS_POINTS_DIVISOR, roundingMode ); } /** * @notice Split the `inputAmount` into two parts based on the `basisPoints` fraction. * eg: 3333 BPS (33.3%) can be used to split an input amount of 600 into: (result=400, removed=200). * @dev The rounding mode is applied to the `result` */ function splitSubtractBps( uint256 inputAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result, uint256 removed) { result = subtractBps(inputAmount, basisPoints, roundingMode); unchecked { removed = inputAmount - result; } } /** * @notice Reverse the fractional amount of an input. * eg: For 3333 BPS (33.3%) and the remainder=400, the result is 600 */ function inverseSubtractBps( uint256 remainderAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result) { if (basisPoints == 0) return remainderAmount; // gas shortcut for 0 if (basisPoints >= BASIS_POINTS_DIVISOR) revert CommonEventsAndErrors.InvalidParam(); uint256 denominatorBps; unchecked { denominatorBps = BASIS_POINTS_DIVISOR - basisPoints; } result = mulDiv( remainderAmount, BASIS_POINTS_DIVISOR, denominatorBps, roundingMode ); } /** * @notice Calculate the relative difference of a value to a reference * @dev `value` and `referenceValue` must have the same precision * The denominator is always the referenceValue */ function relativeDifferenceBps( uint256 value, uint256 referenceValue, Rounding roundingMode ) internal pure returns (uint256) { if (referenceValue == 0) revert CommonEventsAndErrors.InvalidParam(); uint256 absDelta; unchecked { absDelta = value < referenceValue ? referenceValue - value : value - referenceValue; } return mulDiv( absDelta, BASIS_POINTS_DIVISOR, referenceValue, roundingMode ); } }
{ "optimizer": { "enabled": true, "runs": 10000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"internalType":"string","name":"description","type":"string"},{"internalType":"address","name":"baseAssetAddress","type":"address"},{"internalType":"uint8","name":"baseAssetDecimals","type":"uint8"},{"internalType":"address","name":"quoteAssetAddress","type":"address"},{"internalType":"uint8","name":"quoteAssetDecimals","type":"uint8"}],"internalType":"struct IOrigamiOracle.BaseOracleParams","name":"baseParams","type":"tuple"},{"internalType":"address","name":"_baseAssetOracle","type":"address"},{"internalType":"address","name":"_quoteAssetOracle","type":"address"},{"internalType":"address","name":"_priceCheckOracle","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint128","name":"ceiling","type":"uint128"}],"name":"AboveMaxValidRange","type":"error"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint128","name":"floor","type":"uint128"}],"name":"BelowMinValidRange","type":"error"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"}],"name":"InvalidOracleData","type":"error"},{"inputs":[],"name":"InvalidParam","type":"error"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"int256","name":"price","type":"int256"}],"name":"InvalidPrice","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"InvalidToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath_MulDiv_Overflow","type":"error"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"lastUpdatedAt","type":"uint256"},{"internalType":"int256","name":"price","type":"int256"}],"name":"StalePrice","type":"error"},{"inputs":[{"internalType":"uint8","name":"priceType","type":"uint8"}],"name":"UnknownPriceType","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"validFloor","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"validCeiling","type":"uint128"}],"name":"ValidPriceRangeSet","type":"event"},{"inputs":[],"name":"assetScalingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseAssetOracle","outputs":[{"internalType":"contract IOrigamiOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAsset","type":"address"},{"internalType":"uint256","name":"fromAssetAmount","type":"uint256"},{"internalType":"enum IOrigamiOracle.PriceType","name":"priceType","type":"uint8"},{"internalType":"enum OrigamiMath.Rounding","name":"roundingMode","type":"uint8"}],"name":"convertAmount","outputs":[{"internalType":"uint256","name":"toAssetAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOrigamiOracle.PriceType","name":"priceType","type":"uint8"},{"internalType":"enum OrigamiMath.Rounding","name":"roundingMode","type":"uint8"}],"name":"latestPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOrigamiOracle.PriceType","name":"priceType1","type":"uint8"},{"internalType":"enum OrigamiMath.Rounding","name":"roundingMode1","type":"uint8"},{"internalType":"enum IOrigamiOracle.PriceType","name":"priceType2","type":"uint8"},{"internalType":"enum OrigamiMath.Rounding","name":"roundingMode2","type":"uint8"}],"name":"latestPrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset1","type":"address"},{"internalType":"address","name":"asset2","type":"address"}],"name":"matchAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiply","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceCheckOracle","outputs":[{"internalType":"contract IOrigamiOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteAssetOracle","outputs":[{"internalType":"contract IOrigamiOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101606040523480156200001257600080fd5b50604051620018f4380380620018f48339810160408190526200003591620003b8565b83518490600090620000489082620005ae565b5060208101516001600160a01b0390811660805260608201511660a05260408101516200007790601262000690565b60ff16816080015160ff161115620000a257604051633494a40d60e21b815260040160405180910390fd5b60808101516040820151620000b990601262000690565b620000c59190620006b2565b620000d290600a620007cb565b60c052506001600160a01b0380841660e081905283821661010052828216610120526020808701516040805163cdf456e160e01b81529051919094169363cdf456e19260048083019391928290030181865afa15801562000137573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200015d9190620007e3565b6001600160a01b0316146200018557604051633494a40d60e21b815260040160405180910390fd5b600060e0516001600160a01b031663fdf262b76040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001c8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ee9190620007e3565b61010051606087015160405163012a042560e71b81526001600160a01b03808516600483015291821660248201529293501690639502128090604401602060405180830381865afa15801562000248573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200026e919062000801565b6200028c57604051633494a40d60e21b815260040160405180910390fd5b610100516001600160a01b031663fdf262b76040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002ce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f49190620007e3565b60a0516001600160a01b039081169116146101405250620008259350505050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b038111828210171562000350576200035062000315565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000381576200038162000315565b604052919050565b80516001600160a01b0381168114620003a157600080fd5b919050565b805160ff81168114620003a157600080fd5b60008060008060808587031215620003cf57600080fd5b84516001600160401b0380821115620003e757600080fd5b9086019060a08289031215620003fc57600080fd5b620004066200032b565b8251828111156200041657600080fd5b8301601f81018a136200042857600080fd5b8051838111156200043d576200043d62000315565b6020935062000455601f8201601f1916850162000356565b8181528b858385010111156200046a57600080fd5b60005b828110156200048a5783810186015182820187015285016200046d565b506000858383010152808452505050620004a682840162000389565b82820152620004b860408401620003a6565b6040820152620004cb6060840162000389565b6060820152620004de60808401620003a6565b60808201529550620004f287820162000389565b94505050620005046040860162000389565b9150620005146060860162000389565b905092959194509250565b600181811c908216806200053457607f821691505b6020821081036200055557634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005a957600081815260208120601f850160051c81016020861015620005845750805b601f850160051c820191505b81811015620005a55782815560010162000590565b5050505b505050565b81516001600160401b03811115620005ca57620005ca62000315565b620005e281620005db84546200051f565b846200055b565b602080601f8311600181146200061a5760008415620006015750858301515b600019600386901b1c1916600185901b178555620005a5565b600085815260208120601f198616915b828110156200064b578886015182559484019460019091019084016200062a565b50858210156200066a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b60ff8181168382160190811115620006ac57620006ac6200067a565b92915050565b60ff8281168282160390811115620006ac57620006ac6200067a565b600181815b808511156200070f578160001904821115620006f357620006f36200067a565b808516156200070157918102915b93841c9390800290620006d3565b509250929050565b6000826200072857506001620006ac565b816200073757506000620006ac565b81600181146200075057600281146200075b576200077b565b6001915050620006ac565b60ff8411156200076f576200076f6200067a565b50506001821b620006ac565b5060208310610133831016604e8410600b8410161715620007a0575081810a620006ac565b620007ac8383620006ce565b8060001904821115620007c357620007c36200067a565b029392505050565b6000620007dc60ff84168362000717565b9392505050565b600060208284031215620007f657600080fd5b620007dc8262000389565b6000602082840312156200081457600080fd5b81518015158114620007dc57600080fd5b60805160a05160c05160e051610100516101205161014051610ffd620008f7600039600081816102c501526108f601526000818161020b0152818161074901526107c00152600081816101ae0152818161095a01528181610a0a0152610af7015260008181610113015261087a0152600081816102320152818161047301526105700152600081816102ec01528181610352015281816104a20152818161064201526106ee01526000818161028f0152818161032f0152818161040d015281816105ec01526106980152610ffd6000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638fc5e88d1161008c578063cdf456e111610066578063cdf456e11461028a578063d3b5dc3b146102b1578063f3593cd0146102c0578063fdf262b7146102e757600080fd5b80638fc5e88d1461022d5780639502128014610254578063c6845a091461027757600080fd5b80636d4469bd116100c85780636d4469bd146101a95780637284e416146101d05780637349615f146101e5578063766800341461020657600080fd5b8063313ce567146100ef578063528e16071461010e578063699945111461015a575b600080fd5b6100f7601281565b60405160ff90911681526020015b60405180910390f35b6101357f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610105565b61016d610168366004610d0d565b61030e565b60408051948552602085019390935273ffffffffffffffffffffffffffffffffffffffff91821692840192909252166060820152608001610105565b6101357f000000000000000000000000000000000000000000000000000000000000000081565b6101d861037b565b6040516101059190610d69565b6101f86101f3366004610dfe565b610409565b604051908152602001610105565b6101357f000000000000000000000000000000000000000000000000000000000000000081565b6101f87f000000000000000000000000000000000000000000000000000000000000000081565b610267610262366004610e34565b6105e8565b6040519015158152602001610105565b6101f8610285366004610e67565b610745565b6101357f000000000000000000000000000000000000000000000000000000000000000081565b6101f8670de0b6b3a764000081565b6102677f000000000000000000000000000000000000000000000000000000000000000081565b6101357f000000000000000000000000000000000000000000000000000000000000000081565b60008060008061031e8888610745565b6103288787610745565b90999098507f000000000000000000000000000000000000000000000000000000000000000097507f00000000000000000000000000000000000000000000000000000000000000009650945050505050565b6000805461038890610ea0565b80601f01602080910402602001604051908101604052809291908181526020018280546103b490610ea0565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036104a057600061046a8484610745565b905061049885827f000000000000000000000000000000000000000000000000000000000000000086610b3b565b9150506105e0565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361059657600061052084600185600181111561050d5761050d610ef3565b14610519576001610745565b6000610745565b90508060000361056a576040517fdcd07d4f000000000000000000000000000000000000000000000000000000008152306004820152602481018290526044015b60405180910390fd5b610498857f00000000000000000000000000000000000000000000000000000000000000008386610b3b565b6040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610561565b949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614801561069057507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b8061073c57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614801561073c57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b90505b92915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161561083a576040517fc6845a0900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c6845a09906107f79086908690600401610f59565b602060405180830381865afa158015610814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108389190610f7f565b505b6040517fc6845a0900000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c6845a09906108b19087908790600401610f59565b602060405180830381865afa1580156108ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f29190610f7f565b90507f0000000000000000000000000000000000000000000000000000000000000000156109f1576040517fc6845a0900000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c6845a09906109919088908890600401610f59565b602060405180830381865afa1580156109ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d29190610f7f565b90506109e88282670de0b6b3a764000087610b3b565b9250505061073f565b600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663c6845a098683876001811115610a4357610a43610ef3565b14610a4f576000610a52565b60015b6040518363ffffffff1660e01b8152600401610a6f929190610f59565b602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab09190610f7f565b905080600003610b2b576040517fdcd07d4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260248101829052604401610561565b6109e882670de0b6b3a764000083875b6000610b48858585610bec565b90506001826001811115610b5e57610b5e610ef3565b036105e0578280610b7157610b71610f98565b848609156105e0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811015610ba9576001016105e0565b6040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018690526024810185905260448101849052606401610561565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003610c4457838281610c3a57610c3a610f98565b0492505050610cf6565b838110610c8e576040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018790526024810186905260448101859052606401610561565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b60028110610d0a57600080fd5b50565b60008060008060808587031215610d2357600080fd5b8435610d2e81610cfd565b93506020850135610d3e81610cfd565b92506040850135610d4e81610cfd565b91506060850135610d5e81610cfd565b939692955090935050565b600060208083528351808285015260005b81811015610d9657858101830151858201604001528201610d7a565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610df957600080fd5b919050565b60008060008060808587031215610e1457600080fd5b610e1d85610dd5565b9350602085013592506040850135610d4e81610cfd565b60008060408385031215610e4757600080fd5b610e5083610dd5565b9150610e5e60208401610dd5565b90509250929050565b60008060408385031215610e7a57600080fd5b8235610e8581610cfd565b91506020830135610e9581610cfd565b809150509250929050565b600181811c90821680610eb457607f821691505b602082108103610eed577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110610d0a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60408101610f6684610f22565b838252610f7283610f22565b8260208301529392505050565b600060208284031215610f9157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220691d063425df5e2e1faaa6da4e660130ba2e480231016d7665362310caeef91364736f6c6343000813003300000000000000000000000000000000000000000000000000000000000000800000000000000000000000002267a91555dc492aeab78999263e09635135b3a700000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f500000000000000000000000010400df986c4e5c295e889b114644b75a565733700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8100000000000000000000000000000000000000000000000000000000000000120000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001450542d73555344652d4d6172323032352f444149000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638fc5e88d1161008c578063cdf456e111610066578063cdf456e11461028a578063d3b5dc3b146102b1578063f3593cd0146102c0578063fdf262b7146102e757600080fd5b80638fc5e88d1461022d5780639502128014610254578063c6845a091461027757600080fd5b80636d4469bd116100c85780636d4469bd146101a95780637284e416146101d05780637349615f146101e5578063766800341461020657600080fd5b8063313ce567146100ef578063528e16071461010e578063699945111461015a575b600080fd5b6100f7601281565b60405160ff90911681526020015b60405180910390f35b6101357f0000000000000000000000002267a91555dc492aeab78999263e09635135b3a781565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610105565b61016d610168366004610d0d565b61030e565b60408051948552602085019390935273ffffffffffffffffffffffffffffffffffffffff91821692840192909252166060820152608001610105565b6101357f00000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f581565b6101d861037b565b6040516101059190610d69565b6101f86101f3366004610dfe565b610409565b604051908152602001610105565b6101357f00000000000000000000000010400df986c4e5c295e889b114644b75a565733781565b6101f87f0000000000000000000000000000000000000000000000000de0b6b3a764000081565b610267610262366004610e34565b6105e8565b6040519015158152602001610105565b6101f8610285366004610e67565b610745565b6101357f000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8181565b6101f8670de0b6b3a764000081565b6102677f000000000000000000000000000000000000000000000000000000000000000181565b6101357f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81565b60008060008061031e8888610745565b6103288787610745565b90999098507f000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8197507f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f9650945050505050565b6000805461038890610ea0565b80601f01602080910402602001604051908101604052809291908181526020018280546103b490610ea0565b80156104015780601f106103d657610100808354040283529160200191610401565b820191906000526020600020905b8154815290600101906020018083116103e457829003601f168201915b505050505081565b60007f000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036104a057600061046a8484610745565b905061049885827f0000000000000000000000000000000000000000000000000de0b6b3a764000086610b3b565b9150506105e0565b7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff160361059657600061052084600185600181111561050d5761050d610ef3565b14610519576001610745565b6000610745565b90508060000361056a576040517fdcd07d4f000000000000000000000000000000000000000000000000000000008152306004820152602481018290526044015b60405180910390fd5b610498857f0000000000000000000000000000000000000000000000000de0b6b3a76400008386610b3b565b6040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86166004820152602401610561565b949350505050565b60007f000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614801561069057507f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b8061073c57507f000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614801561073c57507f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16145b90505b92915050565b60007f00000000000000000000000010400df986c4e5c295e889b114644b75a565733773ffffffffffffffffffffffffffffffffffffffff161561083a576040517fc6845a0900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010400df986c4e5c295e889b114644b75a5657337169063c6845a09906107f79086908690600401610f59565b602060405180830381865afa158015610814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108389190610f7f565b505b6040517fc6845a0900000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002267a91555dc492aeab78999263e09635135b3a7169063c6845a09906108b19087908790600401610f59565b602060405180830381865afa1580156108ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f29190610f7f565b90507f0000000000000000000000000000000000000000000000000000000000000001156109f1576040517fc6845a0900000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f5169063c6845a09906109919088908890600401610f59565b602060405180830381865afa1580156109ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d29190610f7f565b90506109e88282670de0b6b3a764000087610b3b565b9250505061073f565b600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f51663c6845a098683876001811115610a4357610a43610ef3565b14610a4f576000610a52565b60015b6040518363ffffffff1660e01b8152600401610a6f929190610f59565b602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab09190610f7f565b905080600003610b2b576040517fdcd07d4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f516600482015260248101829052604401610561565b6109e882670de0b6b3a764000083875b6000610b48858585610bec565b90506001826001811115610b5e57610b5e610ef3565b036105e0578280610b7157610b71610f98565b848609156105e0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811015610ba9576001016105e0565b6040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018690526024810185905260448101849052606401610561565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003610c4457838281610c3a57610c3a610f98565b0492505050610cf6565b838110610c8e576040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018790526024810186905260448101859052606401610561565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b60028110610d0a57600080fd5b50565b60008060008060808587031215610d2357600080fd5b8435610d2e81610cfd565b93506020850135610d3e81610cfd565b92506040850135610d4e81610cfd565b91506060850135610d5e81610cfd565b939692955090935050565b600060208083528351808285015260005b81811015610d9657858101830151858201604001528201610d7a565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610df957600080fd5b919050565b60008060008060808587031215610e1457600080fd5b610e1d85610dd5565b9350602085013592506040850135610d4e81610cfd565b60008060408385031215610e4757600080fd5b610e5083610dd5565b9150610e5e60208401610dd5565b90509250929050565b60008060408385031215610e7a57600080fd5b8235610e8581610cfd565b91506020830135610e9581610cfd565b809150509250929050565b600181811c90821680610eb457607f821691505b602082108103610eed577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110610d0a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60408101610f6684610f22565b838252610f7283610f22565b8260208301529392505050565b600060208284031215610f9157600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220691d063425df5e2e1faaa6da4e660130ba2e480231016d7665362310caeef91364736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000800000000000000000000000002267a91555dc492aeab78999263e09635135b3a700000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f500000000000000000000000010400df986c4e5c295e889b114644b75a565733700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b8100000000000000000000000000000000000000000000000000000000000000120000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001450542d73555344652d4d6172323032352f444149000000000000000000000000
-----Decoded View---------------
Arg [0] : baseParams (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : _baseAssetOracle (address): 0x2267a91555DC492aeab78999263e09635135b3A7
Arg [2] : _quoteAssetOracle (address): 0x39CfDbEfe1e7ccF0665675a3c3f6469b61dD32F5
Arg [3] : _priceCheckOracle (address): 0x10400DF986C4E5C295e889b114644b75A5657337
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 0000000000000000000000002267a91555dc492aeab78999263e09635135b3a7
Arg [2] : 00000000000000000000000039cfdbefe1e7ccf0665675a3c3f6469b61dd32f5
Arg [3] : 00000000000000000000000010400df986c4e5c295e889b114644b75a5657337
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [5] : 000000000000000000000000e00bd3df25fb187d6abbb620b3dfd19839947b81
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [7] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [10] : 50542d73555344652d4d6172323032352f444149000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.