Contract
0x52cbE0f49CcdD4Dc6E9C13BAb024EABD2842045B
14
Contract Overview
Balance:
0 ETH
EtherValue:
$0.00
My Name Tag:
Not Available, login to update
Latest 2 internal transactions
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0xbd07d3356eb9d1233ba809ec351cf6b05d2902feef299179c2530503bcd75ef2 | 106824950 | 77 days 2 hrs ago | 0xb2c3d786bb84764524a3d558d3e5a2d61a0c403d | 0x52cbe0f49ccdd4dc6e9c13bab024eabd2842045b | 0 ETH | ||
0xbd07d3356eb9d1233ba809ec351cf6b05d2902feef299179c2530503bcd75ef2 | 106824950 | 77 days 2 hrs ago | 0xb2c3d786bb84764524a3d558d3e5a2d61a0c403d | Contract Creation | 0 ETH |
[ Download CSV Export ]
Contract Name:
OffchainOracle
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { 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) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IOracle { error ConnectorShouldBeNone(); error PoolNotFound(); error PoolWithConnectorNotFound(); function getRate(IERC20 srcToken, IERC20 dstToken, IERC20 connector) external view returns (uint256 rate, uint256 weight); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWrapper { error NotSupportedToken(); error NotAddedMarket(); error NotRemovedMarket(); function wrap(IERC20 token) external view returns (IERC20 wrappedToken, uint256 rate); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; library Sqrt { function sqrt(uint y) internal pure returns (uint z) { unchecked { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./interfaces/IWrapper.sol"; contract MultiWrapper is Ownable { using SafeMath for uint256; using EnumerableSet for EnumerableSet.AddressSet; error WrapperAlreadyAdded(); error UnknownWrapper(); event WrapperAdded(IWrapper connector); event WrapperRemoved(IWrapper connector); EnumerableSet.AddressSet private _wrappers; constructor(IWrapper[] memory existingWrappers) { unchecked { for (uint256 i = 0; i < existingWrappers.length; i++) { if(!_wrappers.add(address(existingWrappers[i]))) revert WrapperAlreadyAdded(); emit WrapperAdded(existingWrappers[i]); } } } function wrappers() external view returns (IWrapper[] memory allWrappers) { allWrappers = new IWrapper[](_wrappers.length()); unchecked { for (uint256 i = 0; i < allWrappers.length; i++) { allWrappers[i] = IWrapper(address(uint160(uint256(_wrappers._inner._values[i])))); } } } function addWrapper(IWrapper wrapper) external onlyOwner { if(!_wrappers.add(address(wrapper))) revert WrapperAlreadyAdded(); emit WrapperAdded(wrapper); } function removeWrapper(IWrapper wrapper) external onlyOwner { if(!_wrappers.remove(address(wrapper))) revert UnknownWrapper(); emit WrapperRemoved(wrapper); } function getWrappedTokens(IERC20 token) external view returns (IERC20[] memory wrappedTokens, uint256[] memory rates) { unchecked { IERC20[] memory memWrappedTokens = new IERC20[](20); uint256[] memory memRates = new uint256[](20); uint256 len = 0; for (uint256 i = 0; i < _wrappers._inner._values.length; i++) { try IWrapper(address(uint160(uint256(_wrappers._inner._values[i])))).wrap(token) returns (IERC20 wrappedToken, uint256 rate) { memWrappedTokens[len] = wrappedToken; memRates[len] = rate; len += 1; for (uint256 j = 0; j < _wrappers._inner._values.length; j++) { if (i != j) { try IWrapper(address(uint160(uint256(_wrappers._inner._values[j])))).wrap(wrappedToken) returns (IERC20 wrappedToken2, uint256 rate2) { bool used = false; for (uint256 k = 0; k < len; k++) { if (wrappedToken2 == memWrappedTokens[k]) { used = true; break; } } if (!used) { memWrappedTokens[len] = wrappedToken2; memRates[len] = rate.mul(rate2).div(1e18); len += 1; } } catch { continue; } } } } catch { continue; } } wrappedTokens = new IERC20[](len + 1); rates = new uint256[](len + 1); for (uint256 i = 0; i < len; i++) { wrappedTokens[i] = memWrappedTokens[i]; rates[i] = memRates[i]; } wrappedTokens[len] = token; rates[len] = 1e18; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./interfaces/IOracle.sol"; import "./interfaces/IWrapper.sol"; import "./MultiWrapper.sol"; import "./libraries/Sqrt.sol"; contract OffchainOracle is Ownable { using Math for uint256; using SafeMath for uint256; using Sqrt for uint256; using EnumerableSet for EnumerableSet.AddressSet; error ArraysLengthMismatch(); error OracleAlreadyAdded(); error ConnectorAlreadyAdded(); error InvalidOracleTokenKind(); error UnknownOracle(); error UnknownConnector(); error SameTokens(); error TooBigThreshold(); enum OracleType { WETH, ETH, WETH_ETH } event OracleAdded(IOracle oracle, OracleType oracleType); event OracleRemoved(IOracle oracle, OracleType oracleType); event ConnectorAdded(IERC20 connector); event ConnectorRemoved(IERC20 connector); event MultiWrapperUpdated(MultiWrapper multiWrapper); struct OraclePrice { uint256 rate; uint256 weight; } EnumerableSet.AddressSet private _wethOracles; EnumerableSet.AddressSet private _ethOracles; EnumerableSet.AddressSet private _connectors; MultiWrapper public multiWrapper; IERC20 private constant _BASE = IERC20(0x0000000000000000000000000000000000000000); IERC20 private immutable _wBase; constructor(MultiWrapper _multiWrapper, IOracle[] memory existingOracles, OracleType[] memory oracleTypes, IERC20[] memory existingConnectors, IERC20 wBase, address owner) { unchecked { if(existingOracles.length != oracleTypes.length) revert ArraysLengthMismatch(); multiWrapper = _multiWrapper; emit MultiWrapperUpdated(_multiWrapper); for (uint256 i = 0; i < existingOracles.length; i++) { if (oracleTypes[i] == OracleType.WETH) { if(!_wethOracles.add(address(existingOracles[i]))) revert OracleAlreadyAdded(); } else if (oracleTypes[i] == OracleType.ETH) { if(!_ethOracles.add(address(existingOracles[i]))) revert OracleAlreadyAdded(); } else if (oracleTypes[i] == OracleType.WETH_ETH) { if(!_wethOracles.add(address(existingOracles[i]))) revert OracleAlreadyAdded(); if(!_ethOracles.add(address(existingOracles[i]))) revert OracleAlreadyAdded(); } else { revert InvalidOracleTokenKind(); } emit OracleAdded(existingOracles[i], oracleTypes[i]); } for (uint256 i = 0; i < existingConnectors.length; i++) { if(!_connectors.add(address(existingConnectors[i]))) revert ConnectorAlreadyAdded(); emit ConnectorAdded(existingConnectors[i]); } _wBase = wBase; } if (owner != msg.sender) transferOwnership(owner); } /** * @notice Returns all registered oracles along with their corresponding oracle types. * @return allOracles An array of all registered oracles * @return oracleTypes An array of the corresponding types for each oracle */ function oracles() public view returns (IOracle[] memory allOracles, OracleType[] memory oracleTypes) { unchecked { IOracle[] memory oraclesBuffer = new IOracle[](_wethOracles._inner._values.length + _ethOracles._inner._values.length); OracleType[] memory oracleTypesBuffer = new OracleType[](oraclesBuffer.length); for (uint256 i = 0; i < _wethOracles._inner._values.length; i++) { oraclesBuffer[i] = IOracle(address(uint160(uint256(_wethOracles._inner._values[i])))); oracleTypesBuffer[i] = OracleType.WETH; } uint256 actualItemsCount = _wethOracles._inner._values.length; for (uint256 i = 0; i < _ethOracles._inner._values.length; i++) { OracleType kind = OracleType.ETH; uint256 oracleIndex = actualItemsCount; IOracle oracle = IOracle(address(uint160(uint256(_ethOracles._inner._values[i])))); for (uint j = 0; j < oraclesBuffer.length; j++) { if (oraclesBuffer[j] == oracle) { oracleIndex = j; kind = OracleType.WETH_ETH; break; } } if (kind == OracleType.ETH) { actualItemsCount++; } oraclesBuffer[oracleIndex] = oracle; oracleTypesBuffer[oracleIndex] = kind; } allOracles = new IOracle[](actualItemsCount); oracleTypes = new OracleType[](actualItemsCount); for (uint256 i = 0; i < actualItemsCount; i++) { allOracles[i] = oraclesBuffer[i]; oracleTypes[i] = oracleTypesBuffer[i]; } } } /** * @notice Returns an array of all registered connectors. * @return allConnectors An array of all registered connectors */ function connectors() external view returns (IERC20[] memory allConnectors) { unchecked { allConnectors = new IERC20[](_connectors.length()); for (uint256 i = 0; i < allConnectors.length; i++) { allConnectors[i] = IERC20(address(uint160(uint256(_connectors._inner._values[i])))); } } } /** * @notice Sets the MultiWrapper contract address. * @param _multiWrapper The address of the MultiWrapper contract */ function setMultiWrapper(MultiWrapper _multiWrapper) external onlyOwner { multiWrapper = _multiWrapper; emit MultiWrapperUpdated(_multiWrapper); } /** * @notice Adds a new oracle to the registry with the given oracle type. * @param oracle The address of the new oracle to add * @param oracleKind The type of the new oracle */ function addOracle(IOracle oracle, OracleType oracleKind) external onlyOwner { if (oracleKind == OracleType.WETH) { if(!_wethOracles.add(address(oracle))) revert OracleAlreadyAdded(); } else if (oracleKind == OracleType.ETH) { if(!_ethOracles.add(address(oracle))) revert OracleAlreadyAdded(); } else if (oracleKind == OracleType.WETH_ETH) { if(!_wethOracles.add(address(oracle))) revert OracleAlreadyAdded(); if(!_ethOracles.add(address(oracle))) revert OracleAlreadyAdded(); } else { revert InvalidOracleTokenKind(); } emit OracleAdded(oracle, oracleKind); } /** * @notice Removes an oracle from the registry with the given oracle type. * @param oracle The address of the oracle to remove * @param oracleKind The type of the oracle to remove */ function removeOracle(IOracle oracle, OracleType oracleKind) external onlyOwner { if (oracleKind == OracleType.WETH) { if(!_wethOracles.remove(address(oracle))) revert UnknownOracle(); } else if (oracleKind == OracleType.ETH) { if(!_ethOracles.remove(address(oracle))) revert UnknownOracle(); } else if (oracleKind == OracleType.WETH_ETH) { if(!_wethOracles.remove(address(oracle))) revert UnknownOracle(); if(!_ethOracles.remove(address(oracle))) revert UnknownOracle(); } else { revert InvalidOracleTokenKind(); } emit OracleRemoved(oracle, oracleKind); } /** * @notice Adds a new connector to the registry. * @param connector The address of the new connector to add */ function addConnector(IERC20 connector) external onlyOwner { if(!_connectors.add(address(connector))) revert ConnectorAlreadyAdded(); emit ConnectorAdded(connector); } /** * @notice Removes a connector from the registry. * @param connector The address of the connector to remove */ function removeConnector(IERC20 connector) external onlyOwner { if(!_connectors.remove(address(connector))) revert UnknownConnector(); emit ConnectorRemoved(connector); } /** * WARNING! * Usage of the dex oracle on chain is highly discouraged! * getRate function can be easily manipulated inside transaction! * @notice Returns the weighted rate between two tokens using default connectors, with the option to filter out rates below a certain threshold. * @param srcToken The source token * @param dstToken The destination token * @param useWrappers Boolean flag to use or not use token wrappers * @return weightedRate weighted rate between the two tokens */ function getRate( IERC20 srcToken, IERC20 dstToken, bool useWrappers ) external view returns (uint256 weightedRate) { return getRateWithCustomConnectors(srcToken, dstToken, useWrappers, new IERC20[](0), 0); } /** * WARNING! * Usage of the dex oracle on chain is highly discouraged! * getRate function can be easily manipulated inside transaction! * @notice Returns the weighted rate between two tokens using default connectors, with the option to filter out rates below a certain threshold. * @param srcToken The source token * @param dstToken The destination token * @param useWrappers Boolean flag to use or not use token wrappers * @param thresholdFilter The threshold percentage (from 0 to 100) used to filter out rates below the threshold * @return weightedRate weighted rate between the two tokens */ function getRateWithThreshold( IERC20 srcToken, IERC20 dstToken, bool useWrappers, uint256 thresholdFilter ) external view returns (uint256 weightedRate) { return getRateWithCustomConnectors(srcToken, dstToken, useWrappers, new IERC20[](0), thresholdFilter); } /** * WARNING! * Usage of the dex oracle on chain is highly discouraged! * getRate function can be easily manipulated inside transaction! * @notice Returns the weighted rate between two tokens using custom connectors, with the option to filter out rates below a certain threshold. * @param srcToken The source token * @param dstToken The destination token * @param useWrappers Boolean flag to use or not use token wrappers * @param customConnectors An array of custom connectors to use * @param thresholdFilter The threshold percentage (from 0 to 100) used to filter out rates below the threshold * @return weightedRate The weighted rate between the two tokens */ function getRateWithCustomConnectors( IERC20 srcToken, IERC20 dstToken, bool useWrappers, IERC20[] memory customConnectors, uint256 thresholdFilter ) public view returns (uint256 weightedRate) { if(srcToken == dstToken) revert SameTokens(); if(thresholdFilter >= 100) revert TooBigThreshold(); (IOracle[] memory allOracles, ) = oracles(); (IERC20[] memory wrappedSrcTokens, uint256[] memory srcRates) = _getWrappedTokens(srcToken, useWrappers); (IERC20[] memory wrappedDstTokens, uint256[] memory dstRates) = _getWrappedTokens(dstToken, useWrappers); IERC20[][2] memory allConnectors = _getAllConnectors(customConnectors); uint256 maxArrLength = wrappedSrcTokens.length * wrappedDstTokens.length * (allConnectors[0].length + allConnectors[1].length) * allOracles.length; OraclePrice[] memory oraclePrices; // Memory allocation in assembly to avoid array zeroing assembly ("memory-safe") { // solhint-disable-line no-inline-assembly oraclePrices := mload(0x40) mstore(0x40, add(oraclePrices, add(0x20, mul(maxArrLength, 0x40)))) mstore(oraclePrices, maxArrLength) } uint256 oracleIndex; uint256 maxOracleWeight; unchecked { for (uint256 k1 = 0; k1 < wrappedSrcTokens.length; k1++) { for (uint256 k2 = 0; k2 < wrappedDstTokens.length; k2++) { if (wrappedSrcTokens[k1] == wrappedDstTokens[k2]) { return srcRates[k1].mul(dstRates[k2]).div(1e18); } for (uint256 k3 = 0; k3 < 2; k3++) { for (uint256 j = 0; j < allConnectors[k3].length; j++) { IERC20 connector = allConnectors[k3][j]; if (connector == wrappedSrcTokens[k1] || connector == wrappedDstTokens[k2]) { continue; } for (uint256 i = 0; i < allOracles.length; i++) { (OraclePrice memory oraclePrice) = _getRateImpl(allOracles[i], wrappedSrcTokens[k1], srcRates[k1], wrappedDstTokens[k2], dstRates[k2], connector); if (oraclePrice.weight > 0) { oraclePrices[oracleIndex] = oraclePrice; oracleIndex++; if (oraclePrice.weight > maxOracleWeight) { maxOracleWeight = oraclePrice.weight; } } } } } } } assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(oraclePrices, oracleIndex) } uint256 totalWeight; for (uint256 i = 0; i < oraclePrices.length; i++) { if (oraclePrices[i].weight * 100 < maxOracleWeight * thresholdFilter) { continue; } (bool ok, uint256 weightedRateI) = oraclePrices[i].rate.tryMul(oraclePrices[i].weight); if (ok) { (ok, weightedRate) = _tryAdd(weightedRate, weightedRateI); if (ok) totalWeight += oraclePrices[i].weight; } } if (totalWeight > 0) { weightedRate = weightedRate / totalWeight; } } } /** * WARNING! * Usage of the dex oracle on chain is highly discouraged! * getRate function can be easily manipulated inside transaction! * @notice The same as `getRate` but checks against `ETH` and `WETH` only */ function getRateToEth(IERC20 srcToken, bool useSrcWrappers) external view returns (uint256 weightedRate) { return getRateToEthWithCustomConnectors(srcToken, useSrcWrappers, new IERC20[](0), 0); } /** * WARNING! * Usage of the dex oracle on chain is highly discouraged! * getRate function can be easily manipulated inside transaction! * @notice The same as `getRate` but checks against `ETH` and `WETH` only */ function getRateToEthWithThreshold(IERC20 srcToken, bool useSrcWrappers, uint256 thresholdFilter) external view returns (uint256 weightedRate) { return getRateToEthWithCustomConnectors(srcToken, useSrcWrappers, new IERC20[](0), thresholdFilter); } /** * WARNING! * Usage of the dex oracle on chain is highly discouraged! * getRate function can be easily manipulated inside transaction! * @notice The same as `getRateWithCustomConnectors` but checks against `ETH` and `WETH` only */ function getRateToEthWithCustomConnectors(IERC20 srcToken, bool useSrcWrappers, IERC20[] memory customConnectors, uint256 thresholdFilter) public view returns (uint256 weightedRate) { if(thresholdFilter >= 100) revert TooBigThreshold(); (IERC20[] memory wrappedSrcTokens, uint256[] memory srcRates) = _getWrappedTokens(srcToken, useSrcWrappers); IERC20[2] memory wrappedDstTokens = [_BASE, _wBase]; bytes32[][2] memory wrappedOracles = [_ethOracles._inner._values, _wethOracles._inner._values]; IERC20[][2] memory allConnectors = _getAllConnectors(customConnectors); uint256 maxArrLength = wrappedSrcTokens.length * wrappedDstTokens.length * (allConnectors[0].length + allConnectors[1].length) * (wrappedOracles[0].length + wrappedOracles[1].length); OraclePrice[] memory oraclePrices; // Memory allocation in assembly to avoid array zeroing assembly ("memory-safe") { // solhint-disable-line no-inline-assembly oraclePrices := mload(0x40) mstore(0x40, add(oraclePrices, mul(maxArrLength, 0x40))) mstore(oraclePrices, maxArrLength) } uint256 oracleIndex; uint256 maxOracleWeight; unchecked { for (uint256 k1 = 0; k1 < wrappedSrcTokens.length; k1++) { for (uint256 k2 = 0; k2 < wrappedDstTokens.length; k2++) { if (wrappedSrcTokens[k1] == wrappedDstTokens[k2]) { return srcRates[k1]; } for (uint256 k3 = 0; k3 < 2; k3++) { for (uint256 j = 0; j < allConnectors[k3].length; j++) { IERC20 connector = allConnectors[k3][j]; if (connector == wrappedSrcTokens[k1] || connector == wrappedDstTokens[k2]) { continue; } for (uint256 i = 0; i < wrappedOracles[k2].length; i++) { (OraclePrice memory oraclePrice) = _getRateImpl(IOracle(address(uint160(uint256(wrappedOracles[k2][i])))), wrappedSrcTokens[k1], srcRates[k1], wrappedDstTokens[k2], 1e18, connector); if (oraclePrice.weight > 0) { oraclePrices[oracleIndex] = oraclePrice; oracleIndex++; if (oraclePrice.weight > maxOracleWeight) { maxOracleWeight = oraclePrice.weight; } } } } } } } assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(oraclePrices, oracleIndex) } uint256 totalWeight; for (uint256 i = 0; i < oracleIndex; i++) { if (oraclePrices[i].weight < maxOracleWeight * thresholdFilter / 100) { continue; } (bool ok, uint256 weightedRateI) = oraclePrices[i].rate.tryMul(oraclePrices[i].weight); if (ok) { (ok, weightedRate) = _tryAdd(weightedRate, weightedRateI); if (ok) totalWeight += oraclePrices[i].weight; } } if (totalWeight > 0) { weightedRate = weightedRate / totalWeight; } } } function _getWrappedTokens(IERC20 token, bool useWrappers) internal view returns (IERC20[] memory wrappedTokens, uint256[] memory rates) { if (useWrappers) { return multiWrapper.getWrappedTokens(token); } wrappedTokens = new IERC20[](1); wrappedTokens[0] = token; rates = new uint256[](1); rates[0] = uint256(1e18); } function _getAllConnectors(IERC20[] memory customConnectors) internal view returns (IERC20[][2] memory allConnectors) { IERC20[] memory connectorsZero; bytes32[] memory rawConnectors = _connectors._inner._values; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly connectorsZero := rawConnectors } allConnectors[0] = connectorsZero; allConnectors[1] = customConnectors; } function _getRateImpl(IOracle oracle, IERC20 srcToken, uint256 srcTokenRate, IERC20 dstToken, uint256 dstTokenRate, IERC20 connector) private view returns (OraclePrice memory oraclePrice) { try oracle.getRate(srcToken, dstToken, connector) returns (uint256 rate, uint256 weight) { uint256 result = _scaledMul([srcTokenRate, rate, dstTokenRate], 1e18); oraclePrice = OraclePrice(result, result == 0 ? 0 : weight); } catch {} // solhint-disable-line no-empty-blocks } function _tryAdd(uint256 value, uint256 addition) private pure returns (bool, uint256) { unchecked { uint256 result = value + addition; if (result < value) return (false, value); return (true, result); } } function _scaledMul(uint256[3] memory m, uint256 scale) private pure returns (uint256) { if (m[0] == 0 || m[1] == 0 || m[2] == 0) return 0; if (m[0] > m[1]) (m[0], m[1]) = (m[1], m[0]); if (m[0] > m[2]) (m[0], m[2]) = (m[2], m[0]); if (m[1] > m[2]) (m[1], m[2]) = (m[2], m[1]); bool scaleApplied; unchecked { uint256 r = m[0] * m[1]; if (r / m[0] != m[1]) { if (!_validatateMulDiv(m[0], m[1], scale)) return 0; r = m[0].mulDiv(m[1], scale); scaleApplied = true; } uint256 r2 = r * m[2]; if (r2 / r != m[2]) { if (!_validatateMulDiv(r, m[2], scaleApplied ? scale : scale * scale)) return 0; r2 = r.mulDiv(m[2], scaleApplied ? scale : scale * scale); } else { r2 /= scaleApplied ? scale : scale * scale; } return r2; } } /// @dev mulDiv validation is required as we do not want our methods to revert function _validatateMulDiv(uint256 x, uint256 y, uint256 denominator) private pure returns (bool) { uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Make sure the result is less than 2^256 return denominator > prod1; } }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract MultiWrapper","name":"_multiWrapper","type":"address"},{"internalType":"contract IOracle[]","name":"existingOracles","type":"address[]"},{"internalType":"enum OffchainOracle.OracleType[]","name":"oracleTypes","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"existingConnectors","type":"address[]"},{"internalType":"contract IERC20","name":"wBase","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArraysLengthMismatch","type":"error"},{"inputs":[],"name":"ConnectorAlreadyAdded","type":"error"},{"inputs":[],"name":"InvalidOracleTokenKind","type":"error"},{"inputs":[],"name":"OracleAlreadyAdded","type":"error"},{"inputs":[],"name":"SameTokens","type":"error"},{"inputs":[],"name":"TooBigThreshold","type":"error"},{"inputs":[],"name":"UnknownConnector","type":"error"},{"inputs":[],"name":"UnknownOracle","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"connector","type":"address"}],"name":"ConnectorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"connector","type":"address"}],"name":"ConnectorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract MultiWrapper","name":"multiWrapper","type":"address"}],"name":"MultiWrapperUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IOracle","name":"oracle","type":"address"},{"indexed":false,"internalType":"enum OffchainOracle.OracleType","name":"oracleType","type":"uint8"}],"name":"OracleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IOracle","name":"oracle","type":"address"},{"indexed":false,"internalType":"enum OffchainOracle.OracleType","name":"oracleType","type":"uint8"}],"name":"OracleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"connector","type":"address"}],"name":"addConnector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"oracle","type":"address"},{"internalType":"enum OffchainOracle.OracleType","name":"oracleKind","type":"uint8"}],"name":"addOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"connectors","outputs":[{"internalType":"contract IERC20[]","name":"allConnectors","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"bool","name":"useWrappers","type":"bool"}],"name":"getRate","outputs":[{"internalType":"uint256","name":"weightedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"bool","name":"useSrcWrappers","type":"bool"}],"name":"getRateToEth","outputs":[{"internalType":"uint256","name":"weightedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"bool","name":"useSrcWrappers","type":"bool"},{"internalType":"contract IERC20[]","name":"customConnectors","type":"address[]"},{"internalType":"uint256","name":"thresholdFilter","type":"uint256"}],"name":"getRateToEthWithCustomConnectors","outputs":[{"internalType":"uint256","name":"weightedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"bool","name":"useSrcWrappers","type":"bool"},{"internalType":"uint256","name":"thresholdFilter","type":"uint256"}],"name":"getRateToEthWithThreshold","outputs":[{"internalType":"uint256","name":"weightedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"bool","name":"useWrappers","type":"bool"},{"internalType":"contract IERC20[]","name":"customConnectors","type":"address[]"},{"internalType":"uint256","name":"thresholdFilter","type":"uint256"}],"name":"getRateWithCustomConnectors","outputs":[{"internalType":"uint256","name":"weightedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"bool","name":"useWrappers","type":"bool"},{"internalType":"uint256","name":"thresholdFilter","type":"uint256"}],"name":"getRateWithThreshold","outputs":[{"internalType":"uint256","name":"weightedRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiWrapper","outputs":[{"internalType":"contract MultiWrapper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracles","outputs":[{"internalType":"contract IOracle[]","name":"allOracles","type":"address[]"},{"internalType":"enum OffchainOracle.OracleType[]","name":"oracleTypes","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"connector","type":"address"}],"name":"removeConnector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"oracle","type":"address"},{"internalType":"enum OffchainOracle.OracleType","name":"oracleKind","type":"uint8"}],"name":"removeOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract MultiWrapper","name":"_multiWrapper","type":"address"}],"name":"setMultiWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
604060a0815234620004e5576200389e90813803806200001f8162000539565b93843982019160c081840312620004e55780516001600160a01b038082169390929091849003620004e55760208181015190936001600160401b03929091838111620004e55781019680601f89011215620004e5578751976200008c620000868a62000575565b62000539565b9887808b838152019160051b83010191838311620004e5578801905b8282106200051f5750505084820151848111620004e55782019381601f86011215620004e557845194620000e0620000868762000575565b95888088838152019160051b83010191848311620004e5578901905b82821062000505575050506060830151908111620004e55782019080601f83011215620004e557815162000134620000868262000575565b92888085848152019260051b820101928311620004e55788809101915b838310620004ea575050505060a06200016d608084016200058d565b92015183811697888203620004e5576200018733620005db565b8951865103620004d457600780546001600160a01b0319168217905586519081527f1030152fe2062b574a830e6b9f13c65995990df31e4dc708d142533bb3ad0f52908890a160005b89518110156200036357620001f0620001ea8288620005a2565b620005cd565b90600391828110156200028857868c839215600014620002af5762000222926200021a91620005a2565b511662000622565b156200029e575b8562000236828d620005a2565b511662000248620001ea838a620005a2565b928951918252831015620002885788816001948c7f5874b2072ff37562df54063dd700c59d45f311bdf6f9cabb5a15f0ffb2e9f622940152a101620001d0565b634e487b7160e01b600052602160045260246000fd5b8751633295224f60e11b8152600490fd5b5050620001ea620002c19189620005a2565b828110156200028857868c60018493146000146200030757620002f192620002e991620005a2565b5116620006a9565b62000229578751633295224f60e11b8152600490fd5b5050620001ea620003199189620005a2565b82811015620002885760020362000352576200033b866200021a838e620005a2565b156200029e57620002f186620002e9838e620005a2565b87516398420d9360e01b8152600490fd5b5086939294508760005b8351811015620003e8576200039085620003888387620005a2565b511662000721565b15620003d757807fff88af5d962d47fd25d87755e8267a029fad5a91740c67d0dade2bdbe5268a1d8787620003c860019589620005a2565b51168b51908152a1016200036d565b8751630a606b6760e41b8152600490fd5b509291509360805233820362000418575b8451613109908162000795823960805181818161217501526125250152f35b339060005416036200049257156200044057506200043690620005db565b81808080620003f9565b60849083519062461bcd60e51b82526004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b60648285519062461bcd60e51b825280600483015260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b86516307e11acb60e51b8152600490fd5b600080fd5b8190620004f7846200058d565b815201910190889062000151565b81516003811015620004e5578152908901908901620000fc565b81518681168103620004e5578152908801908801620000a8565b6040519190601f01601f191682016001600160401b038111838210176200055f57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116200055f5760051b60200190565b51906001600160a01b0382168203620004e557565b8051821015620005b75760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b516003811015620002885790565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3565b6000908082526002602052604082205415600014620006a55760019182546801000000000000000081101562000691578381018085558110156200067d57908260409285835260208320015583549281526002602052205590565b634e487b7160e01b82526032600452602482fd5b634e487b7160e01b82526041600452602482fd5b5090565b6000818152600460205260408120546200071c5760035468010000000000000000811015620006915760018101806003558110156200067d577fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0182905560035491815260046020526040902055600190565b905090565b6000818152600660205260408120546200071c5760055468010000000000000000811015620006915760018101806005558110156200067d577f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018290556005549181526006602052604090205560019056fe604060a0815260048036101561001457600080fd5b600091823560e01c80631a6c6a9814610c555780632857373a14610b7d57806365050a6814610a575780636744d6c7146109ef5780636f9293b914610970578063715018a6146108d457806378159aae146108755780637de4fd101461081b578063802431fb146107b85780638da5cb5b146107675780639d4d7b1c1461060d578063aa16d4c014610553578063ade8b048146104d4578063b77910dc14610481578063d0626518146103d1578063f0b92e40146102195763f2fde38b146100db57600080fd5b346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102155781359173ffffffffffffffffffffffffffffffffffffffff9182841680940361021157610135610f65565b831561018e5750508254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8480fd5b8280fd5b509190346103cd5761022a36610f0b565b91610233610f65565b60038310156103a157826102c45761026073ffffffffffffffffffffffffffffffffffffffff83166115f7565b1561029d57506102977f7a7f56716fe703fb190529c336e57df71ab88188ba47e8d786bac684b61ab9a693945b5192839283611318565b0390a180f35b84517f9444a6da000000000000000000000000000000000000000000000000000000008152fd5b6001830361031c576102eb73ffffffffffffffffffffffffffffffffffffffff83166116be565b1561029d57506102977f7a7f56716fe703fb190529c336e57df71ab88188ba47e8d786bac684b61ab9a6939461028d565b6002830361037a5773ffffffffffffffffffffffffffffffffffffffff8216610344816115f7565b15610352576102eb906116be565b5084517f9444a6da000000000000000000000000000000000000000000000000000000008152fd5b84517f98420d93000000000000000000000000000000000000000000000000000000008152fd5b8360216024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5080fd5b5090346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021557359073ffffffffffffffffffffffffffffffffffffffff8216809203610215577f1030152fe2062b574a830e6b9f13c65995990df31e4dc708d142533bb3ad0f529160209161044f610f65565b817fffffffffffffffffffffffff0000000000000000000000000000000000000000600754161760075551908152a180f35b8382346103cd57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd5760209073ffffffffffffffffffffffffffffffffffffffff600754169051908152f35b5082346105505760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105505761050d610d0f565b92610516610da5565b916044359067ffffffffffffffff821161055057509161053f6020959261054994369101610e90565b90606435926124e5565b9051908152f35b80fd5b50346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102155773ffffffffffffffffffffffffffffffffffffffff6105a0610d0f565b6105a8610f65565b16916105b383611452565b156105e657507fff88af5d962d47fd25d87755e8267a029fad5a91740c67d0dade2bdbe5268a1d9160209151908152a180f35b90517fa606b670000000000000000000000000000000000000000000000000000000008152fd5b509190346103cd5761061e36610f0b565b91610627610f65565b60038310156103a157826106b15761065473ffffffffffffffffffffffffffffffffffffffff8316611347565b1561068a57506102977f5874b2072ff37562df54063dd700c59d45f311bdf6f9cabb5a15f0ffb2e9f62293945192839283611318565b84517f652a449e000000000000000000000000000000000000000000000000000000008152fd5b60018303610709576106d873ffffffffffffffffffffffffffffffffffffffff8316611400565b1561068a57506102977f5874b2072ff37562df54063dd700c59d45f311bdf6f9cabb5a15f0ffb2e9f622939461028d565b6002830361037a5773ffffffffffffffffffffffffffffffffffffffff821661073181611347565b1561073f576106d890611400565b5084517f652a449e000000000000000000000000000000000000000000000000000000008152fd5b8382346103cd57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd5773ffffffffffffffffffffffffffffffffffffffff60209254169051908152f35b8382346103cd5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd576105496020926107f7610d0f565b6107ff610d37565b610807610d96565b9185519361081485610e1b565b84526118a9565b8382346103cd57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd57610549602092610859610d0f565b610861610da5565b9084519261086e84610e1b565b835261213d565b8382346103cd5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd576105496020926108b4610d0f565b906108bd610da5565b8451916108c983610e1b565b8252604435926124e5565b833461055057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105505761090b610f65565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5090346102155760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610215576109a9610d0f565b926109b2610d37565b916109bb610d96565b916064359067ffffffffffffffff82116105505750916109e5610549949260209794369101610e90565b9160843593611c79565b8382346103cd5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd57610549602092610a2e610d0f565b90610a37610d37565b610a3f610d96565b90855192610a4c84610e1b565b835260643593611c79565b50823461055057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610550576005805491610a9583610fe4565b92815b8451811015610b265781811015610afa5760019084845273ffffffffffffffffffffffffffffffffffffffff817f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0015416610af38288611114565b5201610a98565b6024836032897f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8551602080825286518183018190528291828a0191818a0191885b828110610b5057505050500390f35b835173ffffffffffffffffffffffffffffffffffffffff1685528695509381019392810192600101610b41565b8382346103cd57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd5790610bb6611134565b9091835193849381850191855280518092526060850191602080920190845b818110610c2857505050848203818601528080855193848152019401925b828110610c0257505050500390f35b9193839550908082610c18600194839751610d5a565b0195019101918594939192610bf3565b825173ffffffffffffffffffffffffffffffffffffffff1685528897509383019391830191600101610bd5565b50346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102155773ffffffffffffffffffffffffffffffffffffffff610ca2610d0f565b610caa610f65565b1691610cb5836114a4565b15610ce857507f6825b26a0827e9c2ceca01d6289ce4a40e629dc074ec48ea4727d1afbff359f59160209151908152a180f35b90517f30bd159a000000000000000000000000000000000000000000000000000000008152fd5b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610d3257565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610d3257565b906003821015610d675752565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b604435908115158203610d3257565b602435908115158203610d3257565b6040810190811067ffffffffffffffff821117610dd057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff821117610dd057604052565b6020810190811067ffffffffffffffff821117610dd057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610dd057604052565b67ffffffffffffffff8111610dd05760051b60200190565b81601f82011215610d3257803591610ea783610e78565b92610eb56040519485610e37565b808452602092838086019260051b820101928311610d32578301905b828210610edf575050505090565b813573ffffffffffffffffffffffffffffffffffffffff81168103610d32578152908301908301610ed1565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610d325760043573ffffffffffffffffffffffffffffffffffffffff81168103610d3257906024356003811015610d325790565b73ffffffffffffffffffffffffffffffffffffffff600054163303610f8657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b90610fee82610e78565b610ffb6040519182610e37565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06110298294610e78565b0190602036910137565b60015481101561106a5760016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60035481101561106a5760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0190600090565b60055481101561106a5760056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00190600090565b80511561106a5760200190565b805182101561106a5760209160051b010190565b6003821015610d675752565b60018054916003918254611149818601610fe4565b936111548551610fe4565b958360005b8281106112ba5750509160005b8181106111ef57505061117882610fe4565b9561118283610fe4565b9560005b84811061119557505050505050565b73ffffffffffffffffffffffffffffffffffffffff6111b48284611114565b51166111c0828b611114565b526111cb8184611114565b519084821015610d67576111e987926111e4838c611114565b611128565b01611186565b849084918460005273ffffffffffffffffffffffffffffffffffffffff9283837fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0154169388806000905b61127e575b50505085821015610d675787938a858414611275575b916111e4916112688261126f9695611114565b528c611114565b01611166565b97850197611255565b868d80518310156112b357611294838692611114565b5116146112a35781018161123a565b935050505060029038888161123f565b505061123f565b8160005273ffffffffffffffffffffffffffffffffffffffff817fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6015416611302828a611114565b52600061130f828b611114565b52018490611159565b91602061134592949373ffffffffffffffffffffffffffffffffffffffff60408201961681520190610d5a565b565b6000818152600260205260408120546113fb57600154680100000000000000008110156113ce5790826113ba61138584600160409601600155611033565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b905560015492815260026020522055600190565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905090565b6000818152600460205260408120546113fb57600354680100000000000000008110156113ce57908261143e61138584600160409601600355611099565b905560035492815260046020522055600190565b6000818152600660205260408120546113fb57600554680100000000000000008110156113ce579082611490611385846001604096016005556110d0565b905560055492815260066020522055600190565b60008181526006602052604081205490919080156115f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908181018181116115c5576005549083820191821161159857808203611564575b505050600554801561153757810190611516826110d0565b909182549160031b1b19169055600555815260066020526040812055600190565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b611582611573611385936110d0565b90549060031b1c9283926110d0565b90558452600660205260408420553880806114fe565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505090565b60008181526002602052604081205490919080156115f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908181018181116115c557600154908382019182116115985780820361168a575b50505060015480156115375781019061166982611033565b909182549160031b1b19169055600155815260026020526040812055600190565b6116a861169961138593611033565b90549060031b1c928392611033565b9055845260026020526040842055388080611651565b60009080825260049081602052604083205480151560001461180a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908181018181116117de57600354908382019182116117b25780820361177f575b50505060035480156117535781019061173482611099565b909182549160031b1b1916905560035582526020526040812055600190565b6024856031867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b61179d61178e61138593611099565b90549060031b1c928392611099565b9055855283602052604085205538808061171c565b6024876011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b6024866011877f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50505090565b8181029291811591840414171561182357565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90600281101561106a5760051b0190565b9190820180921161182357565b811561187a570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b90919260009273ffffffffffffffffffffffffffffffffffffffff811673ffffffffffffffffffffffffffffffffffffffff841614611c4f5761190c906119046118fc876118f5611134565b509661286b565b97909261286b565b929093612a69565b936119406119386119208451875190611810565b61193288515160208a01515190611863565b90611810565b825190611810565b916040519260208160061b85010160405283526000936000956000985b83518a1015611baa5760005b8251811015611b9f5773ffffffffffffffffffffffffffffffffffffffff6119918c87611114565b511673ffffffffffffffffffffffffffffffffffffffff6119b28386611114565b511614611b695760005b600281106119cd5750600101611969565b8a9c9394959691926119e18260009d611852565b51518c1015611b58579c8c9d73ffffffffffffffffffffffffffffffffffffffff611a298e9f9b9c9d9e611a208391611a1a8888611852565b51611114565b51169b8b611114565b51168a148015611b2f575b611b1a5760009e9d9c9e5b8451811015611b02578e9f809e9f8c8c8c8c8c611aa78d73ffffffffffffffffffffffffffffffffffffffff611a9f8f611a988b848f611aae9e82611a88611a90938b98611114565b51169d611114565b511697611114565b5196611114565b511694611114565b5193612c27565b906020820151611ac7575b50506001019e9d9c9e611a3f565b909d60018f918f8181602095611ae083611ae695611114565b52611114565b50019e0151908111611af9575b8e611ab9565b9d506001611af3565b50909d9a9998506119e1828f9d6001905b019d611852565b909d9c8e9c9b9a99508260016119e192611b13565b5073ffffffffffffffffffffffffffffffffffffffff611b4f8689611114565b51168a14611a34565b9291969594939c9a506001016119bc565b965050509550505050611b949150611b8d611b9b94670de0b6b3a764000096611114565b5192611114565b5190611810565b0490565b50986001019861195d565b9a9950505050509350915050815260009060005b8151811015611c3857611bd18183611114565b50611bf6611bdf8284611114565b51516020611bed8486611114565b51015190612030565b90611c05575b50600101611bbe565b611c0f9195612d4e565b9490611c1c575b38611bfc565b916001906020611c2c8585611114565b51015101929050611c16565b505080611c425750565b611c4c9192611870565b90565b60046040517f3445e17c000000000000000000000000000000000000000000000000000000008152fd5b909293919360009173ffffffffffffffffffffffffffffffffffffffff851673ffffffffffffffffffffffffffffffffffffffff821614611c4f57606484101561200657611cea94611ce2611cda88611cd3979697611134565b509461286b565b98909261286b565b969093612a69565b95611d18611d10611cfe8451875190611810565b6119328a515160208c01515190611863565b845190611810565b936040519460208160061b870101604052855260009560009760006080525b84516080511015611f5d5760005b8351811015611f4e5773ffffffffffffffffffffffffffffffffffffffff611d6f60805188611114565b511673ffffffffffffffffffffffffffffffffffffffff611d908387611114565b511614611f255760005b60028110611dab5750600101611d45565b909b929a60009792979b5b611dc08383611852565b51518d1015611f14578d73ffffffffffffffffffffffffffffffffffffffff611ded8f611a1a8787611852565b51169973ffffffffffffffffffffffffffffffffffffffff611e116080518c611114565b51168b148015611eeb575b611edd5760005b8651811015611ec9578e611e7f8d8d8d8d8d611aa78a8f611a9f82611a9873ffffffffffffffffffffffffffffffffffffffff611e738f611e678397918492611114565b51169b60805190611114565b51169660805190611114565b906020820151611e94575b5050600101611e23565b909e8f8f91611ead8184600194611ae083602098611114565b50019f0151908111611ec0575b8f611e8a565b9e506001611eba565b509d90506001919299505b019b9790611db6565b9d9050600191929950611ed4565b5073ffffffffffffffffffffffffffffffffffffffff611f0b838a611114565b51168b14611e1c565b939c916001919c5097929701611d9a565b965050505094505050611b9b9350611b949150611b8d670de0b6b3a76400009560805190611114565b50608080516001019052611d37565b9a99509750505050509190825260009260005b8351811015611ffa5760646020611f878387611114565b5101510282840211611ff257611fae611fa08286611114565b51516020611bed8488611114565b90611fbf575b506001905b01611f70565b611fc99197612d4e565b9690611fd6575b38611fb4565b936001906020611fe68787611114565b51015101949050611fd0565b600190611fb9565b5050505080611c425750565b60046040517f215a716b000000000000000000000000000000000000000000000000000000008152fd5b91908215612058576120458184029384611870565b036120505760019190565b600091508190565b5060019150600090565b60405190600354808352826020918282019060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b936000905b8282106120b55750505061134592500383610e37565b85548452600195860195889550938101939091019061209f565b6040519081600180549081835260209081840192816000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6926000905b82821061212557505050505090611345910383610e37565b8454865288965094850194938301939083019061210d565b909161214d60009360009361286b565b906040519061215b82610db4565b84825273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166020830152604051946121a786610db4565b6121af612062565b86526121c96121bc6120cf565b9560208801968752612a69565b9482518060011b90808204600214901517156124b857906119326121fc612209936119328a515160208c01515190611863565b9189515190515190611863565b91604051928060061b8401604052835281938295835b835181101561243a57845b6002811061223b575060010161221f565b73ffffffffffffffffffffffffffffffffffffffff61225a8387611114565b511673ffffffffffffffffffffffffffffffffffffffff61227b8387611852565b51161461242157855b60028110612295575060010161222a565b9093959b97998c9b92939597999b9c5b8d6122b08484611852565b5151111561240a5773ffffffffffffffffffffffffffffffffffffffff6122db8f611a1a8686611852565b51169973ffffffffffffffffffffffffffffffffffffffff6122fd878c611114565b51168b1480156123e1575b6123d657815b6123188887611852565b51518110156123c6578e61237c8d8d8d8d73ffffffffffffffffffffffffffffffffffffffff6123748f8f8f908461236582828f61235d90611a1a8961236d99611852565b51169a611114565b511695611114565b5194611852565b511692612aff565b906020820151612391575b505060010161230e565b909e8f8f916123aa8184600194611ae083602098611114565b50019f01519081116123bd575b8f612387565b9e5060016123b7565b509d6001919a505b019c986122a5565b9d6001919a506123ce565b5073ffffffffffffffffffffffffffffffffffffffff612401888b611852565b51168b14612308565b9694916001919b999d509b99979593929b01612284565b50985096505050505050506124369250611114565b5190565b50505050945091509150939293818152825b82811061245e5750505080611c425750565b6124688183611114565b50612476611bdf8284611114565b90612485575b5060010161244c565b61248f9196612d4e565b959061249c575b3861247c565b9260019060206124ac8685611114565b51015101939050612496565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b600092916064851015612006576124fb9161286b565b92906040519061250a82610db4565b6000825273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016602083015260405161255681610db4565b61255e612062565b815261257861256b6120cf565b9560208301968752612a69565b948251908160011b9180830460021490151715611823576119326125ab6125b8936119328a515160208c01515190611863565b9184515190515190611863565b91604051928060061b8401604052835260009360009560005b83518110156127cf5760005b600281106125ee57506001016125d1565b73ffffffffffffffffffffffffffffffffffffffff61260d8387611114565b511673ffffffffffffffffffffffffffffffffffffffff61262e8387611852565b5116146127ba5760005b6002811061264957506001016125dd565b9093959192979960009b9597999b9c5b8d6126648484611852565b515111156127a35773ffffffffffffffffffffffffffffffffffffffff61268f8f611a1a8686611852565b51169973ffffffffffffffffffffffffffffffffffffffff6126b1878c611114565b51168b14801561277a575b61276e5760005b6126cd8887611852565b515181101561275c578e6127128d8d8d8d73ffffffffffffffffffffffffffffffffffffffff6123748f8f8f908461236582828f61235d90611a1a8961236d99611852565b906020820151612727575b50506001016126c3565b909e8f8f916127408184600194611ae083602098611114565b50019f0151908111612753575b8f61271d565b9e50600161274d565b509d600191929a505b019c9890612659565b9d600191929a50612765565b5073ffffffffffffffffffffffffffffffffffffffff61279a888b611852565b51168b146126bc565b9c50999792919593906001909b9997959b01612638565b50989750505050505050506124369250611114565b50999897505050509190925082825260009360005b8481106127f857505050505080611c425750565b60206128048286611114565b510151606483850204116128635761281f611fa08286611114565b90612830575b506001905b016127e4565b61283a9198612d4e565b9790612847575b38612825565b9460019060206128578887611114565b51015101959050612841565b60019061282a565b91906128d8576040519161287e83610db4565b600183526020368185013773ffffffffffffffffffffffffffffffffffffffff6128a784611107565b91169052604051906128b882610db4565b6001825260203681840137670de0b6b3a76400006128d583611107565b52565b73ffffffffffffffffffffffffffffffffffffffff809281600754166040519485927fcb991d9400000000000000000000000000000000000000000000000000000000845216600483015281602460009384935afa938415612a5c5781928295612944575b5050509190565b91945091503d8085843e6129588184610e37565b820160408382031261021157825167ffffffffffffffff90818111612a385784019382601f86011215612a385784519461299186610e78565b9561299f6040519788610e37565b808752602095868089019260051b84010192868411612a58578701915b838310612a3c575050505083810151918211612a38570181601f82011215612a34578051906129ea82610e78565b966129f86040519889610e37565b828852848089019360051b83010193841161055057508301905b828210612a25575050505038808061293d565b81518152908301908301612a12565b8580fd5b8680fd5b82518281168103612a545781529187019187016129bc565b8b80fd5b8a80fd5b50604051903d90823e3d90fd5b906040918251612a7881610db4565b60005b848110612af15750809351908160055480845281602080950160056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db09260005b87828210612adb57505050612ad592500382610e37565b81520152565b8554845260019586019587955093019201612abe565b606082820152602001612a7b565b9294939091604080936064825194612b1686610db4565b60009586815286602082015299845198899485937f14999e7900000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff8094818094166004880152166024860152166044840152165afa938483918496612bf0575b50612b94575b5050505050565b83612bc29394959697505191612ba983610dff565b82526020820152670de0b6b3a764000084820152612d68565b9283612be85750905b5191612bd683610db4565b82526020820152903880808080612b8d565b905090612bcb565b85809297508193503d8311612c20575b612c0a8183610e37565b8101031261021557602081519101519438612b87565b503d612c00565b93959491909295604080946064825195612c4087610db4565b6000968781528760208201529a8451998a9485937f14999e7900000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff8094818094166004880152166024860152166044840152165afa948584918597612d13575b50612cbf575b505050505050565b84612ce49495969798505192612cd484610dff565b8352602083015284820152612d68565b9283612d0b5750905b5191612cf883610db4565b8252602082015290388080808080612cb7565b905090612ced565b86809298508193503d8311612d47575b612d2d8183610e37565b81010312612d4357602081519101519538612cb1565b8380fd5b503d612d23565b9190820191808310612d61575060019190565b6000925090565b80519081158015612f36575b8015612f2a575b612f23576020810191825190818111612f18575b505080516040820190815190818111612f0d575b50508251815190818111612f02575b5050600092825192612dc8825185029485611870565b9151809203612eac575b505080518202612de28382611870565b825114612e795750518215612e6457670de0b6b3a76400005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8284098284028082109103031015612e5c57611c4c9215612e4657670de0b6b3a764000091613032565b6ec097ce7bc90715b34b9f100000000091613032565b505050600090565b6ec097ce7bc90715b34b9f1000000000612dfb565b915050611c4c91600014612e9657670de0b6b3a764000090611870565b6ec097ce7bc90715b34b9f100000000090611870565b90919250517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff828209828202808210910303670de0b6b3a7640000111561180a57612ef8929350612f42565b6001913880612dd2565b825283523880612db2565b825282523880612da3565b835281523880612d8f565b5050600090565b50604081015115612d7b565b50602081015115612d74565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183098183029182808310920391808303921461302157670de0b6b3a76400009082821115612fc3577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152fd5b5050670de0b6b3a764000091500490565b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82840992828102928380861095039480860395146130c65784831115612fc3578291096001821901821680920460028082600302188083028203028083028203028083028203028083028203028083028203028092029003029360018380600003040190848311900302920304170290565b505090611c4c925061187056fea2646970667358221220b49a007f9d1b2bae9171d0885b3f108e533166f04abcd2005b05634a4206323864736f6c63430008130033000000000000000000000000a0446d8804611944f1b527ecd37d7dcbe442caba00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000420000000000000000000000000000000000000600000000000000000000000011799622f4d98a24514011e8527b969f7488ef470000000000000000000000000000000000000000000000000000000000000003000000000000000000000000750c1b699552caf908d67f5ccfd20a261305328c000000000000000000000000fdcb8fa524f84081988e6065fc8ef060f2cf0c2700000000000000000000000089314d57a8a4e636a00922ac289bc3a9a69c436100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000042000000000000000000000000000000000000060000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160700000000000000000000000094b008aa00579c1307b0ef2c499ad98a8ce58e58000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da100000000000000000000000068f180fcce6836688e9084f035309e29bf0a20950000000000000000000000004200000000000000000000000000000000000042
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0446d8804611944f1b527ecd37d7dcbe442caba00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000420000000000000000000000000000000000000600000000000000000000000011799622f4d98a24514011e8527b969f7488ef470000000000000000000000000000000000000000000000000000000000000003000000000000000000000000750c1b699552caf908d67f5ccfd20a261305328c000000000000000000000000fdcb8fa524f84081988e6065fc8ef060f2cf0c2700000000000000000000000089314d57a8a4e636a00922ac289bc3a9a69c436100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000042000000000000000000000000000000000000060000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160700000000000000000000000094b008aa00579c1307b0ef2c499ad98a8ce58e58000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da100000000000000000000000068f180fcce6836688e9084f035309e29bf0a20950000000000000000000000004200000000000000000000000000000000000042
-----Decoded View---------------
Arg [0] : _multiWrapper (address): 0xA0446D8804611944F1B527eCD37d7dcbE442caba
Arg [1] : existingOracles (address[]): 0x750c1b699552cAf908D67F5cCFd20A261305328c,0xFdCB8fA524f84081988e6065Fc8EF060f2CF0C27,0x89314d57A8A4E636A00922ac289BC3a9a69C4361
Arg [2] : oracleTypes (uint8[]): 0,0,1
Arg [3] : existingConnectors (address[]): 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF,0x4200000000000000000000000000000000000006,0x7F5c764cBc14f9669B88837ca1490cCa17c31607,0x94b008aA00579c1307B0EF2c499aD98a8ce58e58,0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1,0x68f180fcCe6836688e9084f035309E29Bf0A2095,0x4200000000000000000000000000000000000042
Arg [4] : wBase (address): 0x4200000000000000000000000000000000000006
Arg [5] : owner (address): 0x11799622F4D98A24514011E8527B969f7488eF47
-----Encoded View---------------
22 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0446d8804611944f1b527ecd37d7dcbe442caba
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [4] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [5] : 00000000000000000000000011799622f4d98a24514011e8527b969f7488ef47
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [7] : 000000000000000000000000750c1b699552caf908d67f5ccfd20a261305328c
Arg [8] : 000000000000000000000000fdcb8fa524f84081988e6065fc8ef060f2cf0c27
Arg [9] : 00000000000000000000000089314d57a8a4e636a00922ac289bc3a9a69c4361
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [15] : 000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
Arg [16] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [17] : 0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607
Arg [18] : 00000000000000000000000094b008aa00579c1307b0ef2c499ad98a8ce58e58
Arg [19] : 000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1
Arg [20] : 00000000000000000000000068f180fcce6836688e9084f035309e29bf0a2095
Arg [21] : 0000000000000000000000004200000000000000000000000000000000000042
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.