Polygon Sponsored slots available. Book your slot here!
Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0xaDd9dA09AB2f2cC4491b0285980417208120DaFD
Contract Name:
OptimisticOracleV2
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { 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 v4.4.1 (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// 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 v4.4.1 (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 substraction 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 v4.4.1 (utils/math/SignedSafeMath.sol) pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler * now has built in overflow checking. */ library SignedSafeMath { /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { return a * b; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { return a / b; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { return a - b; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { return a + b; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; import "../interfaces/AddressWhitelistInterface.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./Lockable.sol"; /** * @title A contract to track a whitelist of addresses. */ contract AddressWhitelist is AddressWhitelistInterface, Ownable, Lockable { enum Status { None, In, Out } mapping(address => Status) public whitelist; address[] public whitelistIndices; event AddedToWhitelist(address indexed addedAddress); event RemovedFromWhitelist(address indexed removedAddress); /** * @notice Adds an address to the whitelist. * @param newElement the new address to add. */ function addToWhitelist(address newElement) external override nonReentrant() onlyOwner { // Ignore if address is already included if (whitelist[newElement] == Status.In) { return; } // Only append new addresses to the array, never a duplicate if (whitelist[newElement] == Status.None) { whitelistIndices.push(newElement); } whitelist[newElement] = Status.In; emit AddedToWhitelist(newElement); } /** * @notice Removes an address from the whitelist. * @param elementToRemove the existing address to remove. */ function removeFromWhitelist(address elementToRemove) external override nonReentrant() onlyOwner { if (whitelist[elementToRemove] != Status.Out) { whitelist[elementToRemove] = Status.Out; emit RemovedFromWhitelist(elementToRemove); } } /** * @notice Checks whether an address is on the whitelist. * @param elementToCheck the address to check. * @return True if `elementToCheck` is on the whitelist, or False. */ function isOnWhitelist(address elementToCheck) external view override nonReentrantView() returns (bool) { return whitelist[elementToCheck] == Status.In; } /** * @notice Gets all addresses that are currently included in the whitelist. * @dev Note: This method skips over, but still iterates through addresses. It is possible for this call to run out * of gas if a large number of addresses have been removed. To reduce the likelihood of this unlikely scenario, we * can modify the implementation so that when addresses are removed, the last addresses in the array is moved to * the empty index. * @return activeWhitelist the list of addresses on the whitelist. */ function getWhitelist() external view override nonReentrantView() returns (address[] memory activeWhitelist) { // Determine size of whitelist first uint256 activeCount = 0; for (uint256 i = 0; i < whitelistIndices.length; i++) { if (whitelist[whitelistIndices[i]] == Status.In) { activeCount++; } } // Populate whitelist activeWhitelist = new address[](activeCount); activeCount = 0; for (uint256 i = 0; i < whitelistIndices.length; i++) { address addr = whitelistIndices[i]; if (whitelist[addr] == Status.In) { activeWhitelist[activeCount] = addr; activeCount++; } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title Library for encoding and decoding ancillary data for DVM price requests. * @notice We assume that on-chain ancillary data can be formatted directly from bytes to utf8 encoding via * web3.utils.hexToUtf8, and that clients will parse the utf8-encoded ancillary data as a comma-delimitted key-value * dictionary. Therefore, this library provides internal methods that aid appending to ancillary data from Solidity * smart contracts. More details on UMA's ancillary data guidelines below: * https://docs.google.com/document/d/1zhKKjgY1BupBGPPrY_WOJvui0B6DMcd-xDR8-9-SPDw/edit */ library AncillaryData { // This converts the bottom half of a bytes32 input to hex in a highly gas-optimized way. // Source: the brilliant implementation at https://gitter.im/ethereum/solidity?at=5840d23416207f7b0ed08c9b. function toUtf8Bytes32Bottom(bytes32 bytesIn) private pure returns (bytes32) { unchecked { uint256 x = uint256(bytesIn); // Nibble interleave x = x & 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff; x = (x | (x * 2**64)) & 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff; x = (x | (x * 2**32)) & 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff; x = (x | (x * 2**16)) & 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff; x = (x | (x * 2**8)) & 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff; x = (x | (x * 2**4)) & 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f; // Hex encode uint256 h = (x & 0x0808080808080808080808080808080808080808080808080808080808080808) / 8; uint256 i = (x & 0x0404040404040404040404040404040404040404040404040404040404040404) / 4; uint256 j = (x & 0x0202020202020202020202020202020202020202020202020202020202020202) / 2; x = x + (h & (i | j)) * 0x27 + 0x3030303030303030303030303030303030303030303030303030303030303030; // Return the result. return bytes32(x); } } /** * @notice Returns utf8-encoded bytes32 string that can be read via web3.utils.hexToUtf8. * @dev Will return bytes32 in all lower case hex characters and without the leading 0x. * This has minor changes from the toUtf8BytesAddress to control for the size of the input. * @param bytesIn bytes32 to encode. * @return utf8 encoded bytes32. */ function toUtf8Bytes(bytes32 bytesIn) internal pure returns (bytes memory) { return abi.encodePacked(toUtf8Bytes32Bottom(bytesIn >> 128), toUtf8Bytes32Bottom(bytesIn)); } /** * @notice Returns utf8-encoded address that can be read via web3.utils.hexToUtf8. * Source: https://ethereum.stackexchange.com/questions/8346/convert-address-to-string/8447#8447 * @dev Will return address in all lower case characters and without the leading 0x. * @param x address to encode. * @return utf8 encoded address bytes. */ function toUtf8BytesAddress(address x) internal pure returns (bytes memory) { return abi.encodePacked(toUtf8Bytes32Bottom(bytes32(bytes20(x)) >> 128), bytes8(toUtf8Bytes32Bottom(bytes20(x)))); } /** * @notice Converts a uint into a base-10, UTF-8 representation stored in a `string` type. * @dev This method is based off of this code: https://stackoverflow.com/a/65707309. */ function toUtf8BytesUint(uint256 x) internal pure returns (bytes memory) { if (x == 0) { return "0"; } uint256 j = x; uint256 len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint256 k = len; while (x != 0) { k = k - 1; uint8 temp = (48 + uint8(x - (x / 10) * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; x /= 10; } return bstr; } function appendKeyValueBytes32( bytes memory currentAncillaryData, bytes memory key, bytes32 value ) internal pure returns (bytes memory) { bytes memory prefix = constructPrefix(currentAncillaryData, key); return abi.encodePacked(currentAncillaryData, prefix, toUtf8Bytes(value)); } /** * @notice Adds "key:value" to `currentAncillaryData` where `value` is an address that first needs to be converted * to utf8 bytes. For example, if `utf8(currentAncillaryData)="k1:v1"`, then this function will return * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`. * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not. * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not. * @param value An address to set as the value in the key:value pair to append to `currentAncillaryData`. * @return Newly appended ancillary data. */ function appendKeyValueAddress( bytes memory currentAncillaryData, bytes memory key, address value ) internal pure returns (bytes memory) { bytes memory prefix = constructPrefix(currentAncillaryData, key); return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesAddress(value)); } /** * @notice Adds "key:value" to `currentAncillaryData` where `value` is a uint that first needs to be converted * to utf8 bytes. For example, if `utf8(currentAncillaryData)="k1:v1"`, then this function will return * `utf8(k1:v1,key:value)`, and if `currentAncillaryData` is blank, then this will return `utf8(key:value)`. * @param currentAncillaryData This bytes data should ideally be able to be utf8-decoded, but its OK if not. * @param key Again, this bytes data should ideally be able to be utf8-decoded, but its OK if not. * @param value A uint to set as the value in the key:value pair to append to `currentAncillaryData`. * @return Newly appended ancillary data. */ function appendKeyValueUint( bytes memory currentAncillaryData, bytes memory key, uint256 value ) internal pure returns (bytes memory) { bytes memory prefix = constructPrefix(currentAncillaryData, key); return abi.encodePacked(currentAncillaryData, prefix, toUtf8BytesUint(value)); } /** * @notice Helper method that returns the left hand side of a "key:value" pair plus the colon ":" and a leading * comma "," if the `currentAncillaryData` is not empty. The return value is intended to be prepended as a prefix to * some utf8 value that is ultimately added to a comma-delimited, key-value dictionary. */ function constructPrefix(bytes memory currentAncillaryData, bytes memory key) internal pure returns (bytes memory) { if (currentAncillaryData.length > 0) { return abi.encodePacked(",", key, ":"); } else { return abi.encodePacked(key, ":"); } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/math/SignedSafeMath.sol"; /** * @title Library for fixed point arithmetic on uints */ library FixedPoint { using SafeMath for uint256; using SignedSafeMath for int256; // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5". // For unsigned values: // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77. uint256 private constant FP_SCALING_FACTOR = 10**18; // --------------------------------------- UNSIGNED ----------------------------------------------------------------------------- struct Unsigned { uint256 rawValue; } /** * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5*(10**18)`. * @param a uint to convert into a FixedPoint. * @return the converted FixedPoint. */ function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) { return Unsigned(a.mul(FP_SCALING_FACTOR)); } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if equal, or False. */ function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue == fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if equal, or False. */ function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue == b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a > b`, or False. */ function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue > b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a > b`, or False. */ function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue > fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a > b`, or False. */ function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue > b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue >= b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue >= fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue >= b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a < b`, or False. */ function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue < b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a < b`, or False. */ function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue < fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a < b`, or False. */ function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue < b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue <= b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue <= fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue <= b.rawValue; } /** * @notice The minimum of `a` and `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return the minimum of `a` and `b`. */ function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return a.rawValue < b.rawValue ? a : b; } /** * @notice The maximum of `a` and `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return the maximum of `a` and `b`. */ function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return a.rawValue > b.rawValue ? a : b; } /** * @notice Adds two `Unsigned`s, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the sum of `a` and `b`. */ function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.add(b.rawValue)); } /** * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow. * @param a a FixedPoint. * @param b a uint256. * @return the sum of `a` and `b`. */ function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return add(a, fromUnscaledUint(b)); } /** * @notice Subtracts two `Unsigned`s, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the difference of `a` and `b`. */ function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.sub(b.rawValue)); } /** * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow. * @param a a FixedPoint. * @param b a uint256. * @return the difference of `a` and `b`. */ function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return sub(a, fromUnscaledUint(b)); } /** * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow. * @param a a uint256. * @param b a FixedPoint. * @return the difference of `a` and `b`. */ function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) { return sub(fromUnscaledUint(a), b); } /** * @notice Multiplies two `Unsigned`s, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint. * @param b a FixedPoint. * @return the product of `a` and `b`. */ function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { // There are two caveats with this computation: // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is // stored internally as a uint256 ~10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which // would round to 3, but this computation produces the result 2. // No need to use SafeMath because FP_SCALING_FACTOR != 0. return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR); } /** * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint. * @param b a uint256. * @return the product of `a` and `b`. */ function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.mul(b)); } /** * @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the product of `a` and `b`. */ function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { uint256 mulRaw = a.rawValue.mul(b.rawValue); uint256 mulFloor = mulRaw / FP_SCALING_FACTOR; uint256 mod = mulRaw.mod(FP_SCALING_FACTOR); if (mod != 0) { return Unsigned(mulFloor.add(1)); } else { return Unsigned(mulFloor); } } /** * @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the product of `a` and `b`. */ function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { // Since b is an uint, there is no risk of truncation and we can just mul it normally return Unsigned(a.rawValue.mul(b)); } /** * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { // There are two caveats with this computation: // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows. // 10^41 is stored internally as a uint256 10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666. return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue)); } /** * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b a uint256 denominator. * @return the quotient of `a` divided by `b`. */ function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.div(b)); } /** * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a uint256 numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) { return div(fromUnscaledUint(a), b); } /** * @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR); uint256 divFloor = aScaled.div(b.rawValue); uint256 mod = aScaled.mod(b.rawValue); if (mod != 0) { return Unsigned(divFloor.add(1)); } else { return Unsigned(divFloor); } } /** * @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b a uint256 denominator. * @return the quotient of `a` divided by `b`. */ function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { // Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))" // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned. // This creates the possibility of overflow if b is very large. return divCeil(a, fromUnscaledUint(b)); } /** * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`. * @dev This will "floor" the result. * @param a a FixedPoint numerator. * @param b a uint256 denominator. * @return output is `a` to the power of `b`. */ function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) { output = fromUnscaledUint(1); for (uint256 i = 0; i < b; i = i.add(1)) { output = mul(output, a); } } // ------------------------------------------------- SIGNED ------------------------------------------------------------- // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5". // For signed values: // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76. int256 private constant SFP_SCALING_FACTOR = 10**18; struct Signed { int256 rawValue; } function fromSigned(Signed memory a) internal pure returns (Unsigned memory) { require(a.rawValue >= 0, "Negative value provided"); return Unsigned(uint256(a.rawValue)); } function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) { require(a.rawValue <= uint256(type(int256).max), "Unsigned too large"); return Signed(int256(a.rawValue)); } /** * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5*(10**18)`. * @param a int to convert into a FixedPoint.Signed. * @return the converted FixedPoint.Signed. */ function fromUnscaledInt(int256 a) internal pure returns (Signed memory) { return Signed(a.mul(SFP_SCALING_FACTOR)); } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint.Signed. * @param b a int256. * @return True if equal, or False. */ function isEqual(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue == fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if equal, or False. */ function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue == b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a > b`, or False. */ function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue > b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a > b`, or False. */ function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue > fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a > b`, or False. */ function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue > b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue >= b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue >= fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue >= b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a < b`, or False. */ function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue < b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a < b`, or False. */ function isLessThan(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue < fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is less than `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a < b`, or False. */ function isLessThan(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue < b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue <= b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue <= fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue <= b.rawValue; } /** * @notice The minimum of `a` and `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the minimum of `a` and `b`. */ function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return a.rawValue < b.rawValue ? a : b; } /** * @notice The maximum of `a` and `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the maximum of `a` and `b`. */ function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return a.rawValue > b.rawValue ? a : b; } /** * @notice Adds two `Signed`s, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the sum of `a` and `b`. */ function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return Signed(a.rawValue.add(b.rawValue)); } /** * @notice Adds an `Signed` to an unscaled int, reverting on overflow. * @param a a FixedPoint.Signed. * @param b an int256. * @return the sum of `a` and `b`. */ function add(Signed memory a, int256 b) internal pure returns (Signed memory) { return add(a, fromUnscaledInt(b)); } /** * @notice Subtracts two `Signed`s, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the difference of `a` and `b`. */ function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return Signed(a.rawValue.sub(b.rawValue)); } /** * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow. * @param a a FixedPoint.Signed. * @param b an int256. * @return the difference of `a` and `b`. */ function sub(Signed memory a, int256 b) internal pure returns (Signed memory) { return sub(a, fromUnscaledInt(b)); } /** * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow. * @param a an int256. * @param b a FixedPoint.Signed. * @return the difference of `a` and `b`. */ function sub(int256 a, Signed memory b) internal pure returns (Signed memory) { return sub(fromUnscaledInt(a), b); } /** * @notice Multiplies two `Signed`s, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the product of `a` and `b`. */ function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) { // There are two caveats with this computation: // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is // stored internally as an int256 ~10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which // would round to 3, but this computation produces the result 2. // No need to use SafeMath because SFP_SCALING_FACTOR != 0. return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR); } /** * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint.Signed. * @param b an int256. * @return the product of `a` and `b`. */ function mul(Signed memory a, int256 b) internal pure returns (Signed memory) { return Signed(a.rawValue.mul(b)); } /** * @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the product of `a` and `b`. */ function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) { int256 mulRaw = a.rawValue.mul(b.rawValue); int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR; // Manual mod because SignedSafeMath doesn't support it. int256 mod = mulRaw % SFP_SCALING_FACTOR; if (mod != 0) { bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0); int256 valueToAdd = isResultPositive ? int256(1) : int256(-1); return Signed(mulTowardsZero.add(valueToAdd)); } else { return Signed(mulTowardsZero); } } /** * @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the product of `a` and `b`. */ function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) { // Since b is an int, there is no risk of truncation and we can just mul it normally return Signed(a.rawValue.mul(b)); } /** * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) { // There are two caveats with this computation: // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows. // 10^41 is stored internally as an int256 10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666. return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue)); } /** * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b an int256 denominator. * @return the quotient of `a` divided by `b`. */ function div(Signed memory a, int256 b) internal pure returns (Signed memory) { return Signed(a.rawValue.div(b)); } /** * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a an int256 numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(int256 a, Signed memory b) internal pure returns (Signed memory) { return div(fromUnscaledInt(a), b); } /** * @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) { int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR); int256 divTowardsZero = aScaled.div(b.rawValue); // Manual mod because SignedSafeMath doesn't support it. int256 mod = aScaled % b.rawValue; if (mod != 0) { bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0); int256 valueToAdd = isResultPositive ? int256(1) : int256(-1); return Signed(divTowardsZero.add(valueToAdd)); } else { return Signed(divTowardsZero); } } /** * @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b an int256 denominator. * @return the quotient of `a` divided by `b`. */ function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) { // Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))" // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed. // This creates the possibility of overflow if b is very large. return divAwayFromZero(a, fromUnscaledInt(b)); } /** * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`. * @dev This will "floor" the result. * @param a a FixedPoint.Signed. * @param b a uint256 (negative exponents are not allowed). * @return output is `a` to the power of `b`. */ function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) { output = fromUnscaledInt(1); for (uint256 i = 0; i < b; i = i.add(1)) { output = mul(output, a); } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title A contract that provides modifiers to prevent reentrancy to state-changing and view-only methods. This contract * is inspired by https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol * and https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol. */ contract Lockable { bool private _notEntered; constructor() { // Storing an initial non-zero value makes deployment a bit more expensive, but in exchange the refund on every // call to nonReentrant will be lower in amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to increase the likelihood of the full // refund coming into effect. _notEntered = true; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` function is not supported. It is possible to * prevent this from happening by making the `nonReentrant` function external, and making it call a `private` * function that does the actual state modification. */ modifier nonReentrant() { _preEntranceCheck(); _preEntranceSet(); _; _postEntranceReset(); } /** * @dev Designed to prevent a view-only method from being re-entered during a call to a `nonReentrant()` state-changing method. */ modifier nonReentrantView() { _preEntranceCheck(); _; } // Internal methods are used to avoid copying the require statement's bytecode to every `nonReentrant()` method. // On entry into a function, `_preEntranceCheck()` should always be called to check if the function is being // re-entered. Then, if the function modifies state, it should call `_postEntranceSet()`, perform its logic, and // then call `_postEntranceReset()`. // View-only methods can simply call `_preEntranceCheck()` to make sure that it is not being re-entered. function _preEntranceCheck() internal view { // On the first call to nonReentrant, _notEntered will be true require(_notEntered, "ReentrancyGuard: reentrant call"); } function _preEntranceSet() internal { // Any calls to nonReentrant after this point will fail _notEntered = false; } function _postEntranceReset() internal { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _notEntered = true; } // These functions are intended to be used by child contracts to temporarily disable and re-enable the guard. // Intended use: // _startReentrantGuardDisabled(); // ... // _endReentrantGuardDisabled(); // // IMPORTANT: these should NEVER be used in a method that isn't inside a nonReentrant block. Otherwise, it's // possible to permanently lock your contract. function _startReentrantGuardDisabled() internal { _notEntered = true; } function _endReentrantGuardDisabled() internal { _notEntered = false; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; import "./Timer.sol"; /** * @title Base class that provides time overrides, but only if being run in test mode. */ abstract contract Testable { // If the contract is being run in production, then `timerAddress` will be the 0x0 address. // Note: this variable should be set on construction and never modified. address public timerAddress; /** * @notice Constructs the Testable contract. Called by child contracts. * @param _timerAddress Contract that stores the current time in a testing environment. * Must be set to 0x0 for production environments that use live time. */ constructor(address _timerAddress) { timerAddress = _timerAddress; } /** * @notice Reverts if not running in test mode. */ modifier onlyIfTest { require(timerAddress != address(0x0)); _; } /** * @notice Sets the current time. * @dev Will revert if not running in test mode. * @param time timestamp to set current Testable time to. */ function setCurrentTime(uint256 time) external onlyIfTest { Timer(timerAddress).setCurrentTime(time); } /** * @notice Gets the current time. Will return the last time set in `setCurrentTime` if running in test mode. * Otherwise, it will return the block timestamp. * @return uint for the current Testable timestamp. */ function getCurrentTime() public view virtual returns (uint256) { if (timerAddress != address(0x0)) { return Timer(timerAddress).getCurrentTime(); } else { return block.timestamp; // solhint-disable-line not-rely-on-time } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title Universal store of current contract time for testing environments. */ contract Timer { uint256 private currentTime; constructor() { currentTime = block.timestamp; // solhint-disable-line not-rely-on-time } /** * @notice Sets the current time. * @dev Will revert if not running in test mode. * @param time timestamp to set `currentTime` to. */ function setCurrentTime(uint256 time) external { currentTime = time; } /** * @notice Gets the currentTime variable set in the Timer. * @return uint256 for the current Testable timestamp. */ function getCurrentTime() public view returns (uint256) { return currentTime; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; interface AddressWhitelistInterface { function addToWhitelist(address newElement) external; function removeFromWhitelist(address newElement) external; function isOnWhitelist(address newElement) external view returns (bool); function getWhitelist() external view returns (address[] memory); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title Stores common interface names used throughout the DVM by registration in the Finder. */ library OracleInterfaces { bytes32 public constant Oracle = "Oracle"; bytes32 public constant IdentifierWhitelist = "IdentifierWhitelist"; bytes32 public constant Store = "Store"; bytes32 public constant FinancialContractsAdmin = "FinancialContractsAdmin"; bytes32 public constant Registry = "Registry"; bytes32 public constant CollateralWhitelist = "CollateralWhitelist"; bytes32 public constant OptimisticOracle = "OptimisticOracle"; bytes32 public constant Bridge = "Bridge"; bytes32 public constant GenericHandler = "GenericHandler"; bytes32 public constant SkinnyOptimisticOracle = "SkinnyOptimisticOracle"; bytes32 public constant ChildMessenger = "ChildMessenger"; bytes32 public constant OracleHub = "OracleHub"; bytes32 public constant OracleSpoke = "OracleSpoke"; } /** * @title Commonly re-used values for contracts associated with the OptimisticOracle. */ library OptimisticOracleConstraints { // Any price request submitted to the OptimisticOracle must contain ancillary data no larger than this value. // This value must be <= the Voting contract's `ancillaryBytesLimit` constant value otherwise it is possible // that a price can be requested to the OptimisticOracle successfully, but cannot be resolved by the DVM which // refuses to accept a price request made with ancillary data length over a certain size. uint256 public constant ancillaryBytesLimit = 8192; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "../interfaces/StoreInterface.sol"; import "../interfaces/OracleAncillaryInterface.sol"; import "../interfaces/FinderInterface.sol"; import "../interfaces/IdentifierWhitelistInterface.sol"; import "../interfaces/OptimisticOracleV2Interface.sol"; import "./Constants.sol"; import "../../common/implementation/Testable.sol"; import "../../common/implementation/Lockable.sol"; import "../../common/implementation/FixedPoint.sol"; import "../../common/implementation/AncillaryData.sol"; import "../../common/implementation/AddressWhitelist.sol"; /** * @title Optimistic Requester. * @notice Optional interface that requesters can implement to receive callbacks. * @dev this contract does _not_ work with ERC777 collateral currencies or any others that call into the receiver on * transfer(). Using an ERC777 token would allow a user to maliciously grief other participants (while also losing * money themselves). */ interface OptimisticRequester { /** * @notice Callback for proposals. * @param identifier price identifier being requested. * @param timestamp timestamp of the price being requested. * @param ancillaryData ancillary data of the price being requested. */ function priceProposed( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external; /** * @notice Callback for disputes. * @param identifier price identifier being requested. * @param timestamp timestamp of the price being requested. * @param ancillaryData ancillary data of the price being requested. * @param refund refund received in the case that refundOnDispute was enabled. */ function priceDisputed( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 refund ) external; /** * @notice Callback for settlement. * @param identifier price identifier being requested. * @param timestamp timestamp of the price being requested. * @param ancillaryData ancillary data of the price being requested. * @param price price that was resolved by the escalation process. */ function priceSettled( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, int256 price ) external; } /** * @title Optimistic Oracle. * @notice Pre-DVM escalation contract that allows faster settlement. */ contract OptimisticOracleV2 is OptimisticOracleV2Interface, Testable, Lockable { using SafeMath for uint256; using SafeERC20 for IERC20; using Address for address; // Finder to provide addresses for DVM contracts. FinderInterface public override finder; // Default liveness value for all price requests. uint256 public override defaultLiveness; // This is effectively the extra ancillary data to add ",ooRequester:0000000000000000000000000000000000000000". uint256 private constant MAX_ADDED_ANCILLARY_DATA = 53; uint256 public constant OO_ANCILLARY_DATA_LIMIT = ancillaryBytesLimit - MAX_ADDED_ANCILLARY_DATA; int256 public constant TOO_EARLY_RESPONSE = type(int256).min; /** * @notice Constructor. * @param _liveness default liveness applied to each price request. * @param _finderAddress finder to use to get addresses of DVM contracts. * @param _timerAddress address of the timer contract. Should be 0x0 in prod. */ constructor( uint256 _liveness, address _finderAddress, address _timerAddress ) Testable(_timerAddress) { finder = FinderInterface(_finderAddress); _validateLiveness(_liveness); defaultLiveness = _liveness; } /** * @notice Requests a new price. * @param identifier price identifier being requested. * @param timestamp timestamp of the price being requested. * @param ancillaryData ancillary data representing additional args being passed with the price request. * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM. * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0, * which could make sense if the contract requests and proposes the value in the same call or * provides its own reward system. * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay. * This can be changed with a subsequent call to setBond(). */ function requestPrice( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, IERC20 currency, uint256 reward ) external override nonReentrant() returns (uint256 totalBond) { require(_getState(msg.sender, identifier, timestamp, ancillaryData) == State.Invalid, "requestPrice: Invalid"); require(_getIdentifierWhitelist().isIdentifierSupported(identifier), "Unsupported identifier"); require(_getCollateralWhitelist().isOnWhitelist(address(currency)), "Unsupported currency"); require(timestamp <= getCurrentTime(), "Timestamp in future"); // This ensures that the ancillary data is <= the OO limit, which is lower than the DVM limit because the // OO adds some data before sending to the DVM. require(ancillaryData.length <= OO_ANCILLARY_DATA_LIMIT, "Ancillary Data too long"); uint256 finalFee = _getStore().computeFinalFee(address(currency)).rawValue; requests[_getId(msg.sender, identifier, timestamp, ancillaryData)] = Request({ proposer: address(0), disputer: address(0), currency: currency, settled: false, requestSettings: RequestSettings({ eventBased: false, refundOnDispute: false, callbackOnPriceProposed: false, callbackOnPriceDisputed: false, callbackOnPriceSettled: false, bond: finalFee, customLiveness: 0 }), proposedPrice: 0, resolvedPrice: 0, expirationTime: 0, reward: reward, finalFee: finalFee }); if (reward > 0) { currency.safeTransferFrom(msg.sender, address(this), reward); } emit RequestPrice(msg.sender, identifier, timestamp, ancillaryData, address(currency), reward, finalFee); // This function returns the initial proposal bond for this request, which can be customized by calling // setBond() with the same identifier and timestamp. return finalFee.mul(2); } /** * @notice Set the proposal bond associated with a price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param bond custom bond amount to set. * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be * changed again with a subsequent call to setBond(). */ function setBond( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 bond ) external override nonReentrant() returns (uint256 totalBond) { require(_getState(msg.sender, identifier, timestamp, ancillaryData) == State.Requested, "setBond: Requested"); Request storage request = _getRequest(msg.sender, identifier, timestamp, ancillaryData); request.requestSettings.bond = bond; // Total bond is the final fee + the newly set bond. return bond.add(request.finalFee); } /** * @notice Sets the request to refund the reward if the proposal is disputed. This can help to "hedge" the caller * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's * bond, so there is still profit to be made even if the reward is refunded. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. */ function setRefundOnDispute( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external override nonReentrant() { require( _getState(msg.sender, identifier, timestamp, ancillaryData) == State.Requested, "setRefundOnDispute: Requested" ); _getRequest(msg.sender, identifier, timestamp, ancillaryData).requestSettings.refundOnDispute = true; } /** * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before * being auto-resolved. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param customLiveness new custom liveness. */ function setCustomLiveness( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 customLiveness ) external override nonReentrant() { require( _getState(msg.sender, identifier, timestamp, ancillaryData) == State.Requested, "setCustomLiveness: Requested" ); _validateLiveness(customLiveness); _getRequest(msg.sender, identifier, timestamp, ancillaryData).requestSettings.customLiveness = customLiveness; } /** * @notice Sets the request to be an "event-based" request. * @dev Calling this method has a few impacts on the request: * * 1. The timestamp at which the request is evaluated is the time of the proposal, not the timestamp associated * with the request. * * 2. The proposer cannot propose the "too early" value (TOO_EARLY_RESPONSE). This is to ensure that a proposer who * prematurely proposes a response loses their bond. * * 3. RefundoOnDispute is automatically set, meaning disputes trigger the reward to be automatically refunded to * the requesting contract. * * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. */ function setEventBased( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external override nonReentrant() { require( _getState(msg.sender, identifier, timestamp, ancillaryData) == State.Requested, "setEventBased: Requested" ); Request storage request = _getRequest(msg.sender, identifier, timestamp, ancillaryData); request.requestSettings.eventBased = true; request.requestSettings.refundOnDispute = true; } /** * @notice Sets which callbacks should be enabled for the request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param callbackOnPriceProposed whether to enable the callback onPriceProposed. * @param callbackOnPriceDisputed whether to enable the callback onPriceDisputed. * @param callbackOnPriceSettled whether to enable the callback onPriceSettled. */ function setCallbacks( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, bool callbackOnPriceProposed, bool callbackOnPriceDisputed, bool callbackOnPriceSettled ) external override nonReentrant() { require( _getState(msg.sender, identifier, timestamp, ancillaryData) == State.Requested, "setCallbacks: Requested" ); Request storage request = _getRequest(msg.sender, identifier, timestamp, ancillaryData); request.requestSettings.callbackOnPriceProposed = callbackOnPriceProposed; request.requestSettings.callbackOnPriceDisputed = callbackOnPriceDisputed; request.requestSettings.callbackOnPriceSettled = callbackOnPriceSettled; } /** * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come * from this proposal. However, any bonds are pulled from the caller. * @param proposer address to set as the proposer. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param proposedPrice price being proposed. * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to * the proposer once settled if the proposal is correct. */ function proposePriceFor( address proposer, address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, int256 proposedPrice ) public override nonReentrant() returns (uint256 totalBond) { require(proposer != address(0), "proposer address must be non 0"); require( _getState(requester, identifier, timestamp, ancillaryData) == State.Requested, "proposePriceFor: Requested" ); Request storage request = _getRequest(requester, identifier, timestamp, ancillaryData); if (request.requestSettings.eventBased) require(proposedPrice != TOO_EARLY_RESPONSE, "Cannot propose 'too early'"); request.proposer = proposer; request.proposedPrice = proposedPrice; // If a custom liveness has been set, use it instead of the default. request.expirationTime = getCurrentTime().add( request.requestSettings.customLiveness != 0 ? request.requestSettings.customLiveness : defaultLiveness ); totalBond = request.requestSettings.bond.add(request.finalFee); if (totalBond > 0) request.currency.safeTransferFrom(msg.sender, address(this), totalBond); emit ProposePrice( requester, proposer, identifier, timestamp, ancillaryData, proposedPrice, request.expirationTime, address(request.currency) ); // End the re-entrancy guard early to allow the caller to potentially take OO-related actions inside this callback. _startReentrantGuardDisabled(); // Callback. if (address(requester).isContract() && request.requestSettings.callbackOnPriceProposed) OptimisticRequester(requester).priceProposed(identifier, timestamp, ancillaryData); _endReentrantGuardDisabled(); } /** * @notice Proposes a price value for an existing price request. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param proposedPrice price being proposed. * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to * the proposer once settled if the proposal is correct. */ function proposePrice( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, int256 proposedPrice ) external override returns (uint256 totalBond) { // Note: re-entrancy guard is done in the inner call. return proposePriceFor(msg.sender, requester, identifier, timestamp, ancillaryData, proposedPrice); } /** * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will * receive any rewards that come from this dispute. However, any bonds are pulled from the caller. * @param disputer address to set as the disputer. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to * the disputer once settled if the dispute was valid (the proposal was incorrect). */ function disputePriceFor( address disputer, address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public override nonReentrant() returns (uint256 totalBond) { require(disputer != address(0), "disputer address must be non 0"); require( _getState(requester, identifier, timestamp, ancillaryData) == State.Proposed, "disputePriceFor: Proposed" ); Request storage request = _getRequest(requester, identifier, timestamp, ancillaryData); request.disputer = disputer; uint256 finalFee = request.finalFee; uint256 bond = request.requestSettings.bond; totalBond = bond.add(finalFee); if (totalBond > 0) { request.currency.safeTransferFrom(msg.sender, address(this), totalBond); } StoreInterface store = _getStore(); // Along with the final fee, "burn" part of the loser's bond to ensure that a larger bond always makes it // proportionally more expensive to delay the resolution even if the proposer and disputer are the same // party. // The total fee is the burned bond and the final fee added together. uint256 totalFee = finalFee.add(_computeBurnedBond(request)); if (totalFee > 0) { request.currency.safeIncreaseAllowance(address(store), totalFee); _getStore().payOracleFeesErc20(address(request.currency), FixedPoint.Unsigned(totalFee)); } _getOracle().requestPrice( identifier, _getTimestampForDvmRequest(request, timestamp), _stampAncillaryData(ancillaryData, requester) ); // Compute refund. uint256 refund = 0; if (request.reward > 0 && request.requestSettings.refundOnDispute) { refund = request.reward; request.reward = 0; request.currency.safeTransfer(requester, refund); } emit DisputePrice( requester, request.proposer, disputer, identifier, timestamp, ancillaryData, request.proposedPrice ); // End the re-entrancy guard early to allow the caller to potentially re-request inside this callback. _startReentrantGuardDisabled(); // Callback. if (address(requester).isContract() && request.requestSettings.callbackOnPriceDisputed) OptimisticRequester(requester).priceDisputed(identifier, timestamp, ancillaryData, refund); _endReentrantGuardDisabled(); } /** * @notice Disputes a price value for an existing price request with an active proposal. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to * the disputer once settled if the dispute was valid (the proposal was incorrect). */ function disputePrice( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external override returns (uint256 totalBond) { // Note: re-entrancy guard is done in the inner call. return disputePriceFor(msg.sender, requester, identifier, timestamp, ancillaryData); } /** * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled * or settleable. Note: this method is not view so that this call may actually settle the price request if it * hasn't been settled. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return resolved price. */ function settleAndGetPrice( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external override nonReentrant() returns (int256) { if (_getState(msg.sender, identifier, timestamp, ancillaryData) != State.Settled) { _settle(msg.sender, identifier, timestamp, ancillaryData); } return _getRequest(msg.sender, identifier, timestamp, ancillaryData).resolvedPrice; } /** * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes * the returned bonds as well as additional rewards. */ function settle( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external override nonReentrant() returns (uint256 payout) { return _settle(requester, identifier, timestamp, ancillaryData); } /** * @notice Gets the current data structure containing all information about a price request. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return the Request data structure. */ function getRequest( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public view override nonReentrantView() returns (Request memory) { return _getRequest(requester, identifier, timestamp, ancillaryData); } /** * @notice Computes the current state of a price request. See the State enum for more details. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return the State. */ function getState( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public view override nonReentrantView() returns (State) { return _getState(requester, identifier, timestamp, ancillaryData); } /** * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price). * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return boolean indicating true if price exists and false if not. */ function hasPrice( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public view override nonReentrantView() returns (bool) { State state = _getState(requester, identifier, timestamp, ancillaryData); return state == State.Settled || state == State.Resolved || state == State.Expired; } /** * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute. * @param ancillaryData ancillary data of the price being requested. * @param requester sender of the initial price request. * @return the stamped ancillary bytes. */ function stampAncillaryData(bytes memory ancillaryData, address requester) public pure override returns (bytes memory) { return _stampAncillaryData(ancillaryData, requester); } function _getId( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) private pure returns (bytes32) { return keccak256(abi.encodePacked(requester, identifier, timestamp, ancillaryData)); } function _settle( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) private returns (uint256 payout) { State state = _getState(requester, identifier, timestamp, ancillaryData); // Set it to settled so this function can never be entered again. Request storage request = _getRequest(requester, identifier, timestamp, ancillaryData); request.settled = true; if (state == State.Expired) { // In the expiry case, just pay back the proposer's bond and final fee along with the reward. request.resolvedPrice = request.proposedPrice; payout = request.requestSettings.bond.add(request.finalFee).add(request.reward); request.currency.safeTransfer(request.proposer, payout); } else if (state == State.Resolved) { // In the Resolved case, pay either the disputer or the proposer the entire payout (+ bond and reward). request.resolvedPrice = _getOracle().getPrice( identifier, _getTimestampForDvmRequest(request, timestamp), _stampAncillaryData(ancillaryData, requester) ); bool disputeSuccess = request.resolvedPrice != request.proposedPrice; uint256 bond = request.requestSettings.bond; // Unburned portion of the loser's bond = 1 - burned bond. uint256 unburnedBond = bond.sub(_computeBurnedBond(request)); // Winner gets: // - Their bond back. // - The unburned portion of the loser's bond. // - Their final fee back. // - The request reward (if not already refunded -- if refunded, it will be set to 0). payout = bond.add(unburnedBond).add(request.finalFee).add(request.reward); request.currency.safeTransfer(disputeSuccess ? request.disputer : request.proposer, payout); } else revert("_settle: not settleable"); emit Settle( requester, request.proposer, request.disputer, identifier, timestamp, ancillaryData, request.resolvedPrice, payout ); // Temporarily disable the re-entrancy guard early to allow the caller to take an OO-related action inside this callback. _startReentrantGuardDisabled(); // Callback. if (address(requester).isContract() && request.requestSettings.callbackOnPriceSettled) OptimisticRequester(requester).priceSettled(identifier, timestamp, ancillaryData, request.resolvedPrice); _endReentrantGuardDisabled(); } function _getRequest( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) private view returns (Request storage) { return requests[_getId(requester, identifier, timestamp, ancillaryData)]; } function _computeBurnedBond(Request storage request) private view returns (uint256) { // burnedBond = floor(bond / 2) return request.requestSettings.bond.div(2); } function _validateLiveness(uint256 _liveness) private pure { require(_liveness < 5200 weeks, "Liveness too large"); require(_liveness > 0, "Liveness cannot be 0"); } function _getState( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) internal view returns (State) { Request storage request = _getRequest(requester, identifier, timestamp, ancillaryData); if (address(request.currency) == address(0)) return State.Invalid; if (request.proposer == address(0)) return State.Requested; if (request.settled) return State.Settled; if (request.disputer == address(0)) return request.expirationTime <= getCurrentTime() ? State.Expired : State.Proposed; return _getOracle().hasPrice( identifier, _getTimestampForDvmRequest(request, timestamp), _stampAncillaryData(ancillaryData, requester) ) ? State.Resolved : State.Disputed; } function _getOracle() internal view returns (OracleAncillaryInterface) { return OracleAncillaryInterface(finder.getImplementationAddress(OracleInterfaces.Oracle)); } function _getCollateralWhitelist() internal view returns (AddressWhitelist) { return AddressWhitelist(finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist)); } function _getStore() internal view returns (StoreInterface) { return StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store)); } function _getIdentifierWhitelist() internal view returns (IdentifierWhitelistInterface) { return IdentifierWhitelistInterface(finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist)); } function _getTimestampForDvmRequest(Request storage request, uint256 requestTimestamp) internal view returns (uint256) { if (request.requestSettings.eventBased) { uint256 liveness = request.requestSettings.customLiveness != 0 ? request.requestSettings.customLiveness : defaultLiveness; return request.expirationTime.sub(liveness); } else { return requestTimestamp; } } /** * @dev We don't handle specifically the case where `ancillaryData` is not already readily translateable in utf8. * For those cases, we assume that the client will be able to strip out the utf8-translateable part of the * ancillary data that this contract stamps. */ function _stampAncillaryData(bytes memory ancillaryData, address requester) internal pure returns (bytes memory) { // Since this contract will be the one to formally submit DVM price requests, its useful for voters to know who // the original requester was. return AncillaryData.appendKeyValueAddress(ancillaryData, "ooRequester", requester); } function getCurrentTime() public view override(Testable, OptimisticOracleV2Interface) returns (uint256) { return Testable.getCurrentTime(); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title Provides addresses of the live contracts implementing certain interfaces. * @dev Examples are the Oracle or Store interfaces. */ interface FinderInterface { /** * @notice Updates the address of the contract that implements `interfaceName`. * @param interfaceName bytes32 encoding of the interface name that is either changed or registered. * @param implementationAddress address of the deployed contract that implements the interface. */ function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external; /** * @notice Gets the address of the contract that implements the given `interfaceName`. * @param interfaceName queried interface. * @return implementationAddress address of the deployed contract that implements the interface. */ function getImplementationAddress(bytes32 interfaceName) external view returns (address); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title Interface for whitelists of supported identifiers that the oracle can provide prices for. */ interface IdentifierWhitelistInterface { /** * @notice Adds the provided identifier as a supported identifier. * @dev Price requests using this identifier will succeed after this call. * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD. */ function addSupportedIdentifier(bytes32 identifier) external; /** * @notice Removes the identifier from the whitelist. * @dev Price requests using this identifier will no longer succeed after this call. * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD. */ function removeSupportedIdentifier(bytes32 identifier) external; /** * @notice Checks whether an identifier is on the whitelist. * @param identifier bytes32 encoding of the string identifier. Eg: BTC/USD. * @return bool if the identifier is supported (or not). */ function isIdentifierSupported(bytes32 identifier) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./FinderInterface.sol"; /** * @title Financial contract facing Oracle interface. * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface. */ abstract contract OptimisticOracleV2Interface { event RequestPrice( address indexed requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData, address currency, uint256 reward, uint256 finalFee ); event ProposePrice( address indexed requester, address indexed proposer, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 proposedPrice, uint256 expirationTimestamp, address currency ); event DisputePrice( address indexed requester, address indexed proposer, address indexed disputer, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 proposedPrice ); event Settle( address indexed requester, address indexed proposer, address indexed disputer, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 price, uint256 payout ); // Struct representing the state of a price request. enum State { Invalid, // Never requested. Requested, // Requested, no other actions taken. Proposed, // Proposed, but not expired or disputed yet. Expired, // Proposed, not disputed, past liveness. Disputed, // Disputed, but no DVM price returned yet. Resolved, // Disputed and DVM price is available. Settled // Final price has been set in the contract (can get here from Expired or Resolved). } struct RequestSettings { bool eventBased; // True if the request is set to be event-based. bool refundOnDispute; // True if the requester should be refunded their reward on dispute. bool callbackOnPriceProposed; // True if callbackOnPriceProposed callback is required. bool callbackOnPriceDisputed; // True if callbackOnPriceDisputed callback is required. bool callbackOnPriceSettled; // True if callbackOnPriceSettled callback is required. uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee. uint256 customLiveness; // Custom liveness value set by the requester. } // Struct representing a price request. struct Request { address proposer; // Address of the proposer. address disputer; // Address of the disputer. IERC20 currency; // ERC20 token used to pay rewards and fees. bool settled; // True if the request is settled. RequestSettings requestSettings; // Custom settings associated with a request. int256 proposedPrice; // Price that the proposer submitted. int256 resolvedPrice; // Price resolved once the request is settled. uint256 expirationTime; // Time at which the request auto-settles without a dispute. uint256 reward; // Amount of the currency to pay to the proposer on settlement. uint256 finalFee; // Final fee to pay to the Store upon request to the DVM. } // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses // to accept a price request made with ancillary data length over a certain size. uint256 public constant ancillaryBytesLimit = 8192; function defaultLiveness() external view virtual returns (uint256); function finder() external view virtual returns (FinderInterface); function getCurrentTime() external view virtual returns (uint256); // Note: this is required so that typechain generates a return value with named fields. mapping(bytes32 => Request) public requests; /** * @notice Requests a new price. * @param identifier price identifier being requested. * @param timestamp timestamp of the price being requested. * @param ancillaryData ancillary data representing additional args being passed with the price request. * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM. * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0, * which could make sense if the contract requests and proposes the value in the same call or * provides its own reward system. * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay. * This can be changed with a subsequent call to setBond(). */ function requestPrice( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, IERC20 currency, uint256 reward ) external virtual returns (uint256 totalBond); /** * @notice Set the proposal bond associated with a price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param bond custom bond amount to set. * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be * changed again with a subsequent call to setBond(). */ function setBond( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 bond ) external virtual returns (uint256 totalBond); /** * @notice Sets the request to refund the reward if the proposal is disputed. This can help to "hedge" the caller * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's * bond, so there is still profit to be made even if the reward is refunded. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. */ function setRefundOnDispute( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external virtual; /** * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before * being auto-resolved. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param customLiveness new custom liveness. */ function setCustomLiveness( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 customLiveness ) external virtual; /** * @notice Sets the request to be an "event-based" request. * @dev Calling this method has a few impacts on the request: * * 1. The timestamp at which the request is evaluated is the time of the proposal, not the timestamp associated * with the request. * * 2. The proposer cannot propose the "too early" value (TOO_EARLY_RESPONSE). This is to ensure that a proposer who * prematurely proposes a response loses their bond. * * 3. RefundoOnDispute is automatically set, meaning disputes trigger the reward to be automatically refunded to * the requesting contract. * * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. */ function setEventBased( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external virtual; /** * @notice Sets which callbacks should be enabled for the request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param callbackOnPriceProposed whether to enable the callback onPriceProposed. * @param callbackOnPriceDisputed whether to enable the callback onPriceDisputed. * @param callbackOnPriceSettled whether to enable the callback onPriceSettled. */ function setCallbacks( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, bool callbackOnPriceProposed, bool callbackOnPriceDisputed, bool callbackOnPriceSettled ) external virtual; /** * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come * from this proposal. However, any bonds are pulled from the caller. * @param proposer address to set as the proposer. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param proposedPrice price being proposed. * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to * the proposer once settled if the proposal is correct. */ function proposePriceFor( address proposer, address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, int256 proposedPrice ) public virtual returns (uint256 totalBond); /** * @notice Proposes a price value for an existing price request. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @param proposedPrice price being proposed. * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to * the proposer once settled if the proposal is correct. */ function proposePrice( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, int256 proposedPrice ) external virtual returns (uint256 totalBond); /** * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will * receive any rewards that come from this dispute. However, any bonds are pulled from the caller. * @param disputer address to set as the disputer. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to * the disputer once settled if the dispute was value (the proposal was incorrect). */ function disputePriceFor( address disputer, address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public virtual returns (uint256 totalBond); /** * @notice Disputes a price value for an existing price request with an active proposal. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to * the disputer once settled if the dispute was valid (the proposal was incorrect). */ function disputePrice( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external virtual returns (uint256 totalBond); /** * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled * or settleable. Note: this method is not view so that this call may actually settle the price request if it * hasn't been settled. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return resolved price. */ function settleAndGetPrice( bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external virtual returns (int256); /** * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes * the returned bonds as well as additional rewards. */ function settle( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) external virtual returns (uint256 payout); /** * @notice Gets the current data structure containing all information about a price request. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return the Request data structure. */ function getRequest( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public view virtual returns (Request memory); /** * @notice Returns the state of a price request. * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return the State enum value. */ function getState( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public view virtual returns (State); /** * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price). * @param requester sender of the initial price request. * @param identifier price identifier to identify the existing request. * @param timestamp timestamp to identify the existing request. * @param ancillaryData ancillary data of the price being requested. * @return true if price has resolved or settled, false otherwise. */ function hasPrice( address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData ) public view virtual returns (bool); function stampAncillaryData(bytes memory ancillaryData, address requester) public view virtual returns (bytes memory); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; /** * @title Financial contract facing Oracle interface. * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface. */ abstract contract OracleAncillaryInterface { /** * @notice Enqueues a request (if a request isn't already present) for the given `identifier`, `time` pair. * @dev Time must be in the past and the identifier must be supported. * @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested. * @param ancillaryData arbitrary data appended to a price request to give the voters more info from the caller. * @param time unix timestamp for the price request. */ function requestPrice( bytes32 identifier, uint256 time, bytes memory ancillaryData ) public virtual; /** * @notice Whether the price for `identifier` and `time` is available. * @dev Time must be in the past and the identifier must be supported. * @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested. * @param time unix timestamp for the price request. * @param ancillaryData arbitrary data appended to a price request to give the voters more info from the caller. * @return bool if the DVM has resolved to a price for the given identifier and timestamp. */ function hasPrice( bytes32 identifier, uint256 time, bytes memory ancillaryData ) public view virtual returns (bool); /** * @notice Gets the price for `identifier` and `time` if it has already been requested and resolved. * @dev If the price is not available, the method reverts. * @param identifier uniquely identifies the price requested. eg BTC/USD (encoded as bytes32) could be requested. * @param time unix timestamp for the price request. * @param ancillaryData arbitrary data appended to a price request to give the voters more info from the caller. * @return int256 representing the resolved price for the given identifier and timestamp. */ function getPrice( bytes32 identifier, uint256 time, bytes memory ancillaryData ) public view virtual returns (int256); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../common/implementation/FixedPoint.sol"; /** * @title Interface that allows financial contracts to pay oracle fees for their use of the system. */ interface StoreInterface { /** * @notice Pays Oracle fees in ETH to the store. * @dev To be used by contracts whose margin currency is ETH. */ function payOracleFees() external payable; /** * @notice Pays oracle fees in the margin currency, erc20Address, to the store. * @dev To be used if the margin currency is an ERC20 token rather than ETH. * @param erc20Address address of the ERC20 token used to pay the fee. * @param amount number of tokens to transfer. An approval for at least this amount must exist. */ function payOracleFeesErc20(address erc20Address, FixedPoint.Unsigned calldata amount) external; /** * @notice Computes the regular oracle fees that a contract should pay for a period. * @param startTime defines the beginning time from which the fee is paid. * @param endTime end time until which the fee is paid. * @param pfc "profit from corruption", or the maximum amount of margin currency that a * token sponsor could extract from the contract through corrupting the price feed in their favor. * @return regularFee amount owed for the duration from start to end time for the given pfc. * @return latePenalty for paying the fee after the deadline. */ function computeRegularFee( uint256 startTime, uint256 endTime, FixedPoint.Unsigned calldata pfc ) external view returns (FixedPoint.Unsigned memory regularFee, FixedPoint.Unsigned memory latePenalty); /** * @notice Computes the final oracle fees that a contract should pay at settlement. * @param currency token used to pay the final fee. * @return finalFee amount due. */ function computeFinalFee(address currency) external view returns (FixedPoint.Unsigned memory); }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"_liveness","type":"uint256"},{"internalType":"address","name":"_finderAddress","type":"address"},{"internalType":"address","name":"_timerAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":true,"internalType":"address","name":"disputer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"indexed":false,"internalType":"int256","name":"proposedPrice","type":"int256"}],"name":"DisputePrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"indexed":false,"internalType":"int256","name":"proposedPrice","type":"int256"},{"indexed":false,"internalType":"uint256","name":"expirationTimestamp","type":"uint256"},{"indexed":false,"internalType":"address","name":"currency","type":"address"}],"name":"ProposePrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"finalFee","type":"uint256"}],"name":"RequestPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":true,"internalType":"address","name":"disputer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"identifier","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"indexed":false,"internalType":"int256","name":"price","type":"int256"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"}],"name":"Settle","type":"event"},{"inputs":[],"name":"OO_ANCILLARY_DATA_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOO_EARLY_RESPONSE","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ancillaryBytesLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultLiveness","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"disputePrice","outputs":[{"internalType":"uint256","name":"totalBond","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"disputer","type":"address"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"disputePriceFor","outputs":[{"internalType":"uint256","name":"totalBond","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finder","outputs":[{"internalType":"contract FinderInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"getRequest","outputs":[{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"disputer","type":"address"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"bool","name":"settled","type":"bool"},{"components":[{"internalType":"bool","name":"eventBased","type":"bool"},{"internalType":"bool","name":"refundOnDispute","type":"bool"},{"internalType":"bool","name":"callbackOnPriceProposed","type":"bool"},{"internalType":"bool","name":"callbackOnPriceDisputed","type":"bool"},{"internalType":"bool","name":"callbackOnPriceSettled","type":"bool"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"uint256","name":"customLiveness","type":"uint256"}],"internalType":"struct OptimisticOracleV2Interface.RequestSettings","name":"requestSettings","type":"tuple"},{"internalType":"int256","name":"proposedPrice","type":"int256"},{"internalType":"int256","name":"resolvedPrice","type":"int256"},{"internalType":"uint256","name":"expirationTime","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"finalFee","type":"uint256"}],"internalType":"struct OptimisticOracleV2Interface.Request","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"getState","outputs":[{"internalType":"enum OptimisticOracleV2Interface.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"hasPrice","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"int256","name":"proposedPrice","type":"int256"}],"name":"proposePrice","outputs":[{"internalType":"uint256","name":"totalBond","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"int256","name":"proposedPrice","type":"int256"}],"name":"proposePriceFor","outputs":[{"internalType":"uint256","name":"totalBond","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"}],"name":"requestPrice","outputs":[{"internalType":"uint256","name":"totalBond","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"requests","outputs":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"disputer","type":"address"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"bool","name":"settled","type":"bool"},{"components":[{"internalType":"bool","name":"eventBased","type":"bool"},{"internalType":"bool","name":"refundOnDispute","type":"bool"},{"internalType":"bool","name":"callbackOnPriceProposed","type":"bool"},{"internalType":"bool","name":"callbackOnPriceDisputed","type":"bool"},{"internalType":"bool","name":"callbackOnPriceSettled","type":"bool"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"uint256","name":"customLiveness","type":"uint256"}],"internalType":"struct OptimisticOracleV2Interface.RequestSettings","name":"requestSettings","type":"tuple"},{"internalType":"int256","name":"proposedPrice","type":"int256"},{"internalType":"int256","name":"resolvedPrice","type":"int256"},{"internalType":"uint256","name":"expirationTime","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"finalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"uint256","name":"bond","type":"uint256"}],"name":"setBond","outputs":[{"internalType":"uint256","name":"totalBond","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"bool","name":"callbackOnPriceProposed","type":"bool"},{"internalType":"bool","name":"callbackOnPriceDisputed","type":"bool"},{"internalType":"bool","name":"callbackOnPriceSettled","type":"bool"}],"name":"setCallbacks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"name":"setCurrentTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"uint256","name":"customLiveness","type":"uint256"}],"name":"setCustomLiveness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"setEventBased","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"setRefundOnDispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"settle","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"settleAndGetPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"address","name":"requester","type":"address"}],"name":"stampAncillaryData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"timerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200437738038062004377833981016040819052620000349162000149565b60018054600160a01b6001600160a01b038481166001600160a81b03199093169290921717909155600280546001600160a01b0319169184169190911790556200007e8362000089565b50506003556200018a565b63bb7448008110620000d75760405162461bcd60e51b81526020600482015260126024820152714c6976656e65737320746f6f206c6172676560701b60448201526064015b60405180910390fd5b60008111620001295760405162461bcd60e51b815260206004820152601460248201527f4c6976656e6573732063616e6e6f7420626520300000000000000000000000006044820152606401620000ce565b50565b80516001600160a01b03811681146200014457600080fd5b919050565b6000806000606084860312156200015f57600080fd5b8351925062000171602085016200012c565b915062000181604085016200012c565b90509250925092565b6141dd806200019a6000396000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80639d866985116100ee578063ba4b930c11610097578063f327b07511610071578063f327b0751461049f578063fba7f1e3146104b2578063fe4e1983146104c5578063ff8c1a8c146104ce57600080fd5b8063ba4b930c14610453578063bc58ccaa14610473578063c371dda71461049657600080fd5b8063af5d2f39116100c8578063af5d2f3914610400578063b8b4f90814610420578063b9a3c84c1461043357600080fd5b80639d866985146102bd578063a9904f9b146103cd578063ad5a755a146103ed57600080fd5b80634ccb56f51161015057806376c7823f1161012a57806376c7823f146102845780637c82288f1461029757806391f58dcb146102aa57600080fd5b80634ccb56f51461025657806353b592391461025e5780635e9a79a91461027157600080fd5b806322f8e5661161018157806322f8e5661461022857806329cb924d1461023b578063473c45fe1461024357600080fd5b806311df92f1146101a8578063120698af146101ce5780631c39c38d146101e3575b600080fd5b6101bb6101b63660046136d6565b6104f5565b6040519081526020015b60405180910390f35b6101e16101dc366004613741565b610d2a565b005b6001546102039073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c5565b6101e1610236366004613791565b610e6c565b6101bb610f15565b6101e16102513660046137aa565b610f24565b6101bb611043565b6101bb61026c366004613741565b611053565b6101bb61027f366004613802565b611119565b6101bb610292366004613865565b6111aa565b6101bb6102a53660046138db565b61176f565b6101e16102b8366004613741565b611bed565b6103b76102cb366004613791565b60006020818152918152604090819020805460018201546002830154845160e081018652600385015460ff8082161515835261010082048116151598830198909852620100008104881615159682019690965263010000008604871615156060820152640100000000909504861615156080860152600484015460a0860152600584015460c08601526006840154600785015460088601546009870154600a9097015473ffffffffffffffffffffffffffffffffffffffff968716999587169896851697740100000000000000000000000000000000000000009095049095169594929391929091908a565b6040516101c59a99989796959493929190613959565b6103e06103db366004613802565b611d30565b6040516101c59190613a16565b6101bb6103fb3660046137aa565b611f01565b61041361040e366004613b33565b61202d565b6040516101c59190613bfb565b6101bb61042e366004613c0e565b612042565b6002546102039073ffffffffffffffffffffffffffffffffffffffff1681565b610466610461366004613802565b612052565b6040516101c59190613ca8565b610486610481366004613802565b612068565b60405190151581526020016101c5565b6101bb61200081565b6101e16104ad366004613cf7565b6120d8565b6101bb6104c0366004613802565b612276565b6101bb60035481565b6101bb7f800000000000000000000000000000000000000000000000000000000000000081565b60006104ff612285565b61052c600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600061053a3388888861230b565b600681111561054b5761054b613c79565b146105b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f7265717565737450726963653a20496e76616c6964000000000000000000000060448201526064015b60405180910390fd5b6105bf61249c565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b876040518263ffffffff1660e01b81526004016105f991815260200190565b60206040518083038186803b15801561061157600080fd5b505afa158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190613d80565b6106af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e737570706f72746564206964656e7469666965720000000000000000000060448201526064016105ae565b6106b761255f565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301529190911690633a3ab6729060240160206040518083038186803b15801561072057600080fd5b505afa158015610734573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107589190613d80565b6107be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e737570706f727465642063757272656e637900000000000000000000000060448201526064016105ae565b6107c6610f15565b85111561082f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f54696d657374616d7020696e206675747572650000000000000000000000000060448201526064016105ae565b61083c6035612000613dcc565b845111156108a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f416e63696c6c617279204461746120746f6f206c6f6e6700000000000000000060448201526064016105ae565b60006108b06125d6565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529190911690635b97aadd9060240160206040518083038186803b15801561091957600080fd5b505afa15801561092d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109519190613de3565b600001519050604051806101400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020016000151581526020016040518060e001604052806000151581526020016000151581526020016000151581526020016000151581526020016000151581526020018481526020016000815250815260200160008152602001600081526020016000815260200184815260200182815250600080610a38338b8b8b61264d565b81526020808201929092526040908101600020835181547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff9283161783558585015160018401805490921690831617905584830151600283018054606080890151939094167fffffffffffffffffffffff0000000000000000000000000000000000000000009091161774010000000000000000000000000000000000000000921515929092029190911790556080808601518051600385018054978301519683015194830151938301517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009098169115157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16919091176101009615158702177fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff1662010000941515949094027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1693909317630100000092151592909202919091177fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff166401000000009515159590950294909417905560a080840151600483015560c0938401516005830155840151600682015591830151600783015560e08301516008830155820151600982015561012090910151600a909101558215610c7757610c7773ffffffffffffffffffffffffffffffffffffffff8516333086612686565b3373ffffffffffffffffffffffffffffffffffffffff167ff1679315ff325c257a944e0ca1bfe7b26616039e9511f9610d4ba3eca851027b888888888887604051610cc796959493929190613e25565b60405180910390a2610cda816002612762565b915050610d21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b95945050505050565b610d32612285565b610d5f600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6001610d6d3385858561230b565b6006811115610d7e57610d7e613c79565b14610de5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7365744576656e7442617365643a20526571756573746564000000000000000060448201526064016105ae565b6000610df33385858561276e565b60030180546101017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090911617905550610e67600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff16610e8e57600080fd5b6001546040517f22f8e5660000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906322f8e56690602401600060405180830381600087803b158015610efa57600080fd5b505af1158015610f0e573d6000803e3d6000fd5b5050505050565b6000610f1f612797565b905090565b610f2c612285565b610f59600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6001610f673386868661230b565b6006811115610f7857610f78613c79565b14610fdf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f736574437573746f6d4c6976656e6573733a205265717565737465640000000060448201526064016105ae565b610fe88161285d565b80610ff53386868661276e565b6005015561103d600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b50505050565b6110506035612000613dcc565b81565b600061105d612285565b61108a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60066110983386868661230b565b60068111156110a9576110a9613c79565b146110bc576110ba33858585612937565b505b6110c83385858561276e565b600701549050611112600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b9392505050565b6000611123612285565b611150600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b61115c85858585612937565b90506111a2600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b949350505050565b60006111b4612285565b6111e1600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff861661125e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f64697370757465722061646472657373206d757374206265206e6f6e2030000060448201526064016105ae565b600261126c8686868661230b565b600681111561127d5761127d613c79565b146112e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f646973707574655072696365466f723a2050726f706f7365640000000000000060448201526064016105ae565b60006112f28686868661276e565b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a16179055600a81015460048201549192509061134c8183612d96565b9350831561137b57600283015461137b9073ffffffffffffffffffffffffffffffffffffffff16333087612686565b60006113856125d6565b9050600061139c61139586612da2565b8590612d96565b9050801561146c5760028501546113ca9073ffffffffffffffffffffffffffffffffffffffff168383612db5565b6113d26125d6565b60028601546040805160208101825284815290517f8659d23200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff928316600482015290516024820152911690638659d23290604401600060405180830381600087803b15801561145357600080fd5b505af1158015611467573d6000803e3d6000fd5b505050505b611474612ec2565b73ffffffffffffffffffffffffffffffffffffffff1663216666a48a61149a888c612f39565b6114a48b8f612f84565b6040518463ffffffff1660e01b81526004016114c293929190613e78565b600060405180830381600087803b1580156114dc57600080fd5b505af11580156114f0573d6000803e3d6000fd5b50505050600080866009015411801561151257506003860154610100900460ff165b156115495750600985018054600090915560028601546115499073ffffffffffffffffffffffffffffffffffffffff168c83612fc6565b8b73ffffffffffffffffffffffffffffffffffffffff168660000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff167f5165909c3d1c01c5d1e121ac6f6d01dda1ba24bc9e1f975b5a375339c15be7f38d8d8d8c600601546040516115eb9493929190613e97565b60405180910390a4611637600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b73ffffffffffffffffffffffffffffffffffffffff8b163b15158015611668575060038601546301000000900460ff165b156116f8576040517f0d8f237200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c1690630d8f2372906116c5908d908d908d908790600401613e97565b600060405180830381600087803b1580156116df57600080fd5b505af11580156116f3573d6000803e3d6000fd5b505050505b611725600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b505050505050610d21600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6000611779612285565b6117a6600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b73ffffffffffffffffffffffffffffffffffffffff8716611823576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f70726f706f7365722061646472657373206d757374206265206e6f6e2030000060448201526064016105ae565b60016118318787878761230b565b600681111561184257611842613c79565b146118a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f70726f706f73655072696365466f723a2052657175657374656400000000000060448201526064016105ae565b60006118b78787878761276e565b600381015490915060ff1615611951577f8000000000000000000000000000000000000000000000000000000000000000831415611951576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742070726f706f73652027746f6f206561726c792700000000000060448201526064016105ae565b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff89161781556006810183905560058101546119bf906119ab576003546119b1565b60058201545b6119b9610f15565b90612d96565b6008820155600a81015460048201546119d791612d96565b91508115611a06576002810154611a069073ffffffffffffffffffffffffffffffffffffffff16333085612686565b6008810154600282015460405173ffffffffffffffffffffffffffffffffffffffff8b8116938b8216937f6e51dd00371aabffa82cd401592f76ed51e98a9ea4b58751c70463a2c78b5ca193611a67938d938d938d938d9390911690613ec7565b60405180910390a3611ab3600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b73ffffffffffffffffffffffffffffffffffffffff87163b15158015611ae35750600381015462010000900460ff165b15611b71576040517f9c2fd1df00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff881690639c2fd1df90611b3e90899089908990600401613e78565b600060405180830381600087803b158015611b5857600080fd5b505af1158015611b6c573d6000803e3d6000fd5b505050505b611b9e600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b50611be3600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b9695505050505050565b611bf5612285565b611c22600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6001611c303385858561230b565b6006811115611c4157611c41613c79565b14611ca8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f736574526566756e644f6e446973707574653a2052657175657374656400000060448201526064016105ae565b6001611cb63385858561276e565b6003018054911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909216919091179055610e67600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b611dbc6040805161014081018252600080825260208083018290528284018290526060808401839052845160e081018652838152918201839052938101829052928301819052608083810182905260a0840182905260c0840191909152909190820190815260200160008152602001600081526020016000815260200160008152602001600081525090565b611dc4612285565b611dd08585858561276e565b6040805161014081018252825473ffffffffffffffffffffffffffffffffffffffff90811682526001840154811660208084019190915260028501549182168385015260ff7401000000000000000000000000000000000000000090920482161515606080850191909152845160e08082018752600388015480861615158352610100808204871615159584019590955262010000810486161515978301979097526301000000870485161515928201929092526401000000009095049092161515608085810191909152600486015460a080870191909152600587015460c08088019190915291850195909552600686015494840194909452600785015493830193909352600884015490820152600983015491810191909152600a909101546101208201529050949350505050565b6000611f0b612285565b611f38600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b6001611f463387878761230b565b6006811115611f5757611f57613c79565b14611fbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f736574426f6e643a20526571756573746564000000000000000000000000000060448201526064016105ae565b6000611fcc3387878761276e565b60048101849055600a810154909150611fe6908490612d96565b9150506111a2600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60606120398383612f84565b90505b92915050565b6000611be333878787878761176f565b600061205c612285565b610d218585858561230b565b6000612072612285565b60006120808686868661230b565b9050600681600681111561209657612096613c79565b14806120b3575060058160068111156120b1576120b1613c79565b145b80611be3575060038160068111156120cd576120cd613c79565b149695505050505050565b6120e0612285565b61210d600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b600161211b3388888861230b565b600681111561212c5761212c613c79565b14612193576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f73657443616c6c6261636b733a2052657175657374656400000000000000000060448201526064016105ae565b60006121a13388888861276e565b60030180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff1662010000861515027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1617630100000085151502177fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff16640100000000841515021790555060018054740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909116179055505050505050565b6000610d2133868686866111aa565b60015474010000000000000000000000000000000000000000900460ff16612309576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105ae565b565b60008061231a8686868661276e565b600281015490915073ffffffffffffffffffffffffffffffffffffffff166123465760009150506111a2565b805473ffffffffffffffffffffffffffffffffffffffff1661236c5760019150506111a2565b600281015474010000000000000000000000000000000000000000900460ff161561239b5760069150506111a2565b600181015473ffffffffffffffffffffffffffffffffffffffff166123df576123c2610f15565b816008015411156123d45760026123d7565b60035b9150506111a2565b6123e7612ec2565b73ffffffffffffffffffffffffffffffffffffffff1663b551cd508661240d8488612f39565b612417878b612f84565b6040518463ffffffff1660e01b815260040161243593929190613e78565b60206040518083038186803b15801561244d57600080fd5b505afa158015612461573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124859190613d80565b612490576004611be3565b50600595945050505050565b6002546040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4964656e74696669657257686974656c69737400000000000000000000000000600482015260009173ffffffffffffffffffffffffffffffffffffffff169063aafd5e40906024015b60206040518083038186803b15801561252757600080fd5b505afa15801561253b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1f9190613f1a565b6002546040517faafd5e400000000000000000000000000000000000000000000000000000000081527f436f6c6c61746572616c57686974656c69737400000000000000000000000000600482015260009173ffffffffffffffffffffffffffffffffffffffff169063aafd5e409060240161250f565b6002546040517faafd5e400000000000000000000000000000000000000000000000000000000081527f53746f7265000000000000000000000000000000000000000000000000000000600482015260009173ffffffffffffffffffffffffffffffffffffffff169063aafd5e409060240161250f565b6000848484846040516020016126669493929190613f37565b604051602081830303815290604052805190602001209050949350505050565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261103d9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261301c565b60006120398284613f90565b600080600061277f8787878761264d565b81526020019081526020016000209050949350505050565b60015460009073ffffffffffffffffffffffffffffffffffffffff161561285857600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166329cb924d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561282057600080fd5b505afa158015612834573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1f9190613fcd565b504290565b63bb74480081106128ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4c6976656e65737320746f6f206c61726765000000000000000000000000000060448201526064016105ae565b60008111612934576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4c6976656e6573732063616e6e6f74206265203000000000000000000000000060448201526064016105ae565b50565b6000806129468686868661230b565b905060006129568787878761276e565b6002810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055905060038260068111156129ad576129ad613c79565b1415612a0e57600681015460078201556009810154600a82015460048301546129db92916119b99190612d96565b81546002830154919450612a099173ffffffffffffffffffffffffffffffffffffffff908116911685612fc6565b612bec565b6005826006811115612a2257612a22613c79565b1415612b8a57612a30612ec2565b73ffffffffffffffffffffffffffffffffffffffff1663719c6d5687612a568489612f39565b612a60888c612f84565b6040518463ffffffff1660e01b8152600401612a7e93929190613e78565b60206040518083038186803b158015612a9657600080fd5b505afa158015612aaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ace9190613fcd565b6007820181905560068201546004830154911415906000612af8612af185612da2565b8390613128565b9050612b1d84600901546119b986600a01546119b98587612d9690919063ffffffff16565b9550612b8283612b4457845473ffffffffffffffffffffffffffffffffffffffff16612b60565b600185015473ffffffffffffffffffffffffffffffffffffffff165b600286015473ffffffffffffffffffffffffffffffffffffffff169088612fc6565b505050612bec565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5f736574746c653a206e6f7420736574746c6561626c6500000000000000000060448201526064016105ae565b60018101548154600783015460405173ffffffffffffffffffffffffffffffffffffffff93841693928316928b16917f3f384afb4bd9f0aef0298c80399950011420eb33b0e1a750b20966270247b9a091612c4e918c918c918c918c90613fe6565b60405180910390a4612c9a600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b73ffffffffffffffffffffffffffffffffffffffff87163b15158015612ccc57506003810154640100000000900460ff165b15612d5f5760078101546040517f04cc1fd500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8916916304cc1fd591612d2c918a918a918a91600401613e97565b600060405180830381600087803b158015612d4657600080fd5b505af1158015612d5a573d6000803e3d6000fd5b505050505b612d8c600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b5050949350505050565b60006120398284614019565b600481015460009061203c906002613134565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b158015612e2757600080fd5b505afa158015612e3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5f9190613fcd565b612e699190614019565b60405173ffffffffffffffffffffffffffffffffffffffff851660248201526044810182905290915061103d9085907f095ea7b300000000000000000000000000000000000000000000000000000000906064016126e0565b6002546040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4f7261636c650000000000000000000000000000000000000000000000000000600482015260009173ffffffffffffffffffffffffffffffffffffffff169063aafd5e409060240161250f565b600382015460009060ff1615612f7d576005830154600090612f5d57600354612f63565b60058401545b6008850154909150612f759082613128565b91505061203c565b508061203c565b6060612039836040518060400160405280600b81526020017f6f6f52657175657374657200000000000000000000000000000000000000000081525084613140565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610e679084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016126e0565b600061307e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166131869092919063ffffffff16565b805190915015610e67578080602001905181019061309c9190613d80565b610e67576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016105ae565b60006120398284613dcc565b60006120398284614060565b6060600061314e8585613195565b9050848161315b856131d7565b60405160200161316d9392919061409b565b6040516020818303038152906040529150509392505050565b60606111a28484600085613265565b8151606090156131c657816040516020016131b091906140de565b604051602081830303815290604052905061203c565b816040516020016131b0919061414a565b60606131f86fffffffffffffffffffffffffffffffff602084901c166133e5565b6132138360601b6bffffffffffffffffffffffff19166133e5565b60405160200161324f9291909182527fffffffffffffffff00000000000000000000000000000000000000000000000016602082015260280190565b6040516020818303038152906040529050919050565b6060824710156132f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016105ae565b843b61335f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ae565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613388919061418b565b60006040518083038185875af1925050503d80600081146133c5576040519150601f19603f3d011682016040523d82523d6000602084013e6133ca565b606091505b50915091506133da828286613587565b979650505050505050565b6000808260001c9050806fffffffffffffffffffffffffffffffff169050806801000000000000000002811777ffffffffffffffff0000000000000000ffffffffffffffff169050806401000000000281177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16905080620100000281177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff169050806101000281177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff1690508060100281177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16905060006008827f0808080808080808080808080808080808080808080808080808080808080808168161350957613509614031565b0460047f040404040404040404040404040404040404040404040404040404040404040484160460027f020202020202020202020202020202020202020202020202020202020202020285160417166027029091017f3030303030303030303030303030303030303030303030303030303030303030019392505050565b60608315613596575081611112565b8251156135a65782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae9190613bfb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261361a57600080fd5b813567ffffffffffffffff80821115613635576136356135da565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561367b5761367b6135da565b8160405283815286602085880101111561369457600080fd5b836020870160208301376000602085830101528094505050505092915050565b73ffffffffffffffffffffffffffffffffffffffff8116811461293457600080fd5b600080600080600060a086880312156136ee57600080fd5b8535945060208601359350604086013567ffffffffffffffff81111561371357600080fd5b61371f88828901613609565b9350506060860135613730816136b4565b949793965091946080013592915050565b60008060006060848603121561375657600080fd5b8335925060208401359150604084013567ffffffffffffffff81111561377b57600080fd5b61378786828701613609565b9150509250925092565b6000602082840312156137a357600080fd5b5035919050565b600080600080608085870312156137c057600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156137e557600080fd5b6137f187828801613609565b949793965093946060013593505050565b6000806000806080858703121561381857600080fd5b8435613823816136b4565b93506020850135925060408501359150606085013567ffffffffffffffff81111561384d57600080fd5b61385987828801613609565b91505092959194509250565b600080600080600060a0868803121561387d57600080fd5b8535613888816136b4565b94506020860135613898816136b4565b93506040860135925060608601359150608086013567ffffffffffffffff8111156138c257600080fd5b6138ce88828901613609565b9150509295509295909350565b60008060008060008060c087890312156138f457600080fd5b86356138ff816136b4565b9550602087013561390f816136b4565b94506040870135935060608701359250608087013567ffffffffffffffff81111561393957600080fd5b61394589828a01613609565b92505060a087013590509295509295509295565b73ffffffffffffffffffffffffffffffffffffffff8b811682528a8116602083015289166040820152871515606082015261020081016139e5608083018980511515825260208101511515602083015260408101511515604083015260608101511515606083015260808101511515608083015260a081015160a083015260c081015160c08301525050565b6101608201969096526101808101949094526101a08401929092526101c08301526101e09091015295945050505050565b815173ffffffffffffffffffffffffffffffffffffffff16815261020081016020830151613a5c602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151613a84604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151613a98606084018215159052565b506080830151613af4608084018280511515825260208101511515602083015260408101511515604083015260608101511515606083015260808101511515608083015260a081015160a083015260c081015160c08301525050565b5060a083015161016083015260c083015161018083015260e08301516101a08301526101008301516101c0830152610120909201516101e09091015290565b60008060408385031215613b4657600080fd5b823567ffffffffffffffff811115613b5d57600080fd5b613b6985828601613609565b9250506020830135613b7a816136b4565b809150509250929050565b60005b83811015613ba0578181015183820152602001613b88565b8381111561103d5750506000910152565b60008151808452613bc9816020860160208601613b85565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006120396020830184613bb1565b600080600080600060a08688031215613c2657600080fd5b8535613c31816136b4565b94506020860135935060408601359250606086013567ffffffffffffffff811115613c5b57600080fd5b613c6788828901613609565b95989497509295608001359392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160078310613ce3577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b801515811461293457600080fd5b60008060008060008060c08789031215613d1057600080fd5b8635955060208701359450604087013567ffffffffffffffff811115613d3557600080fd5b613d4189828a01613609565b9450506060870135613d5281613ce9565b92506080870135613d6281613ce9565b915060a0870135613d7281613ce9565b809150509295509295509295565b600060208284031215613d9257600080fd5b815161111281613ce9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613dde57613dde613d9d565b500390565b600060208284031215613df557600080fd5b6040516020810181811067ffffffffffffffff82111715613e1857613e186135da565b6040529151825250919050565b86815285602082015260c060408201526000613e4460c0830187613bb1565b73ffffffffffffffffffffffffffffffffffffffff95909516606083015250608081019290925260a0909101529392505050565b838152826020820152606060408201526000610d216060830184613bb1565b848152836020820152608060408201526000613eb66080830185613bb1565b905082606083015295945050505050565b86815285602082015260c060408201526000613ee660c0830187613bb1565b606083019590955250608081019290925273ffffffffffffffffffffffffffffffffffffffff1660a0909101529392505050565b600060208284031215613f2c57600080fd5b8151611112816136b4565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b16815283601482015282603482015260008251613f80816054850160208701613b85565b9190910160540195945050505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613fc857613fc8613d9d565b500290565b600060208284031215613fdf57600080fd5b5051919050565b85815284602082015260a06040820152600061400560a0830186613bb1565b606083019490945250608001529392505050565b6000821982111561402c5761402c613d9d565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614096577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600084516140ad818460208901613b85565b8451908301906140c1818360208901613b85565b84519101906140d4818360208801613b85565b0195945050505050565b7f2c00000000000000000000000000000000000000000000000000000000000000815260008251614116816001850160208701613b85565b7f3a000000000000000000000000000000000000000000000000000000000000006001939091019283015250600201919050565b6000825161415c818460208701613b85565b7f3a00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b6000825161419d818460208701613b85565b919091019291505056fea264697066735822122076d9eb32bfdac668f344370ae32c96fb5078d448618c354883822990883f26cb64736f6c634300080900330000000000000000000000000000000000000000000000000000000000001c2000000000000000000000000009aea4b2242abc8bb4bb78d537a67a245a7bec640000000000000000000000000000000000000000000000000000000000000000
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.