Contract
0x3Ce81621e674Db129033548CbB9FF31AEDCc1BF6
2
Contract Overview
Balance:
0 xDAI
xDAI Value:
$0.00
My Name Tag:
Not Available, login to update
Txn Hash | Method |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x101919dafa6e9eeced97174785a90ab64d69d454b98a49cad1a9e3f7a1c6f284 | 0x604060a0 | 27313353 | 63 days 21 hrs ago | 0x56e44874f624ebde6efcc783efd685f0fbdc6dcf | IN | Contract Creation | 0 xDAI | 0.003140596021 |
[ Download CSV Export ]
Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0x89314d57A8A4E636A00922ac289BC3a9a69C4361
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.7.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 anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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.6.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.8.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) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 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 10, 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 * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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.8.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. * * ``` * 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 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) { 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; } } /** * @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; } weightedRate += (oraclePrices[i].rate * oraclePrices[i].weight); 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; } weightedRate += (oraclePrices[i].rate * oraclePrices[i].weight); 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) { oraclePrice = OraclePrice(rate * srcTokenRate * dstTokenRate / 1e36, weight); } catch {} // solhint-disable-line no-empty-blocks } }
{ "optimizer": { "enabled": true, "runs": 1000000 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"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"}],"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
604060a08152346200043b576200338b803803806200001e8162000474565b92833981019060a0818303126200043b5780516001600160a01b039190828116908190036200043b576020828101516001600160401b0394919291908581116200043b5784019386601f860112156200043b57845194620000896200008387620004b0565b62000474565b95858088838152019160051b830101918983116200043b578601905b8282106200045a57505050878101518681116200043b5781019587601f880112156200043b57865196620000dd6200008389620004b0565b9786808a838152019160051b830101918a83116200043b578701905b828210620004405750505060608201519081116200043b5781019680601f890112156200043b578751620001316200008382620004b0565b9886808b848152019260051b8201019283116200043b5786809101915b8383106200042057505050506080620001689101620004c8565b600080546001600160a01b03198082163390811784558b51939693919286167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08880a38751895103620004115750817f1030152fe2062b574a830e6b9f13c65995990df31e4dc708d142533bb3ad0f5292879260075416176007558a51908152a1825b85518110156200036c576200020b620002058289620004dd565b62000508565b600390818110156200029d57620002c25762000235846200022d848a620004dd565b51166200052c565b15620002b1575b83620002498389620004dd565b5116906200025c62000205848b620004dd565b908b519283528110156200029d578a827f5874b2072ff37562df54063dd700c59d45f311bdf6f9cabb5a15f0ffb2e9f6229289600196950152a101620001eb565b634e487b7160e01b86526021600452602486fd5b8951633295224f60e11b8152600490fd5b620002d262000205838a620004dd565b818110156200029d576001036200031257620002fc84620002f4848a620004dd565b5116620005b3565b6200023c578951633295224f60e11b8152600490fd5b6200032262000205838a620004dd565b818110156200029d576002036200035b5762000344846200022d848a620004dd565b15620002b157620002fc84620002f4848a620004dd565b89516398420d9360e01b8152600490fd5b5083889288855b8151811015620003ee5762000396836200038e8385620004dd565b51166200062b565b15620003dd57807fff88af5d962d47fd25d87755e8267a029fad5a91740c67d0dade2bdbe5268a1d8585620003ce60019587620004dd565b51168951908152a10162000373565b8551630a606b6760e41b8152600490fd5b858560805251612cec90816200069f82396080518181816120df015261247f0152f35b6307e11acb60e51b8152600490fd5b81906200042d84620004c8565b81520191019086906200014e565b600080fd5b815160038110156200043b578152908701908701620000f9565b815185811681036200043b578152908601908601620000a5565b6040519190601f01601f191682016001600160401b038111838210176200049a57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116200049a5760051b60200190565b51906001600160a01b03821682036200043b57565b8051821015620004f25760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b516003811015620005165790565b634e487b7160e01b600052602160045260246000fd5b6000908082526002602052604082205415600014620005af576001918254680100000000000000008110156200059b578381018085558110156200058757908260409285835260208320015583549281526002602052205590565b634e487b7160e01b82526032600452602482fd5b634e487b7160e01b82526041600452602482fd5b5090565b6000818152600460205260408120546200062657600354680100000000000000008110156200059b57600181018060035581101562000587577fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0182905560035491815260046020526040902055600190565b905090565b6000818152600660205260408120546200062657600554680100000000000000008110156200059b57600181018060055581101562000587577f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018290556005549181526006602052604090205560019056fe604060a0815260048036101561001457600080fd5b600091823560e01c80631a6c6a9814610c555780632857373a14610b7d57806365050a6814610a575780636744d6c7146109ef5780636f9293b914610970578063715018a6146108d457806378159aae146108755780637de4fd101461081b578063802431fb146107b85780638da5cb5b146107675780639d4d7b1c1461060d578063aa16d4c014610553578063ade8b048146104d4578063b77910dc14610481578063d0626518146103d1578063f0b92e40146102195763f2fde38b146100db57600080fd5b346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102155781359173ffffffffffffffffffffffffffffffffffffffff9182841680940361021157610135610f49565b831561018e5750508254827fffffffffffffffffffffffff00000000000000000000000000000000000000008216178455167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b8480fd5b8280fd5b509190346103cd5761022a36610eef565b91610233610f49565b60038310156103a157826102c45761026073ffffffffffffffffffffffffffffffffffffffff83166115db565b1561029d57506102977f7a7f56716fe703fb190529c336e57df71ab88188ba47e8d786bac684b61ab9a693945b51928392836112fc565b0390a180f35b84517f9444a6da000000000000000000000000000000000000000000000000000000008152fd5b6001830361031c576102eb73ffffffffffffffffffffffffffffffffffffffff83166116a2565b1561029d57506102977f7a7f56716fe703fb190529c336e57df71ab88188ba47e8d786bac684b61ab9a6939461028d565b6002830361037a5773ffffffffffffffffffffffffffffffffffffffff8216610344816115db565b15610352576102eb906116a2565b5084517f9444a6da000000000000000000000000000000000000000000000000000000008152fd5b84517f98420d93000000000000000000000000000000000000000000000000000000008152fd5b8360216024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5080fd5b5090346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021557359073ffffffffffffffffffffffffffffffffffffffff8216809203610215577f1030152fe2062b574a830e6b9f13c65995990df31e4dc708d142533bb3ad0f529160209161044f610f49565b817fffffffffffffffffffffffff0000000000000000000000000000000000000000600754161760075551908152a180f35b8382346103cd57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd5760209073ffffffffffffffffffffffffffffffffffffffff600754169051908152f35b5082346105505760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105505761050d610d0f565b92610516610da5565b916044359067ffffffffffffffff821161055057509161053f6020959261054994369101610e74565b906064359261243f565b9051908152f35b80fd5b50346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102155773ffffffffffffffffffffffffffffffffffffffff6105a0610d0f565b6105a8610f49565b16916105b383611436565b156105e657507fff88af5d962d47fd25d87755e8267a029fad5a91740c67d0dade2bdbe5268a1d9160209151908152a180f35b90517fa606b670000000000000000000000000000000000000000000000000000000008152fd5b509190346103cd5761061e36610eef565b91610627610f49565b60038310156103a157826106b15761065473ffffffffffffffffffffffffffffffffffffffff831661132b565b1561068a57506102977f5874b2072ff37562df54063dd700c59d45f311bdf6f9cabb5a15f0ffb2e9f622939451928392836112fc565b84517f652a449e000000000000000000000000000000000000000000000000000000008152fd5b60018303610709576106d873ffffffffffffffffffffffffffffffffffffffff83166113e4565b1561068a57506102977f5874b2072ff37562df54063dd700c59d45f311bdf6f9cabb5a15f0ffb2e9f622939461028d565b6002830361037a5773ffffffffffffffffffffffffffffffffffffffff82166107318161132b565b1561073f576106d8906113e4565b5084517f652a449e000000000000000000000000000000000000000000000000000000008152fd5b8382346103cd57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd5773ffffffffffffffffffffffffffffffffffffffff60209254169051908152f35b8382346103cd5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd576105496020926107f7610d0f565b6107ff610d37565b610807610d96565b9185519361081485610dff565b845261188d565b8382346103cd57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd57610549602092610859610d0f565b610861610da5565b9084519261086e84610dff565b83526120a7565b8382346103cd5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd576105496020926108b4610d0f565b906108bd610da5565b8451916108c983610dff565b82526044359261243f565b833461055057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105505761090b610f49565b8073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5090346102155760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610215576109a9610d0f565b926109b2610d37565b916109bb610d96565b916064359067ffffffffffffffff82116105505750916109e5610549949260209794369101610e74565b9160843593611c34565b8382346103cd5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd57610549602092610a2e610d0f565b90610a37610d37565b610a3f610d96565b90855192610a4c84610dff565b835260643593611c34565b50823461055057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610550576005805491610a9583610fc8565b92815b8451811015610b265781811015610afa5760019084845273ffffffffffffffffffffffffffffffffffffffff817f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0015416610af382886110f8565b5201610a98565b6024836032897f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8551602080825286518183018190528291828a0191818a0191885b828110610b5057505050500390f35b835173ffffffffffffffffffffffffffffffffffffffff1685528695509381019392810192600101610b41565b8382346103cd57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103cd5790610bb6611118565b9091835193849381850191855280518092526060850191602080920190845b818110610c2857505050848203818601528080855193848152019401925b828110610c0257505050500390f35b9193839550908082610c18600194839751610d5a565b0195019101918594939192610bf3565b825173ffffffffffffffffffffffffffffffffffffffff1685528897509383019391830191600101610bd5565b50346102155760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102155773ffffffffffffffffffffffffffffffffffffffff610ca2610d0f565b610caa610f49565b1691610cb583611488565b15610ce857507f6825b26a0827e9c2ceca01d6289ce4a40e629dc074ec48ea4727d1afbff359f59160209151908152a180f35b90517f30bd159a000000000000000000000000000000000000000000000000000000008152fd5b6004359073ffffffffffffffffffffffffffffffffffffffff82168203610d3257565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff82168203610d3257565b906003821015610d675752565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b604435908115158203610d3257565b602435908115158203610d3257565b6040810190811067ffffffffffffffff821117610dd057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6020810190811067ffffffffffffffff821117610dd057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610dd057604052565b67ffffffffffffffff8111610dd05760051b60200190565b81601f82011215610d3257803591610e8b83610e5c565b92610e996040519485610e1b565b808452602092838086019260051b820101928311610d32578301905b828210610ec3575050505090565b813573ffffffffffffffffffffffffffffffffffffffff81168103610d32578152908301908301610eb5565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040910112610d325760043573ffffffffffffffffffffffffffffffffffffffff81168103610d3257906024356003811015610d325790565b73ffffffffffffffffffffffffffffffffffffffff600054163303610f6a57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b90610fd282610e5c565b610fdf6040519182610e1b565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061100d8294610e5c565b0190602036910137565b60015481101561104e5760016000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60190600090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60035481101561104e5760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0190600090565b60055481101561104e5760056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00190600090565b80511561104e5760200190565b805182101561104e5760209160051b010190565b6003821015610d675752565b6001805491600391825461112d818601610fc8565b936111388551610fc8565b958360005b82811061129e5750509160005b8181106111d357505061115c82610fc8565b9561116683610fc8565b9560005b84811061117957505050505050565b73ffffffffffffffffffffffffffffffffffffffff61119882846110f8565b51166111a4828b6110f8565b526111af81846110f8565b519084821015610d67576111cd87926111c8838c6110f8565b61110c565b0161116a565b849084918460005273ffffffffffffffffffffffffffffffffffffffff9283837fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0154169388806000905b611262575b50505085821015610d675787938a858414611259575b916111c89161124c8261125396956110f8565b528c6110f8565b0161114a565b97850197611239565b868d8051831015611297576112788386926110f8565b5116146112875781018161121e565b9350505050600290388881611223565b5050611223565b8160005273ffffffffffffffffffffffffffffffffffffffff817fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60154166112e6828a6110f8565b5260006112f3828b6110f8565b5201849061113d565b91602061132992949373ffffffffffffffffffffffffffffffffffffffff60408201961681520190610d5a565b565b6000818152600260205260408120546113df57600154680100000000000000008110156113b257908261139e61136984600160409601600155611017565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b905560015492815260026020522055600190565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905090565b6000818152600460205260408120546113df57600354680100000000000000008110156113b25790826114226113698460016040960160035561107d565b905560035492815260046020522055600190565b6000818152600660205260408120546113df57600554680100000000000000008110156113b2579082611474611369846001604096016005556110b4565b905560055492815260066020522055600190565b60008181526006602052604081205490919080156115d6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908181018181116115a9576005549083820191821161157c57808203611548575b505050600554801561151b578101906114fa826110b4565b909182549160031b1b19169055600555815260066020526040812055600190565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b611566611557611369936110b4565b90549060031b1c9283926110b4565b90558452600660205260408420553880806114e2565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505090565b60008181526002602052604081205490919080156115d6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908181018181116115a9576001549083820191821161157c5780820361166e575b505050600154801561151b5781019061164d82611017565b909182549160031b1b19169055600155815260026020526040812055600190565b61168c61167d61136993611017565b90549060031b1c928392611017565b9055845260026020526040842055388080611635565b6000908082526004908160205260408320548015156000146117ee577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908181018181116117c2576003549083820191821161179657808203611763575b5050506003548015611737578101906117188261107d565b909182549160031b1b1916905560035582526020526040812055600190565b6024856031867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b6117816117726113699361107d565b90549060031b1c92839261107d565b90558552836020526040852055388080611700565b6024876011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b6024866011877f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50505090565b8181029291811591840414171561180757565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b90600281101561104e5760051b0190565b9190820180921161180757565b811561185e570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b90919260009273ffffffffffffffffffffffffffffffffffffffff811673ffffffffffffffffffffffffffffffffffffffff841614611c0a576118f0906118e86118e0876118d9611118565b50966127ba565b9790926127ba565b9290936129b8565b9361192461191c61190484518751906117f4565b61191688515160208a01515190611847565b906117f4565b8251906117f4565b916040519260208160061b85010160405283526000936000956000985b83518a1015611b8e5760005b8251811015611b835773ffffffffffffffffffffffffffffffffffffffff6119758c876110f8565b511673ffffffffffffffffffffffffffffffffffffffff61199683866110f8565b511614611b4d5760005b600281106119b1575060010161194d565b8a9c9394959691926119c58260009d611836565b51518c1015611b3c579c8c9d73ffffffffffffffffffffffffffffffffffffffff611a0d8e9f9b9c9d9e611a0483916119fe8888611836565b516110f8565b51169b8b6110f8565b51168a148015611b13575b611afe5760009e9d9c9e5b8451811015611ae6578e9f809e9f8c8c8c8c8c611a8b8d73ffffffffffffffffffffffffffffffffffffffff611a838f611a7c8b848f611a929e82611a6c611a74938b986110f8565b51169d6110f8565b5116976110f8565b51966110f8565b5116946110f8565b5193612ba0565b906020820151611aab575b50506001019e9d9c9e611a23565b909d60018f918f8181602095611ac483611aca956110f8565b526110f8565b50019e0151908111611add575b8e611a9d565b9d506001611ad7565b50909d9a9998506119c5828f9d6001905b019d611836565b909d9c8e9c9b9a99508260016119c592611af7565b5073ffffffffffffffffffffffffffffffffffffffff611b3386896110f8565b51168a14611a18565b9291969594939c9a506001016119a0565b965050509550505050611b789150611b71611b7f94670de0b6b3a7640000966110f8565b51926110f8565b51906117f4565b0490565b509860010198611941565b98505050505095945091505083526000926000915b8151831015611bf157600190611bb984846110f8565b50611bc484846110f8565b51516020611bd286866110f8565b5101510201946020611be485856110f8565b5101510192019193611ba3565b9391505080611bfd5750565b611c079192611854565b90565b60046040517f3445e17c000000000000000000000000000000000000000000000000000000008152fd5b909293919360009173ffffffffffffffffffffffffffffffffffffffff851673ffffffffffffffffffffffffffffffffffffffff821614611c0a576064841015611fa257611ca594611c9d611c9588611c8e979697611118565b50946127ba565b9890926127ba565b9690936129b8565b95611cd3611ccb611cb984518751906117f4565b6119168a515160208c01515190611847565b8451906117f4565b936040519460208160061b870101604052855260009560009760006080525b84516080511015611f185760005b8351811015611f095773ffffffffffffffffffffffffffffffffffffffff611d2a608051886110f8565b511673ffffffffffffffffffffffffffffffffffffffff611d4b83876110f8565b511614611ee05760005b60028110611d665750600101611d00565b909b929a60009792979b5b611d7b8383611836565b51518d1015611ecf578d73ffffffffffffffffffffffffffffffffffffffff611da88f6119fe8787611836565b51169973ffffffffffffffffffffffffffffffffffffffff611dcc6080518c6110f8565b51168b148015611ea6575b611e985760005b8651811015611e84578e611e3a8d8d8d8d8d611a8b8a8f611a8382611a7c73ffffffffffffffffffffffffffffffffffffffff611e2e8f611e2283979184926110f8565b51169b608051906110f8565b511696608051906110f8565b906020820151611e4f575b5050600101611dde565b909e8f8f91611e688184600194611ac4836020986110f8565b50019f0151908111611e7b575b8f611e45565b9e506001611e75565b509d90506001919299505b019b9790611d71565b9d9050600191929950611e8f565b5073ffffffffffffffffffffffffffffffffffffffff611ec6838a6110f8565b51168b14611dd7565b939c916001919c5097929701611d55565b965050505094505050611b7f9350611b789150611b71670de0b6b3a764000095608051906110f8565b50608080516001019052611cf2565b985099985050505050919082526000946000935b8351851015611f945760646020611f4387876110f8565b5101510282840211611f8a57600190611f5c86866110f8565b51516020611f6a88886110f8565b5101510201966020611f7c87876110f8565b51015101945b019395611f2c565b9593600190611f82565b95935050505080611bfd5750565b60046040517f215a716b000000000000000000000000000000000000000000000000000000008152fd5b60405190600354808352826020918282019060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b936000905b82821061201f5750505061132992500383610e1b565b855484526001958601958895509381019390910190612009565b6040519081600180549081835260209081840192816000527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6926000905b82821061208f57505050505090611329910383610e1b565b84548652889650948501949383019390830190612077565b90916120b76000936000936127ba565b90604051906120c582610db4565b84825273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660208301526040519461211186610db4565b612119611fcc565b8652612133612126612039565b95602088019687526129b8565b9482518060011b90808204600214901517156124125790611916612166612173936119168a515160208c01515190611847565b9189515190515190611847565b91604051928060061b8401604052835281938295835b83518110156123a457845b600281106121a55750600101612189565b73ffffffffffffffffffffffffffffffffffffffff6121c483876110f8565b511673ffffffffffffffffffffffffffffffffffffffff6121e58387611836565b51161461238b57855b600281106121ff5750600101612194565b9093959b97998c9b92939597999b9c5b8d61221a8484611836565b515111156123745773ffffffffffffffffffffffffffffffffffffffff6122458f6119fe8686611836565b51169973ffffffffffffffffffffffffffffffffffffffff612267878c6110f8565b51168b14801561234b575b61234057815b6122828887611836565b5151811015612330578e6122e68d8d8d8d73ffffffffffffffffffffffffffffffffffffffff6122de8f8f8f90846122cf82828f6122c7906119fe896122d799611836565b51169a6110f8565b5116956110f8565b5194611836565b511692612a4e565b9060208201516122fb575b5050600101612278565b909e8f8f916123148184600194611ac4836020986110f8565b50019f0151908111612327575b8f6122f1565b9e506001612321565b509d6001919a505b019c9861220f565b9d6001919a50612338565b5073ffffffffffffffffffffffffffffffffffffffff61236b888b611836565b51168b14612272565b9694916001919b999d509b99979593929b016121ee565b50985096505050505050506123a092506110f8565b5190565b5050505094509250905093929380825282915b8183106123c95750505080611bfd5750565b909192946001906123da85846110f8565b506123e585846110f8565b515160206123f387866110f8565b510151020195602061240586856110f8565b51015101930191906123b7565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b600092916064851015611fa257612455916127ba565b92906040519061246482610db4565b6000825273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660208301526040516124b081610db4565b6124b8611fcc565b81526124d26124c5612039565b95602083019687526129b8565b948251908160011b918083046002149015171561180757611916612505612512936119168a515160208c01515190611847565b9184515190515190611847565b91604051928060061b8401604052835260009360009560005b83518110156127295760005b60028110612548575060010161252b565b73ffffffffffffffffffffffffffffffffffffffff61256783876110f8565b511673ffffffffffffffffffffffffffffffffffffffff6125888387611836565b5116146127145760005b600281106125a35750600101612537565b9093959192979960009b9597999b9c5b8d6125be8484611836565b515111156126fd5773ffffffffffffffffffffffffffffffffffffffff6125e98f6119fe8686611836565b51169973ffffffffffffffffffffffffffffffffffffffff61260b878c6110f8565b51168b1480156126d4575b6126c85760005b6126278887611836565b51518110156126b6578e61266c8d8d8d8d73ffffffffffffffffffffffffffffffffffffffff6122de8f8f8f90846122cf82828f6122c7906119fe896122d799611836565b906020820151612681575b505060010161261d565b909e8f8f9161269a8184600194611ac4836020986110f8565b50019f01519081116126ad575b8f612677565b9e5060016126a7565b509d600191929a505b019c98906125b3565b9d600191929a506126bf565b5073ffffffffffffffffffffffffffffffffffffffff6126f4888b611836565b51168b14612616565b9c50999792919593906001909b9997959b01612592565b50989750505050505050506123a092506110f8565b5099989650505050909193508181526000936000935b83851061275357505050505080611bfd5750565b909192939496602061276587866110f8565b510151606483850204116127b05760019061278087866110f8565b5151602061278e89886110f8565b51015102019760206127a088876110f8565b51015101955b019392919061273f565b96946001906127a6565b919061282757604051916127cd83610db4565b600183526020368185013773ffffffffffffffffffffffffffffffffffffffff6127f6846110eb565b911690526040519061280782610db4565b6001825260203681840137670de0b6b3a7640000612824836110eb565b52565b73ffffffffffffffffffffffffffffffffffffffff809281600754166040519485927fcb991d9400000000000000000000000000000000000000000000000000000000845216600483015281602460009384935afa9384156129ab5781928295612893575b5050509190565b91945091503d8085843e6128a78184610e1b565b820160408382031261021157825167ffffffffffffffff908181116129875784019382601f86011215612987578451946128e086610e5c565b956128ee6040519788610e1b565b808752602095868089019260051b840101928684116129a7578701915b83831061298b575050505083810151918211612987570181601f820112156129835780519061293982610e5c565b966129476040519889610e1b565b828852848089019360051b83010193841161055057508301905b828210612974575050505038808061288c565b81518152908301908301612961565b8580fd5b8680fd5b825182811681036129a357815291870191870161290b565b8b80fd5b8a80fd5b50604051903d90823e3d90fd5b9060409182516129c781610db4565b60005b848110612a405750809351908160055480845281602080950160056000527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db09260005b87828210612a2a57505050612a2492500382610e1b565b81520152565b8554845260019586019587955093019201612a0d565b6060828201526020016129ca565b9194939294604080926064825196612a6588610db4565b60009788815288602082015299845197889485937f14999e7900000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff8094818094166004880152166024860152166044840152165afa928385918695612b69575b50612ae3575b5050505050565b612af19293949596506117f4565b92670de0b6b3a764000093848102948186041490151715612b3c57506ec097ce7bc90715b34b9f1000000000905192612b2984610db4565b0482526020820152903880808080612adc565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b84809296508193503d8311612b99575b612b838183610e1b565b8101031261021157602081519101519338612ad6565b503d612b79565b92959493919093604080956064825193612bb985610db4565b6000948581528560208201529a845198899485937f14999e7900000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff8094818094166004880152166024860152166044840152165afa8094828096612c7d575b5050612c36575050505050565b6ec097ce7bc90715b34b9f10000000009394959650612c5e9291612c59916117f4565b6117f4565b04915191612c6b83610db4565b82526020820152903880808080612adc565b91955091508582813d8311612caf575b612c978183610e1b565b81010312610550575060208151910151933880612c29565b503d612c8d56fea2646970667358221220530f04a79e984b5dff092974003627fd34fc1109ea4946afeb9a75791151089464736f6c63430008130033000000000000000000000000750c1b699552caf908d67f5ccfd20a261305328c00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000015f78275ef05c40a98c4c6ea75b5d6b1f7388dc000000000000000000000000a8bfb77136451d408732298392e9c37b2c54a5aa0000000000000000000000003e55bb9383186d978db33bb796facbfcb2c491a10000000000000000000000009632e2b35f901e372939d59c3509747c641f76930000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000006a023ccd1ff6f2045c3309768ead9e68f978f6e100000000000000000000000071850b7e9ee3f13ab46d67167341e4bdc905eef9000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a830000000000000000000000004ecaba5870353805a9f068101a40e0f32ed605c6
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.