Contract 0x22A9AaAC9c3184f68C7B7C95b1300C4B1D2fB95C 5

Txn Hash Method
Block
From
To
Value [Txn Fee]
0xfd034135f83dacd7fffeb1b4f089fa1892e1a5fbbb885b9d448e5eeb024d69d1Sync Uma Params294906852023-08-16 14:38:20225 days 20 hrs ago0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d IN  0x22a9aaac9c3184f68c7b7c95b1300c4b1d2fb95c0 xDAI0.000311454
0xcda79f415a0e57c3b884b9b29120a01421fea58b9ec1d455aa67fbbdb2d9f557Sync Uma Params294906842023-08-16 14:38:10225 days 20 hrs ago0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d IN  0x22a9aaac9c3184f68c7b7c95b1300c4b1d2fb95c0 xDAI0.000200454
0x2cfc1797ba6754bb50159b64a735213cb24817a5ff37601c1d2d764a6e57a771Sync Uma Params294906812023-08-16 14:37:55225 days 20 hrs ago0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d IN  0x22a9aaac9c3184f68c7b7c95b1300c4b1d2fb95c0 xDAI0.000311454
0x7f5f26fc29160708c05187e8d27e7b6bec3e6cc53b0a468a7678f2a6fbc22504Sync Uma Params294906802023-08-16 14:37:45225 days 20 hrs ago0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d IN  0x22a9aaac9c3184f68c7b7c95b1300c4b1d2fb95c0 xDAI0.000311454
0x0ba54d3de32ea3de7626144882d24e916a55b126cd0f8345a03d36132a8b70b8Sync Uma Params271022402023-03-24 17:00:35370 days 18 hrs ago0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d IN  0x22a9aaac9c3184f68c7b7c95b1300c4b1d2fb95c0 xDAI0.000086718
0xc7cb72b5564f373853b9ad54a9e30fd2b3653426bab427492958a10ede7e6a770x60a06040270871502023-03-23 18:32:40371 days 16 hrs ago0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d IN  Create: OptimisticOracleV30 xDAI0.008237728
[ Download CSV Export 
View more zero value Internal Transactions in Advanced View mode
Index Block
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
OptimisticOracleV3

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 22 : Ownable.sol
// 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);
    }
}

File 2 of 22 : IERC20.sol
// 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);
}

File 3 of 22 : SafeERC20.sol
// 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");
        }
    }
}

File 4 of 22 : Address.sol
// 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);
            }
        }
    }
}

File 5 of 22 : Context.sol
// 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;
    }
}

File 6 of 22 : SafeMath.sol
// 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;
        }
    }
}

File 7 of 22 : SignedSafeMath.sol
// 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;
    }
}

File 8 of 22 : AddressWhitelist.sol
// 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++;
            }
        }
    }
}

File 9 of 22 : AncillaryData.sol
// 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, ":");
        }
    }
}

File 10 of 22 : FixedPoint.sol
// 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);
        }
    }
}

File 11 of 22 : Lockable.sol
// 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;
    }
}

File 12 of 22 : MultiCaller.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

// This contract is taken from Uniswap's multi call implementation (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/base/Multicall.sol)
// and was modified to be solidity 0.8 compatible. Additionally, the method was restricted to only work with msg.value
// set to 0 to avoid any nasty attack vectors on function calls that use value sent with deposits.

/// @title MultiCaller
/// @notice Enables calling multiple methods in a single call to the contract
contract MultiCaller {
    function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}

File 13 of 22 : AddressWhitelistInterface.sol
// 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);
}

File 14 of 22 : Constants.sol
// 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 OptimisticOracleV2 = "OptimisticOracleV2";
    bytes32 public constant OptimisticOracleV3 = "OptimisticOracleV3";
    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;
}

File 15 of 22 : FinderInterface.sol
// 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);
}

File 16 of 22 : IdentifierWhitelistInterface.sol
// 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);
}

File 17 of 22 : OracleAncillaryInterface.sol
// 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);
}

File 18 of 22 : StoreInterface.sol
// 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);
}

File 19 of 22 : OptimisticOracleV3.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "../interfaces/OptimisticOracleV3CallbackRecipientInterface.sol";
import "../interfaces/OptimisticOracleV3Interface.sol";
import "../interfaces/EscalationManagerInterface.sol";

import "../../data-verification-mechanism/implementation/Constants.sol";
import "../../data-verification-mechanism/interfaces/FinderInterface.sol";
import "../../data-verification-mechanism/interfaces/IdentifierWhitelistInterface.sol";
import "../../data-verification-mechanism/interfaces/OracleAncillaryInterface.sol";
import "../../data-verification-mechanism/interfaces/StoreInterface.sol";

import "../../common/implementation/AddressWhitelist.sol";
import "../../common/implementation/AncillaryData.sol";
import "../../common/implementation/Lockable.sol";
import "../../common/implementation/MultiCaller.sol";

/**
 * @title Optimistic Oracle V3.
 * @notice The OOv3 is used to assert truths about the world which are verified using an optimistic escalation game.
 * @dev Core idea: an asserter makes a statement about a truth, calling "assertTruth". If this statement is not
 * challenged, it is taken as the state of the world. If challenged, it is arbitrated using the UMA DVM, or if
 * configured, an escalation manager. Escalation managers enable integrations to define their own security properties and
 * tradeoffs, enabling the notion of "sovereign security".
 */

contract OptimisticOracleV3 is OptimisticOracleV3Interface, Lockable, Ownable, MultiCaller {
    using SafeERC20 for IERC20;

    FinderInterface public immutable finder; // Finder used to discover other UMA ecosystem contracts.

    // Cached UMA parameters.
    address public cachedOracle;
    mapping(address => WhitelistedCurrency) public cachedCurrencies;
    mapping(bytes32 => bool) public cachedIdentifiers;

    mapping(bytes32 => Assertion) public assertions; // All assertions made by the Optimistic Oracle V3.

    uint256 public burnedBondPercentage; // Percentage of the bond that is paid to the UMA store if the assertion is disputed.

    bytes32 public constant defaultIdentifier = "ASSERT_TRUTH";
    int256 public constant numericalTrue = 1e18; // Numerical representation of true.
    IERC20 public defaultCurrency;
    uint64 public defaultLiveness;

    /**
     * @notice Construct the OptimisticOracleV3 contract.
     * @param _finder keeps track of all contracts within the UMA system based on their interfaceName.
     * @param _defaultCurrency the default currency to bond asserters in assertTruthWithDefaults.
     * @param _defaultLiveness the default liveness for assertions in assertTruthWithDefaults.
     */
    constructor(
        FinderInterface _finder,
        IERC20 _defaultCurrency,
        uint64 _defaultLiveness
    ) {
        finder = _finder;
        setAdminProperties(_defaultCurrency, _defaultLiveness, 0.5e18);
    }

    /**
     * @notice Sets the default currency, liveness, and burned bond percentage.
     * @dev Only callable by the contract owner (UMA governor).
     * @param _defaultCurrency the default currency to bond asserters in assertTruthWithDefaults.
     * @param _defaultLiveness the default liveness for assertions in assertTruthWithDefaults.
     * @param _burnedBondPercentage the percentage of the bond that is sent as fee to UMA Store contract on disputes.
     */
    function setAdminProperties(
        IERC20 _defaultCurrency,
        uint64 _defaultLiveness,
        uint256 _burnedBondPercentage
    ) public onlyOwner {
        require(_burnedBondPercentage <= 1e18, "Burned bond percentage > 100");
        require(_burnedBondPercentage > 0, "Burned bond percentage is 0");
        burnedBondPercentage = _burnedBondPercentage;
        defaultCurrency = _defaultCurrency;
        defaultLiveness = _defaultLiveness;
        syncUmaParams(defaultIdentifier, address(_defaultCurrency));

        emit AdminPropertiesSet(_defaultCurrency, _defaultLiveness, _burnedBondPercentage);
    }

    /**
     * @notice Asserts a truth about the world, using the default currency and liveness. No callback recipient or
     * escalation manager is enabled. The caller is expected to provide a bond of finalFee/burnedBondPercentage
     * (with burnedBondPercentage set to 50%, the bond is 2x final fee) of the default currency.
     * @dev The caller must approve this contract to spend at least the result of getMinimumBond(defaultCurrency).
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter account that receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @return assertionId unique identifier for this assertion.
     */

    function assertTruthWithDefaults(bytes calldata claim, address asserter) external returns (bytes32) {
        // Note: re-entrancy guard is done in the inner call.
        return
            assertTruth(
                claim,
                asserter, // asserter
                address(0), // callbackRecipient
                address(0), // escalationManager
                defaultLiveness,
                defaultCurrency,
                getMinimumBond(address(defaultCurrency)),
                defaultIdentifier,
                bytes32(0)
            );
    }

    /**
     * @notice Asserts a truth about the world, using a fully custom configuration.
     * @dev The caller must approve this contract to spend at least bond amount of currency.
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter account that receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @param callbackRecipient if configured, this address will receive a function call assertionResolvedCallback and
     * assertionDisputedCallback at resolution or dispute respectively. Enables dynamic responses to these events. The
     * recipient _must_ implement these callbacks and not revert or the assertion resolution will be blocked.
     * @param escalationManager if configured, this address will control escalation properties of the assertion. This
     * means a) choosing to arbitrate via the UMA DVM, b) choosing to discard assertions on dispute, or choosing to
     * validate disputes. Combining these, the asserter can define their own security properties for the assertion.
     * escalationManager also _must_ implement the same callbacks as callbackRecipient.
     * @param liveness time to wait before the assertion can be resolved. Assertion can be disputed in this time.
     * @param currency bond currency pulled from the caller and held in escrow until the assertion is resolved.
     * @param bond amount of currency to pull from the caller and hold in escrow until the assertion is resolved. This
     * must be >= getMinimumBond(address(currency)).
     * @param identifier UMA DVM identifier to use for price requests in the event of a dispute. Must be pre-approved.
     * @param domainId optional domain that can be used to relate this assertion to others in the escalationManager and
     * can be used by the configured escalationManager to define custom behavior for groups of assertions. This is
     * typically used for "escalation games" by changing bonds or other assertion properties based on the other
     * assertions that have come before. If not needed this value should be 0 to save gas.
     * @return assertionId unique identifier for this assertion.
     */
    function assertTruth(
        bytes memory claim,
        address asserter,
        address callbackRecipient,
        address escalationManager,
        uint64 liveness,
        IERC20 currency,
        uint256 bond,
        bytes32 identifier,
        bytes32 domainId
    ) public nonReentrant returns (bytes32 assertionId) {
        uint64 time = uint64(getCurrentTime());
        assertionId = _getId(claim, bond, time, liveness, currency, callbackRecipient, escalationManager, identifier);

        require(asserter != address(0), "Asserter cant be 0");
        require(assertions[assertionId].asserter == address(0), "Assertion already exists");
        require(_validateAndCacheIdentifier(identifier), "Unsupported identifier");
        require(_validateAndCacheCurrency(address(currency)), "Unsupported currency");
        require(bond >= getMinimumBond(address(currency)), "Bond amount too low");

        assertions[assertionId] = Assertion({
            escalationManagerSettings: EscalationManagerSettings({
                arbitrateViaEscalationManager: false, // Default behavior: use the DVM as an oracle.
                discardOracle: false, // Default behavior: respect the Oracle result.
                validateDisputers: false, // Default behavior: disputer will not be validated.
                escalationManager: escalationManager,
                assertingCaller: msg.sender
            }),
            asserter: asserter,
            disputer: address(0),
            callbackRecipient: callbackRecipient,
            currency: currency,
            domainId: domainId,
            identifier: identifier,
            bond: bond,
            settled: false,
            settlementResolution: false,
            assertionTime: time,
            expirationTime: time + liveness
        });

        {
            EscalationManagerInterface.AssertionPolicy memory assertionPolicy = _getAssertionPolicy(assertionId);
            require(!assertionPolicy.blockAssertion, "Assertion not allowed"); // Check if the assertion is permitted.
            EscalationManagerSettings storage emSettings = assertions[assertionId].escalationManagerSettings;
            (emSettings.arbitrateViaEscalationManager, emSettings.discardOracle, emSettings.validateDisputers) = (
                // Choose which oracle to arbitrate disputes via. If set to true then the escalation manager will
                // arbitrate disputes. Else, the DVM arbitrates disputes. This lets integrations "unplug" the DVM.
                assertionPolicy.arbitrateViaEscalationManager,
                // Choose whether to discard the Oracle result. If true then "throw away" the assertion. To get an
                // assertion to be true it must be re-asserted and not disputed.
                assertionPolicy.discardOracle,
                // Configures if the escalation manager should validate the disputer on assertions. This enables you
                // to construct setups such as whitelisted disputers.
                assertionPolicy.validateDisputers
            );
        }

        currency.safeTransferFrom(msg.sender, address(this), bond); // Pull the bond from the caller.

        emit AssertionMade(
            assertionId,
            domainId,
            claim,
            asserter,
            callbackRecipient,
            escalationManager,
            msg.sender,
            time + liveness,
            currency,
            bond,
            identifier
        );
    }

    /**
     * @notice Disputes an assertion. Depending on how the assertion was configured, this may either escalate to the UMA
     * DVM or the configured escalation manager for arbitration.
     * @dev The caller must approve this contract to spend at least bond amount of currency for the associated assertion.
     * @param assertionId unique identifier for the assertion to dispute.
     * @param disputer receives bonds back at settlement.
     */
    function disputeAssertion(bytes32 assertionId, address disputer) external nonReentrant {
        require(disputer != address(0), "Disputer can't be 0");
        Assertion storage assertion = assertions[assertionId];
        require(assertion.asserter != address(0), "Assertion does not exist");
        require(assertion.disputer == address(0), "Assertion already disputed");
        require(assertion.expirationTime > getCurrentTime(), "Assertion is expired");
        require(_isDisputeAllowed(assertionId), "Dispute not allowed");

        assertion.disputer = disputer;

        assertion.currency.safeTransferFrom(msg.sender, address(this), assertion.bond);

        _oracleRequestPrice(assertionId, assertion.identifier, assertion.assertionTime);

        _callbackOnAssertionDispute(assertionId);

        // Send resolve callback if dispute resolution is discarded
        if (assertion.escalationManagerSettings.discardOracle) _callbackOnAssertionResolve(assertionId, false);

        emit AssertionDisputed(assertionId, msg.sender, disputer);
    }

    /**
     * @notice Resolves an assertion. If the assertion has not been disputed, the assertion is resolved as true and the
     * asserter receives the bond. If the assertion has been disputed, the assertion is resolved depending on the oracle
     * result. Based on the result, the asserter or disputer receives the bond. If the assertion was disputed then an
     * amount of the bond is sent to the UMA Store as an oracle fee based on the burnedBondPercentage. The remainder of
     * the bond is returned to the asserter or disputer.
     * @param assertionId unique identifier for the assertion to resolve.
     */
    function settleAssertion(bytes32 assertionId) public nonReentrant {
        Assertion storage assertion = assertions[assertionId];
        require(assertion.asserter != address(0), "Assertion does not exist"); // Revert if assertion does not exist.
        require(!assertion.settled, "Assertion already settled"); // Revert if assertion already settled.
        assertion.settled = true;
        if (assertion.disputer == address(0)) {
            // No dispute, settle with the asserter
            require(assertion.expirationTime <= getCurrentTime(), "Assertion not expired"); // Revert if not expired.
            assertion.settlementResolution = true;
            assertion.currency.safeTransfer(assertion.asserter, assertion.bond);
            _callbackOnAssertionResolve(assertionId, true);

            emit AssertionSettled(assertionId, assertion.asserter, false, true, msg.sender);
        } else {
            // Dispute, settle with the disputer. Reverts if price not resolved.
            int256 resolvedPrice = _oracleGetPrice(assertionId, assertion.identifier, assertion.assertionTime);

            // If set to discard settlement resolution then false. Else, use oracle value to find resolution.
            if (assertion.escalationManagerSettings.discardOracle) assertion.settlementResolution = false;
            else assertion.settlementResolution = resolvedPrice == numericalTrue;

            address bondRecipient = resolvedPrice == numericalTrue ? assertion.asserter : assertion.disputer;

            // Calculate oracle fee and the remaining amount of bonds to send to the correct party (asserter or disputer).
            uint256 oracleFee = (burnedBondPercentage * assertion.bond) / 1e18;
            uint256 bondRecipientAmount = assertion.bond * 2 - oracleFee;

            // Pay out the oracle fee and remaining bonds to the correct party. Note: the oracle fee is sent to the
            // Store contract, even if the escalation manager is used to arbitrate disputes.
            assertion.currency.safeTransfer(address(_getStore()), oracleFee);
            assertion.currency.safeTransfer(bondRecipient, bondRecipientAmount);

            if (!assertion.escalationManagerSettings.discardOracle)
                _callbackOnAssertionResolve(assertionId, assertion.settlementResolution);

            emit AssertionSettled(assertionId, bondRecipient, true, assertion.settlementResolution, msg.sender);
        }
    }

    /**
     * @notice Settles an assertion and returns the resolution.
     * @param assertionId unique identifier for the assertion to resolve and return the resolution for.
     * @return resolution of the assertion.
     */
    function settleAndGetAssertionResult(bytes32 assertionId) external returns (bool) {
        // Note: re-entrancy guard is done in the inner settleAssertion call.
        if (!assertions[assertionId].settled) settleAssertion(assertionId);
        return getAssertionResult(assertionId);
    }

    /**
     * @notice Fetches information about a specific identifier & currency from the UMA contracts and stores a local copy
     * of the information within this contract. This is used to save gas when making assertions as we can avoid an
     * external call to the UMA contracts to fetch this.
     * @param identifier identifier to fetch information for and store locally.
     * @param currency currency to fetch information for and store locally.
     */
    function syncUmaParams(bytes32 identifier, address currency) public {
        cachedOracle = finder.getImplementationAddress(OracleInterfaces.Oracle);
        cachedIdentifiers[identifier] = _getIdentifierWhitelist().isIdentifierSupported(identifier);
        cachedCurrencies[currency].isWhitelisted = _getCollateralWhitelist().isOnWhitelist(currency);
        cachedCurrencies[currency].finalFee = _getStore().computeFinalFee(currency).rawValue;
    }

    /**
     * @notice Fetches information about a specific assertion and returns it.
     * @param assertionId unique identifier for the assertion to fetch information for.
     * @return assertion information about the assertion.
     */
    function getAssertion(bytes32 assertionId) external view returns (Assertion memory) {
        return assertions[assertionId];
    }

    /**
     * @notice Fetches the resolution of a specific assertion and returns it. If the assertion has not been settled then
     * this will revert. If the assertion was disputed and configured to discard the oracle resolution return false.
     * @param assertionId unique identifier for the assertion to fetch the resolution for.
     * @return resolution of the assertion.
     */
    function getAssertionResult(bytes32 assertionId) public view returns (bool) {
        Assertion memory assertion = assertions[assertionId];
        // Return early if not using answer from resolved dispute.
        if (assertion.disputer != address(0) && assertion.escalationManagerSettings.discardOracle) return false;
        require(assertion.settled, "Assertion not settled"); // Revert if assertion not settled.
        return assertion.settlementResolution;
    }

    /**
     * @notice Returns the current block timestamp.
     * @dev Can be overridden to control contract time.
     * @return current block timestamp.
     */
    function getCurrentTime() public view virtual returns (uint256) {
        return block.timestamp;
    }

    /**
     * @notice Appends information onto an assertionId to construct ancillary data used for dispute resolution.
     * @param assertionId unique identifier for the assertion to construct ancillary data for.
     * @return ancillaryData stamped assertion information.
     */
    function stampAssertion(bytes32 assertionId) public view returns (bytes memory) {
        return _stampAssertion(assertionId);
    }

    /**
     * @notice Returns the minimum bond amount required to make an assertion. This is calculated as the final fee of the
     * currency divided by the burnedBondPercentage. If burn percentage is 50% then the min bond is 2x the final fee.
     * @param currency currency to calculate the minimum bond for.
     * @return minimum bond amount.
     */
    function getMinimumBond(address currency) public view returns (uint256) {
        uint256 finalFee = cachedCurrencies[currency].finalFee;
        return (finalFee * 1e18) / burnedBondPercentage;
    }

    // Returns the unique identifier for this assertion. This identifier is used to identify the assertion.
    function _getId(
        bytes memory claim,
        uint256 bond,
        uint256 time,
        uint64 liveness,
        IERC20 currency,
        address callbackRecipient,
        address escalationManager,
        bytes32 identifier
    ) internal view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    claim,
                    bond,
                    time,
                    liveness,
                    currency,
                    callbackRecipient,
                    escalationManager,
                    identifier,
                    msg.sender
                )
            );
    }

    // Returns ancillary data for the Oracle request containing assertionId and asserter.
    function _stampAssertion(bytes32 assertionId) internal view returns (bytes memory) {
        return
            AncillaryData.appendKeyValueAddress(
                AncillaryData.appendKeyValueBytes32("", "assertionId", assertionId),
                "ooAsserter",
                assertions[assertionId].asserter
            );
    }

    // Returns the Address Whitelist contract to validate the currency.
    function _getCollateralWhitelist() internal view returns (AddressWhitelist) {
        return AddressWhitelist(finder.getImplementationAddress(OracleInterfaces.CollateralWhitelist));
    }

    // Returns the Identifier Whitelist contract to validate the identifier.
    function _getIdentifierWhitelist() internal view returns (IdentifierWhitelistInterface) {
        return IdentifierWhitelistInterface(finder.getImplementationAddress(OracleInterfaces.IdentifierWhitelist));
    }

    // Returns the Store contract to fetch the final fee.
    function _getStore() internal view returns (StoreInterface) {
        return StoreInterface(finder.getImplementationAddress(OracleInterfaces.Store));
    }

    // Returns the Oracle contract to use on dispute. This can be either UMA DVM or the escalation manager.
    function _getOracle(bytes32 assertionId) internal view returns (OracleAncillaryInterface) {
        if (assertions[assertionId].escalationManagerSettings.arbitrateViaEscalationManager)
            return OracleAncillaryInterface(_getEscalationManager(assertionId));
        return OracleAncillaryInterface(cachedOracle);
    }

    // Requests resolving dispute from the Oracle (UMA DVM or escalation manager).
    function _oracleRequestPrice(
        bytes32 assertionId,
        bytes32 identifier,
        uint256 time
    ) internal {
        _getOracle(assertionId).requestPrice(identifier, time, _stampAssertion(assertionId));
    }

    // Returns the resolved resolution from the Oracle (UMA DVM or escalation manager).
    function _oracleGetPrice(
        bytes32 assertionId,
        bytes32 identifier,
        uint256 time
    ) internal view returns (int256) {
        return _getOracle(assertionId).getPrice(identifier, time, _stampAssertion(assertionId));
    }

    // Returns the escalation manager address for the assertion.
    function _getEscalationManager(bytes32 assertionId) internal view returns (address) {
        return assertions[assertionId].escalationManagerSettings.escalationManager;
    }

    // Returns the assertion policy parameters from the escalation manager. If no escalation manager is set then return
    // default values.
    function _getAssertionPolicy(bytes32 assertionId)
        internal
        view
        returns (EscalationManagerInterface.AssertionPolicy memory)
    {
        address em = _getEscalationManager(assertionId);
        if (em == address(0)) return EscalationManagerInterface.AssertionPolicy(false, false, false, false);
        return EscalationManagerInterface(em).getAssertionPolicy(assertionId);
    }

    // Returns whether the dispute is allowed by the escalation manager. If no escalation manager is set or the
    // escalation manager is not configured to validate disputers then return true.
    function _isDisputeAllowed(bytes32 assertionId) internal view returns (bool) {
        if (!assertions[assertionId].escalationManagerSettings.validateDisputers) return true;
        address em = assertions[assertionId].escalationManagerSettings.escalationManager;
        if (em == address(0)) return true;
        return EscalationManagerInterface(em).isDisputeAllowed(assertionId, msg.sender);
    }

    // Validates if the identifier is whitelisted by first checking the cache. If not whitelisted in the cache then
    // checks it from the identifier whitelist contract and caches result.
    function _validateAndCacheIdentifier(bytes32 identifier) internal returns (bool) {
        if (cachedIdentifiers[identifier]) return true;
        cachedIdentifiers[identifier] = _getIdentifierWhitelist().isIdentifierSupported(identifier);
        return cachedIdentifiers[identifier];
    }

    // Validates if the currency is whitelisted by first checking the cache. If not whitelisted in the cache then
    // checks it from the collateral whitelist contract and caches whitelist status and final fee.
    function _validateAndCacheCurrency(address currency) internal returns (bool) {
        if (cachedCurrencies[currency].isWhitelisted) return true;
        cachedCurrencies[currency].isWhitelisted = _getCollateralWhitelist().isOnWhitelist(currency);
        cachedCurrencies[currency].finalFee = _getStore().computeFinalFee(currency).rawValue;
        return cachedCurrencies[currency].isWhitelisted;
    }

    // Sends assertion resolved callback to the callback recipient and escalation manager (if set).
    function _callbackOnAssertionResolve(bytes32 assertionId, bool assertedTruthfully) internal {
        address cr = assertions[assertionId].callbackRecipient;
        address em = _getEscalationManager(assertionId);
        if (cr != address(0))
            OptimisticOracleV3CallbackRecipientInterface(cr).assertionResolvedCallback(assertionId, assertedTruthfully);
        if (em != address(0)) EscalationManagerInterface(em).assertionResolvedCallback(assertionId, assertedTruthfully);
    }

    // Sends assertion disputed callback to the callback recipient and escalation manager (if set).
    function _callbackOnAssertionDispute(bytes32 assertionId) internal {
        address cr = assertions[assertionId].callbackRecipient;
        address em = _getEscalationManager(assertionId);
        if (cr != address(0)) OptimisticOracleV3CallbackRecipientInterface(cr).assertionDisputedCallback(assertionId);
        if (em != address(0)) EscalationManagerInterface(em).assertionDisputedCallback(assertionId);
    }
}

File 20 of 22 : EscalationManagerInterface.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

import "./OptimisticOracleV3CallbackRecipientInterface.sol";

/**
 * @title Escalation Manager Interface
 * @notice Interface for contracts that manage the escalation policy for assertions.
 */
interface EscalationManagerInterface is OptimisticOracleV3CallbackRecipientInterface {
    // Assertion policy parameters as returned by the escalation manager.
    struct AssertionPolicy {
        bool blockAssertion; // If true, the the assertion should be blocked.
        bool arbitrateViaEscalationManager; // If true, the escalation manager will arbitrate the assertion.
        bool discardOracle; // If true, the Optimistic Oracle V3 should discard the oracle price.
        bool validateDisputers; // If true, the escalation manager will validate the disputers.
    }

    /**
     * @notice Returns the assertion policy for the given assertion.
     * @param assertionId the assertion identifier to get the assertion policy for.
     * @return the assertion policy for the given assertion identifier.
     */
    function getAssertionPolicy(bytes32 assertionId) external view returns (AssertionPolicy memory);

    /**
     * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is disputed. Used to validate
     * if the dispute should be allowed based on the escalation policy.
     * @param assertionId the assertionId to validate the dispute for.
     * @param disputeCaller the caller of the dispute function.
     * @return bool true if the dispute is allowed, false otherwise.
     */
    function isDisputeAllowed(bytes32 assertionId, address disputeCaller) external view returns (bool);

    /**
     * @notice Implements price getting logic. This method is called by Optimistic Oracle V3 settling an assertion that
     * is configured to use the escalation manager as the oracle. The interface is constructed to mimic the UMA DVM.
     * @param identifier price identifier being requested.
     * @param time timestamp of the price being requested.
     * @param ancillaryData ancillary data of the price being requested.
     * @return price from the escalation manager to inform the resolution of the dispute.
     */
    function getPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) external returns (int256);

    /**
     * @notice Implements price requesting logic for the escalation manager. This function is called by the Optimistic
     * Oracle V3 on dispute and is constructed to mimic that of the UMA DVM interface.
     * @param identifier the identifier to fetch the price for.
     * @param time the time to fetch the price for.
     * @param ancillaryData ancillary data of the price being requested.
     */
    function requestPrice(
        bytes32 identifier,
        uint256 time,
        bytes memory ancillaryData
    ) external;
}

File 21 of 22 : OptimisticOracleV3CallbackRecipientInterface.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

/**
 * @title Optimistic Oracle V3 Callback Recipient Interface
 * @notice Interface for contracts implementing callbacks to be received from the Optimistic Oracle V3.
 */
interface OptimisticOracleV3CallbackRecipientInterface {
    /**
     * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is resolved.
     * @param assertionId The identifier of the assertion that was resolved.
     * @param assertedTruthfully Whether the assertion was resolved as truthful or not.
     */
    function assertionResolvedCallback(bytes32 assertionId, bool assertedTruthfully) external;

    /**
     * @notice Callback function that is called by Optimistic Oracle V3 when an assertion is disputed.
     * @param assertionId The identifier of the assertion that was disputed.
     */
    function assertionDisputedCallback(bytes32 assertionId) external;
}

File 22 of 22 : OptimisticOracleV3Interface.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.16;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Optimistic Oracle V3 Interface that callers must use to assert truths about the world.
 */
interface OptimisticOracleV3Interface {
    // Struct grouping together the settings related to the escalation manager stored in the assertion.
    struct EscalationManagerSettings {
        bool arbitrateViaEscalationManager; // False if the DVM is used as an oracle (EscalationManager on True).
        bool discardOracle; // False if Oracle result is used for resolving assertion after dispute.
        bool validateDisputers; // True if the EM isDisputeAllowed should be checked on disputes.
        address assertingCaller; // Stores msg.sender when assertion was made.
        address escalationManager; // Address of the escalation manager (zero address if not configured).
    }

    // Struct for storing properties and lifecycle of an assertion.
    struct Assertion {
        EscalationManagerSettings escalationManagerSettings; // Settings related to the escalation manager.
        address asserter; // Address of the asserter.
        uint64 assertionTime; // Time of the assertion.
        bool settled; // True if the request is settled.
        IERC20 currency; // ERC20 token used to pay rewards and fees.
        uint64 expirationTime; // Unix timestamp marking threshold when the assertion can no longer be disputed.
        bool settlementResolution; // Resolution of the assertion (false till resolved).
        bytes32 domainId; // Optional domain that can be used to relate the assertion to others in the escalationManager.
        bytes32 identifier; // UMA DVM identifier to use for price requests in the event of a dispute.
        uint256 bond; // Amount of currency that the asserter has bonded.
        address callbackRecipient; // Address that receives the callback.
        address disputer; // Address of the disputer.
    }

    // Struct for storing cached currency whitelist.
    struct WhitelistedCurrency {
        bool isWhitelisted; // True if the currency is whitelisted.
        uint256 finalFee; // Final fee of the currency.
    }

    /**
     * @notice Returns the default identifier used by the Optimistic Oracle V3.
     * @return The default identifier.
     */
    function defaultIdentifier() external view returns (bytes32);

    /**
     * @notice Fetches information about a specific assertion and returns it.
     * @param assertionId unique identifier for the assertion to fetch information for.
     * @return assertion information about the assertion.
     */
    function getAssertion(bytes32 assertionId) external view returns (Assertion memory);

    /**
     * @notice Asserts a truth about the world, using the default currency and liveness. No callback recipient or
     * escalation manager is enabled. The caller is expected to provide a bond of finalFee/burnedBondPercentage
     * (with burnedBondPercentage set to 50%, the bond is 2x final fee) of the default currency.
     * @dev The caller must approve this contract to spend at least the result of getMinimumBond(defaultCurrency).
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @return assertionId unique identifier for this assertion.
     */
    function assertTruthWithDefaults(bytes memory claim, address asserter) external returns (bytes32);

    /**
     * @notice Asserts a truth about the world, using a fully custom configuration.
     * @dev The caller must approve this contract to spend at least bond amount of currency.
     * @param claim the truth claim being asserted. This is an assertion about the world, and is verified by disputers.
     * @param asserter receives bonds back at settlement. This could be msg.sender or
     * any other account that the caller wants to receive the bond at settlement time.
     * @param callbackRecipient if configured, this address will receive a function call assertionResolvedCallback and
     * assertionDisputedCallback at resolution or dispute respectively. Enables dynamic responses to these events. The
     * recipient _must_ implement these callbacks and not revert or the assertion resolution will be blocked.
     * @param escalationManager if configured, this address will control escalation properties of the assertion. This
     * means a) choosing to arbitrate via the UMA DVM, b) choosing to discard assertions on dispute, or choosing to
     * validate disputes. Combining these, the asserter can define their own security properties for the assertion.
     * escalationManager also _must_ implement the same callbacks as callbackRecipient.
     * @param liveness time to wait before the assertion can be resolved. Assertion can be disputed in this time.
     * @param currency bond currency pulled from the caller and held in escrow until the assertion is resolved.
     * @param bond amount of currency to pull from the caller and hold in escrow until the assertion is resolved. This
     * must be >= getMinimumBond(address(currency)).
     * @param identifier UMA DVM identifier to use for price requests in the event of a dispute. Must be pre-approved.
     * @param domainId optional domain that can be used to relate this assertion to others in the escalationManager and
     * can be used by the configured escalationManager to define custom behavior for groups of assertions. This is
     * typically used for "escalation games" by changing bonds or other assertion properties based on the other
     * assertions that have come before. If not needed this value should be 0 to save gas.
     * @return assertionId unique identifier for this assertion.
     */
    function assertTruth(
        bytes memory claim,
        address asserter,
        address callbackRecipient,
        address escalationManager,
        uint64 liveness,
        IERC20 currency,
        uint256 bond,
        bytes32 identifier,
        bytes32 domainId
    ) external returns (bytes32);

    /**
     * @notice Fetches information about a specific identifier & currency from the UMA contracts and stores a local copy
     * of the information within this contract. This is used to save gas when making assertions as we can avoid an
     * external call to the UMA contracts to fetch this.
     * @param identifier identifier to fetch information for and store locally.
     * @param currency currency to fetch information for and store locally.
     */
    function syncUmaParams(bytes32 identifier, address currency) external;

    /**
     * @notice Resolves an assertion. If the assertion has not been disputed, the assertion is resolved as true and the
     * asserter receives the bond. If the assertion has been disputed, the assertion is resolved depending on the oracle
     * result. Based on the result, the asserter or disputer receives the bond. If the assertion was disputed then an
     * amount of the bond is sent to the UMA Store as an oracle fee based on the burnedBondPercentage. The remainder of
     * the bond is returned to the asserter or disputer.
     * @param assertionId unique identifier for the assertion to resolve.
     */
    function settleAssertion(bytes32 assertionId) external;

    /**
     * @notice Settles an assertion and returns the resolution.
     * @param assertionId unique identifier for the assertion to resolve and return the resolution for.
     * @return resolution of the assertion.
     */
    function settleAndGetAssertionResult(bytes32 assertionId) external returns (bool);

    /**
     * @notice Fetches the resolution of a specific assertion and returns it. If the assertion has not been settled then
     * this will revert. If the assertion was disputed and configured to discard the oracle resolution return false.
     * @param assertionId unique identifier for the assertion to fetch the resolution for.
     * @return resolution of the assertion.
     */
    function getAssertionResult(bytes32 assertionId) external view returns (bool);

    /**
     * @notice Returns the minimum bond amount required to make an assertion. This is calculated as the final fee of the
     * currency divided by the burnedBondPercentage. If burn percentage is 50% then the min bond is 2x the final fee.
     * @param currency currency to calculate the minimum bond for.
     * @return minimum bond amount.
     */
    function getMinimumBond(address currency) external view returns (uint256);

    event AssertionMade(
        bytes32 indexed assertionId,
        bytes32 domainId,
        bytes claim,
        address indexed asserter,
        address callbackRecipient,
        address escalationManager,
        address caller,
        uint64 expirationTime,
        IERC20 currency,
        uint256 bond,
        bytes32 indexed identifier
    );

    event AssertionDisputed(bytes32 indexed assertionId, address indexed caller, address indexed disputer);

    event AssertionSettled(
        bytes32 indexed assertionId,
        address indexed bondRecipient,
        bool disputed,
        bool settlementResolution,
        address settleCaller
    );

    event AdminPropertiesSet(IERC20 defaultCurrency, uint64 defaultLiveness, uint256 burnedBondPercentage);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"contract FinderInterface","name":"_finder","type":"address"},{"internalType":"contract IERC20","name":"_defaultCurrency","type":"address"},{"internalType":"uint64","name":"_defaultLiveness","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"defaultCurrency","type":"address"},{"indexed":false,"internalType":"uint64","name":"defaultLiveness","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"burnedBondPercentage","type":"uint256"}],"name":"AdminPropertiesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assertionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"disputer","type":"address"}],"name":"AssertionDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assertionId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"domainId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"claim","type":"bytes"},{"indexed":true,"internalType":"address","name":"asserter","type":"address"},{"indexed":false,"internalType":"address","name":"callbackRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"escalationManager","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint64","name":"expirationTime","type":"uint64"},{"indexed":false,"internalType":"contract IERC20","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"bond","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"identifier","type":"bytes32"}],"name":"AssertionMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"assertionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"bondRecipient","type":"address"},{"indexed":false,"internalType":"bool","name":"disputed","type":"bool"},{"indexed":false,"internalType":"bool","name":"settlementResolution","type":"bool"},{"indexed":false,"internalType":"address","name":"settleCaller","type":"address"}],"name":"AssertionSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bytes","name":"claim","type":"bytes"},{"internalType":"address","name":"asserter","type":"address"},{"internalType":"address","name":"callbackRecipient","type":"address"},{"internalType":"address","name":"escalationManager","type":"address"},{"internalType":"uint64","name":"liveness","type":"uint64"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"bytes32","name":"domainId","type":"bytes32"}],"name":"assertTruth","outputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"claim","type":"bytes"},{"internalType":"address","name":"asserter","type":"address"}],"name":"assertTruthWithDefaults","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"assertions","outputs":[{"components":[{"internalType":"bool","name":"arbitrateViaEscalationManager","type":"bool"},{"internalType":"bool","name":"discardOracle","type":"bool"},{"internalType":"bool","name":"validateDisputers","type":"bool"},{"internalType":"address","name":"assertingCaller","type":"address"},{"internalType":"address","name":"escalationManager","type":"address"}],"internalType":"struct OptimisticOracleV3Interface.EscalationManagerSettings","name":"escalationManagerSettings","type":"tuple"},{"internalType":"address","name":"asserter","type":"address"},{"internalType":"uint64","name":"assertionTime","type":"uint64"},{"internalType":"bool","name":"settled","type":"bool"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"uint64","name":"expirationTime","type":"uint64"},{"internalType":"bool","name":"settlementResolution","type":"bool"},{"internalType":"bytes32","name":"domainId","type":"bytes32"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"address","name":"callbackRecipient","type":"address"},{"internalType":"address","name":"disputer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnedBondPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cachedCurrencies","outputs":[{"internalType":"bool","name":"isWhitelisted","type":"bool"},{"internalType":"uint256","name":"finalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cachedIdentifiers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cachedOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultCurrency","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultIdentifier","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultLiveness","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"},{"internalType":"address","name":"disputer","type":"address"}],"name":"disputeAssertion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finder","outputs":[{"internalType":"contract FinderInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"}],"name":"getAssertion","outputs":[{"components":[{"components":[{"internalType":"bool","name":"arbitrateViaEscalationManager","type":"bool"},{"internalType":"bool","name":"discardOracle","type":"bool"},{"internalType":"bool","name":"validateDisputers","type":"bool"},{"internalType":"address","name":"assertingCaller","type":"address"},{"internalType":"address","name":"escalationManager","type":"address"}],"internalType":"struct OptimisticOracleV3Interface.EscalationManagerSettings","name":"escalationManagerSettings","type":"tuple"},{"internalType":"address","name":"asserter","type":"address"},{"internalType":"uint64","name":"assertionTime","type":"uint64"},{"internalType":"bool","name":"settled","type":"bool"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"uint64","name":"expirationTime","type":"uint64"},{"internalType":"bool","name":"settlementResolution","type":"bool"},{"internalType":"bytes32","name":"domainId","type":"bytes32"},{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"address","name":"callbackRecipient","type":"address"},{"internalType":"address","name":"disputer","type":"address"}],"internalType":"struct OptimisticOracleV3Interface.Assertion","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"}],"name":"getAssertionResult","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"currency","type":"address"}],"name":"getMinimumBond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"numericalTrue","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_defaultCurrency","type":"address"},{"internalType":"uint64","name":"_defaultLiveness","type":"uint64"},{"internalType":"uint256","name":"_burnedBondPercentage","type":"uint256"}],"name":"setAdminProperties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"}],"name":"settleAndGetAssertionResult","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"}],"name":"settleAssertion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"assertionId","type":"bytes32"}],"name":"stampAssertion","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"address","name":"currency","type":"address"}],"name":"syncUmaParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162004ddd38038062004ddd833981016040819052620000349162000634565b6000805460ff19166001179055620000536200004d3390565b6200007e565b6001600160a01b0383166080526200007582826706f05b59d3b20000620000d7565b5050506200072f565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6000546001600160a01b036101009091041633146200013d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b670de0b6b3a7640000811115620001975760405162461bcd60e51b815260206004820152601c60248201527f4275726e656420626f6e642070657263656e74616765203e2031303000000000604482015260640162000134565b60008111620001e95760405162461bcd60e51b815260206004820152601b60248201527f4275726e656420626f6e642070657263656e7461676520697320300000000000604482015260640162000134565b6005819055600680546001600160401b038416600160a01b026001600160e01b03199091166001600160a01b03861617179055620002376b082a6a68aa4a8bea8a4aaa8960a31b846200028e565b604080516001600160a01b03851681526001600160401b03841660208201529081018290527fd0f09246d369018534c67fec6a6c3259c6f962ef82c5521c337ae0ccc104e4bd9060600160405180910390a1505050565b6080516040516302abf57960e61b8152654f7261636c6560d01b60048201526001600160a01b039091169063aafd5e4090602401602060405180830381865afa158015620002e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000306919062000693565b600180546001600160a01b0319166001600160a01b039290921691909117905562000330620004f9565b6001600160a01b03166390978d1b836040518263ffffffff1660e01b81526004016200035e91815260200190565b602060405180830381865afa1580156200037c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003a29190620006ba565b6000838152600360205260409020805460ff1916911515919091179055620003c96200058f565b604051631d1d5b3960e11b81526001600160a01b0383811660048301529190911690633a3ab67290602401602060405180830381865afa15801562000412573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004389190620006ba565b6001600160a01b0382166000908152600260205260409020805460ff191691151591909117905562000469620005e1565b604051635b97aadd60e01b81526001600160a01b0383811660048301529190911690635b97aadd90602401602060405180830381865afa158015620004b2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004d89190620006de565b516001600160a01b0390911660009081526002602052604090206001015550565b6080516040516302abf57960e61b81527f4964656e74696669657257686974656c6973740000000000000000000000000060048201526000916001600160a01b03169063aafd5e40906024015b602060405180830381865afa15801562000564573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200058a919062000693565b905090565b6080516040516302abf57960e61b81527f436f6c6c61746572616c57686974656c6973740000000000000000000000000060048201526000916001600160a01b03169063aafd5e409060240162000546565b6080516040516302abf57960e61b81526453746f726560d81b60048201526000916001600160a01b03169063aafd5e409060240162000546565b6001600160a01b03811681146200063157600080fd5b50565b6000806000606084860312156200064a57600080fd5b835162000657816200061b565b60208501519093506200066a816200061b565b60408501519092506001600160401b03811681146200068857600080fd5b809150509250925092565b600060208284031215620006a657600080fd5b8151620006b3816200061b565b9392505050565b600060208284031215620006cd57600080fd5b81518015158114620006b357600080fd5b600060208284031215620006f157600080fd5b604051602081016001600160401b03811182821017156200072257634e487b7160e01b600052604160045260246000fd5b6040529151825250919050565b60805161467662000767600039600081816105a601528181611e72015281816129c40152818161323801526132cd01526146766000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80638ea2f2ab116100ee578063b9a3c84c11610097578063da03b36e11610071578063da03b36e1461071b578063e39dfd7f1461072a578063f2fde38b1461073d578063fe4e19831461075057600080fd5b8063b9a3c84c146105a1578063d509b017146105c8578063d60715b5146105ef57600080fd5b8063a8655785116100c8578063a86557851461054e578063ac9650d814610561578063afedba4f1461058157600080fd5b80638ea2f2ab14610508578063a6a22b431461051b578063a7af2d0f1461052e57600080fd5b8063530dd3921161015b578063715018a611610135578063715018a6146102df57806382762520146102e757806388302884146102fa5780638da5cb5b146104e557600080fd5b8063530dd392146102555780636457c97914610288578063707621571461029b57600080fd5b806336b13af41161018c57806336b13af41461021a5780634124beef1461022d5780634360af3d1461024257600080fd5b806308e7c3e6146101b357806320402e1d146101cf57806329cb924d14610214575b600080fd5b6101bc60055481565b6040519081526020015b60405180910390f35b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b426101bc565b6101bc610228366004613a49565b610795565b61024061023b366004613acc565b61084c565b005b6101bc610250366004613ae5565b610e41565b610278610263366004613acc565b60036020526000908152604090205460ff1681565b60405190151581526020016101c6565b6101bc610296366004613bde565b610e89565b6102c86102a9366004613ae5565b6002602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016101c6565b6102406116ef565b6102406102f5366004613ccf565b611782565b6104d8610308366004613acc565b6040805161022081018252600061018082018181526101a083018290526101c083018290526101e083018290526102008301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250600090815260046020818152604092839020835161022081018552815460ff80821615156101808401908152610100808404831615156101a0860152620100008404831615156101c086015273ffffffffffffffffffffffffffffffffffffffff630100000090940484166101e08601526001860154841661020086015290845260028501548084169685019690965267ffffffffffffffff740100000000000000000000000000000000000000008088048216998601999099527c010000000000000000000000000000000000000000000000000000000096879004831615156060860152600386015480851660808701529889041660a085015294909604909516151560c08201529281015460e08401526005810154918301919091526006810154610120830152600781015483166101408301526008015490911661016082015290565b6040516101c69190613d0d565b600054610100900473ffffffffffffffffffffffffffffffffffffffff166101ef565b610278610516366004613acc565b6119de565b610240610529366004613e29565b611a2f565b6001546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b61024061055c366004613e29565b611e24565b61057461056f366004613e59565b6121a9565b6040516101c69190613f3c565b61059461058f366004613acc565b61231b565b6040516101c69190613fbc565b6101ef7f000000000000000000000000000000000000000000000000000000000000000081565b6101bc7f4153534552545f5452555448000000000000000000000000000000000000000081565b6107036105fd366004613acc565b600460208181526000928352604092839020835160a081018552815460ff8082161515835261010082048116151594830194909452620100008104841615159582019590955273ffffffffffffffffffffffffffffffffffffffff630100000090950485166060820152600182015485166080820152600282015460038301549483015460058401546006850154600786015460089096015494988481169867ffffffffffffffff7401000000000000000000000000000000000000000080880482169a7c01000000000000000000000000000000000000000000000000000000009889900481169a8486169a928504909316989093049092169594939290811691168c565b6040516101c69c9b9a99989796959493929190613fcf565b6101bc670de0b6b3a764000081565b610278610738366004613acc565b612326565b61024061074b366004613ae5565b6124fe565b60065461077c9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101c6565b600061084284848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060065488945090925082915067ffffffffffffffff740100000000000000000000000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff1661081a81610e41565b7f4153534552545f545255544800000000000000000000000000000000000000006000610e89565b90505b9392505050565b610854612631565b610881600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6000818152600460205260409020600281015473ffffffffffffffffffffffffffffffffffffffff16610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20646f6573206e6f74206578697374000000000000000060448201526064015b60405180910390fd5b60028101547c0100000000000000000000000000000000000000000000000000000000900460ff16156109a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f417373657274696f6e20616c726561647920736574746c656400000000000000604482015260640161090c565b6002810180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055600881015473ffffffffffffffffffffffffffffffffffffffff16610b865742600382015474010000000000000000000000000000000000000000900467ffffffffffffffff161115610a9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420657870697265640000000000000000000000604482015260640161090c565b6003810180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff81167c01000000000000000000000000000000000000000000000000000000001790915560028201546006830154610b159273ffffffffffffffffffffffffffffffffffffffff90811692169061269d565b610b20826001612776565b60028101546040805160008152600160208201523381830152905173ffffffffffffffffffffffffffffffffffffffff9092169184917ff4fa324b13daeb4e1aae736c2553632ae0fb16fb31f2d4da8ac99fd056313a13919081900360600190a3610e0d565b60058101546002820154600091610bc19185919074010000000000000000000000000000000000000000900467ffffffffffffffff166128e3565b8254909150610100900460ff1615610c02576003820180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff169055610c58565b6003820180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16670de0b6b3a764000083147c0100000000000000000000000000000000000000000000000000000000021790555b6000670de0b6b3a76400008214610c8957600883015473ffffffffffffffffffffffffffffffffffffffff16610ca5565b600283015473ffffffffffffffffffffffffffffffffffffffff165b90506000670de0b6b3a76400008460060154600554610cc491906140da565b610cce9190614146565b905060008185600601546002610ce491906140da565b610cee9190614181565b9050610d1d610cfb612973565b600387015473ffffffffffffffffffffffffffffffffffffffff16908461269d565b6003850154610d439073ffffffffffffffffffffffffffffffffffffffff16848361269d565b8454610100900460ff16610d84576003850154610d849087907c0100000000000000000000000000000000000000000000000000000000900460ff16612776565b600385015460408051600181527c010000000000000000000000000000000000000000000000000000000090920460ff1615156020830152339082015273ffffffffffffffffffffffffffffffffffffffff84169087907ff4fa324b13daeb4e1aae736c2553632ae0fb16fb31f2d4da8ac99fd056313a139060600160405180910390a3505050505b50610e3e600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040812060010154600554610e7f82670de0b6b3a76400006140da565b6108459190614146565b6000610e93612631565b610ec0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b42610edb8b8667ffffffffffffffff84168a8a8e8e8b612a4a565b915073ffffffffffffffffffffffffffffffffffffffff8a16610f5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f41737365727465722063616e7420626520300000000000000000000000000000604482015260640161090c565b60008281526004602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1615610fe9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20616c7265616479206578697374730000000000000000604482015260640161090c565b610ff284612a91565b611058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e737570706f72746564206964656e74696669657200000000000000000000604482015260640161090c565b61106186612b75565b6110c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e737570706f727465642063757272656e6379000000000000000000000000604482015260640161090c565b6110d086610e41565b851015611139576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f426f6e6420616d6f756e7420746f6f206c6f7700000000000000000000000000604482015260640161090c565b6040805161022081018252600061018082018181526101a083018290526101c08301829052336101e084015273ffffffffffffffffffffffffffffffffffffffff8c81166102008501529083528d8116602084015267ffffffffffffffff8516938301939093526060820152908716608082015260a081016111bb8984614194565b67ffffffffffffffff1681526020016000151581526020018481526020018581526020018681526020018a73ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152506004600084815260200190815260200160002060008201518160000160008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548160ff02191690831515021790555060608201518160000160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505060208201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550606082015181600201601c6101000a81548160ff02191690831515021790555060808201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160030160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060c082015181600301601c6101000a81548160ff02191690831515021790555060e08201518160040155610100820151816005015561012082015181600601556101408201518160070160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101608201518160080160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050600061151283612d68565b80519091501561157e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420616c6c6f7765640000000000000000000000604482015260640161090c565b600083815260046020908152604091829020908301519183015160609093015181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff1662010000911515919091027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff161761010093151593909302929092177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690151517905561164873ffffffffffffffffffffffffffffffffffffffff8716333088612e70565b838a73ffffffffffffffffffffffffffffffffffffffff16837fdb1513f0abeb57a364db56aa3eb52015cca5268f00fd67bc73aaf22bccab02b7868f8e8e338f8a6116939190614194565b8f8f6040516116a99897969594939291906141b5565b60405180910390a4506116e2600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b9998505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314611776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b6117806000612ece565b565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314611809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b670de0b6b3a764000081111561187b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4275726e656420626f6e642070657263656e74616765203e2031303000000000604482015260640161090c565b600081116118e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4275726e656420626f6e642070657263656e7461676520697320300000000000604482015260640161090c565b60058190556006805467ffffffffffffffff841674010000000000000000000000000000000000000000027fffffffff0000000000000000000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff8616171790556119797f4153534552545f5452555448000000000000000000000000000000000000000084611e24565b6040805173ffffffffffffffffffffffffffffffffffffffff8516815267ffffffffffffffff841660208201529081018290527fd0f09246d369018534c67fec6a6c3259c6f962ef82c5521c337ae0ccc104e4bd9060600160405180910390a1505050565b6000818152600460205260408120600201547c0100000000000000000000000000000000000000000000000000000000900460ff16611a2057611a208261084c565b611a2982612326565b92915050565b611a37612631565b611a64600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b73ffffffffffffffffffffffffffffffffffffffff8116611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f44697370757465722063616e2774206265203000000000000000000000000000604482015260640161090c565b6000828152600460205260409020600281015473ffffffffffffffffffffffffffffffffffffffff16611b70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20646f6573206e6f742065786973740000000000000000604482015260640161090c565b600881015473ffffffffffffffffffffffffffffffffffffffff1615611bf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f417373657274696f6e20616c7265616479206469737075746564000000000000604482015260640161090c565b42600382015474010000000000000000000000000000000000000000900467ffffffffffffffff1611611c81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f417373657274696f6e2069732065787069726564000000000000000000000000604482015260640161090c565b611c8a83612f4b565b611cf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f44697370757465206e6f7420616c6c6f77656400000000000000000000000000604482015260640161090c565b6008810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169190911790915560068201546003830154611d5092169033903090612e70565b60058101546002820154611d8791859174010000000000000000000000000000000000000000900467ffffffffffffffff1661303a565b611d90836130be565b8054610100900460ff1615611daa57611daa836000612776565b60405173ffffffffffffffffffffffffffffffffffffffff831690339085907f60133788b013c89f2a3756dbc47e3484997b87bd7e0af98a7d70232032c1ce2b90600090a450611e20600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4f7261636c65000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401602060405180830381865afa158015611ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef29190614225565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055611f3f6131e7565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b836040518263ffffffff1660e01b8152600401611f7991815260200190565b602060405180830381865afa158015611f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fba9190614252565b600083815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611ffd61327c565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301529190911690633a3ab67290602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190614252565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556120e9612973565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301529190911690635b97aadd90602401602060405180830381865afa158015612157573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217b919061426d565b5173ffffffffffffffffffffffffffffffffffffffff90911660009081526002602052604090206001015550565b60608167ffffffffffffffff8111156121c4576121c4613b02565b6040519080825280602002602001820160405280156121f757816020015b60608152602001906001900390816121e25790505b50905060005b82811015612314576000803086868581811061221b5761221b6142af565b905060200281019061222d91906142de565b60405161223b92919061434a565b600060405180830381855af49150503d8060008114612276576040519150601f19603f3d011682016040523d82523d6000602084013e61227b565b606091505b5091509150816122e15760448151101561229457600080fd5b600481019050808060200190518101906122ae919061435a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090c9190613fbc565b808484815181106122f4576122f46142af565b60200260200101819052505050808061230c906143d1565b9150506121fd565b5092915050565b6060611a2982613311565b6000818152600460208181526040808420815161022081018352815460ff80821615156101808401908152610100808404831615156101a0860152620100008404831615156101c086015273ffffffffffffffffffffffffffffffffffffffff630100000090940484166101e08601526001860154841661020086015290845260028501548084169785019790975267ffffffffffffffff740100000000000000000000000000000000000000008089048216978601979097527c010000000000000000000000000000000000000000000000000000000097889004831615156060860152600386015480851660808701529687041660a085015295909404909316151560c08201529381015460e08501526005810154928401929092526006820154610120840152600782015481166101408401526008909101541661016082018190521580159061247b57508051602001515b156124895750600092915050565b80606001516124f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420736574746c65640000000000000000000000604482015260640161090c565b60c0015192915050565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314612585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b73ffffffffffffffffffffffffffffffffffffffff8116612628576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161090c565b610e3e81612ece565b60005460ff16611780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161090c565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526127719084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526133c9565b505050565b6000828152600460205260409020600781015460019091015473ffffffffffffffffffffffffffffffffffffffff91821691168115612838576040517ff1b156b200000000000000000000000000000000000000000000000000000000815260048101859052831515602482015273ffffffffffffffffffffffffffffffffffffffff83169063f1b156b290604401600060405180830381600087803b15801561281f57600080fd5b505af1158015612833573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff8116156128dd576040517ff1b156b200000000000000000000000000000000000000000000000000000000815260048101859052831515602482015273ffffffffffffffffffffffffffffffffffffffff82169063f1b156b290604401600060405180830381600087803b1580156128c457600080fd5b505af11580156128d8573d6000803e3d6000fd5b505050505b50505050565b60006128ee846134d5565b73ffffffffffffffffffffffffffffffffffffffff1663719c6d56848461291488613311565b6040518463ffffffff1660e01b815260040161293293929190614409565b602060405180830381865afa15801561294f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108429190614428565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f53746f726500000000000000000000000000000000000000000000000000000060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063aafd5e40906024015b602060405180830381865afa158015612a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a459190614225565b905090565b6000888888888888888833604051602001612a6d99989796959493929190614441565b60405160208183030381529060405280519060200120905098975050505050505050565b60008181526003602052604081205460ff1615612ab057506001919050565b612ab86131e7565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b836040518263ffffffff1660e01b8152600401612af291815260200190565b602060405180830381865afa158015612b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b339190614252565b60009283526003602052604090922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001692151592831790555060ff1690565b73ffffffffffffffffffffffffffffffffffffffff811660009081526002602052604081205460ff1615612bab57506001919050565b612bb361327c565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529190911690633a3ab67290602401602060405180830381865afa158015612c21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c459190614252565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612c9f612973565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529190911690635b97aadd90602401602060405180830381865afa158015612d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d31919061426d565b5173ffffffffffffffffffffffffffffffffffffffff90921660009081526002602052604090206001810192909255505460ff1690565b60408051608081018252600080825260208083018290528284018290526060830182905284825260049052919091206001015473ffffffffffffffffffffffffffffffffffffffff1680612de1575050604080516080810182526000808252602082018190529181018290526060810191909152919050565b6040517fa6b011a70000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff82169063a6b011a790602401608060405180830381865afa158015612e4c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084591906144b7565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526128dd9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016126ef565b6000805473ffffffffffffffffffffffffffffffffffffffff8381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60008181526004602052604081205462010000900460ff16612f6f57506001919050565b60008281526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff1680612fa55750600192915050565b6040517f6b915d910000000000000000000000000000000000000000000000000000000081526004810184905233602482015273ffffffffffffffffffffffffffffffffffffffff821690636b915d9190604401602060405180830381865afa158015613016573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108459190614252565b613043836134d5565b73ffffffffffffffffffffffffffffffffffffffff1663216666a4838361306987613311565b6040518463ffffffff1660e01b815260040161308793929190614409565b600060405180830381600087803b1580156130a157600080fd5b505af11580156130b5573d6000803e3d6000fd5b50505050505050565b6000818152600460205260409020600781015460019091015473ffffffffffffffffffffffffffffffffffffffff91821691168115613178576040517fd448a4ec0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff83169063d448a4ec90602401600060405180830381600087803b15801561315f57600080fd5b505af1158015613173573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff811615612771576040517fd448a4ec0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff82169063d448a4ec90602401613087565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4964656e74696669657257686974656c6973740000000000000000000000000060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401612a04565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f436f6c6c61746572616c57686974656c6973740000000000000000000000000060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401612a04565b6060611a29613365604051806020016040528060008152506040518060400160405280600b81526020017f617373657274696f6e496400000000000000000000000000000000000000000081525085613537565b604080518082018252600a81527f6f6f41737365727465720000000000000000000000000000000000000000000060208083019190915260008781526004909152919091206002015473ffffffffffffffffffffffffffffffffffffffff1661357d565b600061342b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166135989092919063ffffffff16565b80519091501561277157808060200190518101906134499190614252565b612771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161090c565b60008181526004602052604081205460ff16156135195760008281526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff16611a29565b505060015473ffffffffffffffffffffffffffffffffffffffff1690565b6060600061354585856135a7565b90508481613552856135e9565b60405160200161356493929190614534565b6040516020818303038152906040529150509392505050565b6060600061358b85856135a7565b905084816135528561362a565b606061084284846000856136a2565b8151606090156135d857816040516020016135c29190614577565b6040516020818303038152906040529050611a29565b816040516020016135c291906145e3565b60606135f8608083901c613822565b61360183613822565b6040805160208101939093528201526060015b6040516020818303038152906040529050919050565b606061364b6fffffffffffffffffffffffffffffffff602084901c16613822565b6136668360601b6bffffffffffffffffffffffff1916613822565b6040516020016136149291909182527fffffffffffffffff00000000000000000000000000000000000000000000000016602082015260280190565b606082471015613734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161090c565b843b61379c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161090c565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516137c59190614624565b60006040518083038185875af1925050503d8060008114613802576040519150601f19603f3d011682016040523d82523d6000602084013e613807565b606091505b50915091506138178282866139c4565b979650505050505050565b6000808260001c9050806fffffffffffffffffffffffffffffffff169050806801000000000000000002811777ffffffffffffffff0000000000000000ffffffffffffffff169050806401000000000281177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16905080620100000281177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff169050806101000281177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff1690508060100281177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16905060006008827f0808080808080808080808080808080808080808080808080808080808080808168161394657613946614117565b0460047f040404040404040404040404040404040404040404040404040404040404040484160460027f020202020202020202020202020202020202020202020202020202020202020285160417166027029091017f3030303030303030303030303030303030303030303030303030303030303030019392505050565b606083156139d3575081610845565b8251156139e35782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090c9190613fbc565b73ffffffffffffffffffffffffffffffffffffffff81168114610e3e57600080fd5b8035613a4481613a17565b919050565b600080600060408486031215613a5e57600080fd5b833567ffffffffffffffff80821115613a7657600080fd5b818601915086601f830112613a8a57600080fd5b813581811115613a9957600080fd5b876020828501011115613aab57600080fd5b60209283019550935050840135613ac181613a17565b809150509250925092565b600060208284031215613ade57600080fd5b5035919050565b600060208284031215613af757600080fd5b813561084581613a17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b7857613b78613b02565b604052919050565b600067ffffffffffffffff821115613b9a57613b9a613b02565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b803567ffffffffffffffff81168114613a4457600080fd5b60008060008060008060008060006101208a8c031215613bfd57600080fd5b893567ffffffffffffffff811115613c1457600080fd5b8a01601f81018c13613c2557600080fd5b8035613c38613c3382613b80565b613b31565b8181528d6020838501011115613c4d57600080fd5b81602084016020830137600060208383010152809b50505050613c7260208b01613a39565b9750613c8060408b01613a39565b9650613c8e60608b01613a39565b9550613c9c60808b01613bc6565b9450613caa60a08b01613a39565b935060c08a0135925060e08a013591506101008a013590509295985092959850929598565b600080600060608486031215613ce457600080fd5b8335613cef81613a17565b9250613cfd60208501613bc6565b9150604084013590509250925092565b815180511515825260208082015115158184015260408083015115158185015260608084015173ffffffffffffffffffffffffffffffffffffffff9081168287015260809485015181168587015292860151831660a08601529085015167ffffffffffffffff1660c0850152840151151560e084015290830151908116610100808401919091526102008301919060a08501519150610120613dba8186018467ffffffffffffffff169052565b60c08601519250610140613dd18187018515159052565b60e08701516101608781019190915292870151610180870152908601516101a086015285015173ffffffffffffffffffffffffffffffffffffffff9081166101c0860152908501519081166101e08501529050612314565b60008060408385031215613e3c57600080fd5b823591506020830135613e4e81613a17565b809150509250929050565b60008060208385031215613e6c57600080fd5b823567ffffffffffffffff80821115613e8457600080fd5b818501915085601f830112613e9857600080fd5b813581811115613ea757600080fd5b8660208260051b8501011115613ebc57600080fd5b60209290920196919550909350505050565b60005b83811015613ee9578181015183820152602001613ed1565b50506000910152565b60008151808452613f0a816020860160208601613ece565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613faf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613f9d858351613ef2565b94509285019290850190600101613f63565b5092979650505050505050565b6020815260006108456020830184613ef2565b610200810161402b828f805115158252602081015115156020830152604081015115156040830152606081015173ffffffffffffffffffffffffffffffffffffffff808216606085015280608084015116608085015250505050565b73ffffffffffffffffffffffffffffffffffffffff9c8d1660a083015267ffffffffffffffff9b8c1660c083015299151560e0820152978b16610100890152959098166101208701529215156101408601526101608501919091526101808401526101a08301529284166101c0820152919092166101e090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614112576141126140ab565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261417c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115611a2957611a296140ab565b67ffffffffffffffff818116838216019080821115612314576123146140ab565b60006101008a83528060208401526141cf8184018b613ef2565b73ffffffffffffffffffffffffffffffffffffffff998a16604085015297891660608401525050938616608085015267ffffffffffffffff9290921660a084015290931660c082015260e0019190915292915050565b60006020828403121561423757600080fd5b815161084581613a17565b80518015158114613a4457600080fd5b60006020828403121561426457600080fd5b61084582614242565b60006020828403121561427f57600080fd5b6040516020810181811067ffffffffffffffff821117156142a2576142a2613b02565b6040529151825250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261431357600080fd5b83018035915067ffffffffffffffff82111561432e57600080fd5b60200191503681900382131561434357600080fd5b9250929050565b8183823760009101908152919050565b60006020828403121561436c57600080fd5b815167ffffffffffffffff81111561438357600080fd5b8201601f8101841361439457600080fd5b80516143a2613c3382613b80565b8181528560208385010111156143b757600080fd5b6143c8826020830160208601613ece565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614402576144026140ab565b5060010190565b8381528260208201526060604082015260006143c86060830184613ef2565b60006020828403121561443a57600080fd5b5051919050565b60006101208083526144558184018d613ef2565b602084019b909b525050604081019790975267ffffffffffffffff95909516606087015273ffffffffffffffffffffffffffffffffffffffff938416608087015291831660a0860152821660c085015260e08401521661010090910152919050565b6000608082840312156144c957600080fd5b6040516080810181811067ffffffffffffffff821117156144ec576144ec613b02565b6040526144f883614242565b815261450660208401614242565b602082015261451760408401614242565b604082015261452860608401614242565b60608201529392505050565b60008451614546818460208901613ece565b84519083019061455a818360208901613ece565b845191019061456d818360208801613ece565b0195945050505050565b7f2c000000000000000000000000000000000000000000000000000000000000008152600082516145af816001850160208701613ece565b7f3a000000000000000000000000000000000000000000000000000000000000006001939091019283015250600201919050565b600082516145f5818460208701613ece565b7f3a00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b60008251614636818460208701613ece565b919091019291505056fea2646970667358221220f03b241d1c61d5494f1c346bd67521c49226c51304400e4ef1a5a988d347aaf364736f6c63430008100033000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd4000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a830000000000000000000000000000000000000000000000000000000000001c20

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80638ea2f2ab116100ee578063b9a3c84c11610097578063da03b36e11610071578063da03b36e1461071b578063e39dfd7f1461072a578063f2fde38b1461073d578063fe4e19831461075057600080fd5b8063b9a3c84c146105a1578063d509b017146105c8578063d60715b5146105ef57600080fd5b8063a8655785116100c8578063a86557851461054e578063ac9650d814610561578063afedba4f1461058157600080fd5b80638ea2f2ab14610508578063a6a22b431461051b578063a7af2d0f1461052e57600080fd5b8063530dd3921161015b578063715018a611610135578063715018a6146102df57806382762520146102e757806388302884146102fa5780638da5cb5b146104e557600080fd5b8063530dd392146102555780636457c97914610288578063707621571461029b57600080fd5b806336b13af41161018c57806336b13af41461021a5780634124beef1461022d5780634360af3d1461024257600080fd5b806308e7c3e6146101b357806320402e1d146101cf57806329cb924d14610214575b600080fd5b6101bc60055481565b6040519081526020015b60405180910390f35b6006546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b426101bc565b6101bc610228366004613a49565b610795565b61024061023b366004613acc565b61084c565b005b6101bc610250366004613ae5565b610e41565b610278610263366004613acc565b60036020526000908152604090205460ff1681565b60405190151581526020016101c6565b6101bc610296366004613bde565b610e89565b6102c86102a9366004613ae5565b6002602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016101c6565b6102406116ef565b6102406102f5366004613ccf565b611782565b6104d8610308366004613acc565b6040805161022081018252600061018082018181526101a083018290526101c083018290526101e083018290526102008301829052825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915250600090815260046020818152604092839020835161022081018552815460ff80821615156101808401908152610100808404831615156101a0860152620100008404831615156101c086015273ffffffffffffffffffffffffffffffffffffffff630100000090940484166101e08601526001860154841661020086015290845260028501548084169685019690965267ffffffffffffffff740100000000000000000000000000000000000000008088048216998601999099527c010000000000000000000000000000000000000000000000000000000096879004831615156060860152600386015480851660808701529889041660a085015294909604909516151560c08201529281015460e08401526005810154918301919091526006810154610120830152600781015483166101408301526008015490911661016082015290565b6040516101c69190613d0d565b600054610100900473ffffffffffffffffffffffffffffffffffffffff166101ef565b610278610516366004613acc565b6119de565b610240610529366004613e29565b611a2f565b6001546101ef9073ffffffffffffffffffffffffffffffffffffffff1681565b61024061055c366004613e29565b611e24565b61057461056f366004613e59565b6121a9565b6040516101c69190613f3c565b61059461058f366004613acc565b61231b565b6040516101c69190613fbc565b6101ef7f000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd481565b6101bc7f4153534552545f5452555448000000000000000000000000000000000000000081565b6107036105fd366004613acc565b600460208181526000928352604092839020835160a081018552815460ff8082161515835261010082048116151594830194909452620100008104841615159582019590955273ffffffffffffffffffffffffffffffffffffffff630100000090950485166060820152600182015485166080820152600282015460038301549483015460058401546006850154600786015460089096015494988481169867ffffffffffffffff7401000000000000000000000000000000000000000080880482169a7c01000000000000000000000000000000000000000000000000000000009889900481169a8486169a928504909316989093049092169594939290811691168c565b6040516101c69c9b9a99989796959493929190613fcf565b6101bc670de0b6b3a764000081565b610278610738366004613acc565b612326565b61024061074b366004613ae5565b6124fe565b60065461077c9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101c6565b600061084284848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060065488945090925082915067ffffffffffffffff740100000000000000000000000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff1661081a81610e41565b7f4153534552545f545255544800000000000000000000000000000000000000006000610e89565b90505b9392505050565b610854612631565b610881600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b6000818152600460205260409020600281015473ffffffffffffffffffffffffffffffffffffffff16610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20646f6573206e6f74206578697374000000000000000060448201526064015b60405180910390fd5b60028101547c0100000000000000000000000000000000000000000000000000000000900460ff16156109a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f417373657274696f6e20616c726561647920736574746c656400000000000000604482015260640161090c565b6002810180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c0100000000000000000000000000000000000000000000000000000000179055600881015473ffffffffffffffffffffffffffffffffffffffff16610b865742600382015474010000000000000000000000000000000000000000900467ffffffffffffffff161115610a9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420657870697265640000000000000000000000604482015260640161090c565b6003810180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff81167c01000000000000000000000000000000000000000000000000000000001790915560028201546006830154610b159273ffffffffffffffffffffffffffffffffffffffff90811692169061269d565b610b20826001612776565b60028101546040805160008152600160208201523381830152905173ffffffffffffffffffffffffffffffffffffffff9092169184917ff4fa324b13daeb4e1aae736c2553632ae0fb16fb31f2d4da8ac99fd056313a13919081900360600190a3610e0d565b60058101546002820154600091610bc19185919074010000000000000000000000000000000000000000900467ffffffffffffffff166128e3565b8254909150610100900460ff1615610c02576003820180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff169055610c58565b6003820180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff16670de0b6b3a764000083147c0100000000000000000000000000000000000000000000000000000000021790555b6000670de0b6b3a76400008214610c8957600883015473ffffffffffffffffffffffffffffffffffffffff16610ca5565b600283015473ffffffffffffffffffffffffffffffffffffffff165b90506000670de0b6b3a76400008460060154600554610cc491906140da565b610cce9190614146565b905060008185600601546002610ce491906140da565b610cee9190614181565b9050610d1d610cfb612973565b600387015473ffffffffffffffffffffffffffffffffffffffff16908461269d565b6003850154610d439073ffffffffffffffffffffffffffffffffffffffff16848361269d565b8454610100900460ff16610d84576003850154610d849087907c0100000000000000000000000000000000000000000000000000000000900460ff16612776565b600385015460408051600181527c010000000000000000000000000000000000000000000000000000000090920460ff1615156020830152339082015273ffffffffffffffffffffffffffffffffffffffff84169087907ff4fa324b13daeb4e1aae736c2553632ae0fb16fb31f2d4da8ac99fd056313a139060600160405180910390a3505050505b50610e3e600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b50565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260026020526040812060010154600554610e7f82670de0b6b3a76400006140da565b6108459190614146565b6000610e93612631565b610ec0600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b42610edb8b8667ffffffffffffffff84168a8a8e8e8b612a4a565b915073ffffffffffffffffffffffffffffffffffffffff8a16610f5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f41737365727465722063616e7420626520300000000000000000000000000000604482015260640161090c565b60008281526004602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1615610fe9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20616c7265616479206578697374730000000000000000604482015260640161090c565b610ff284612a91565b611058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e737570706f72746564206964656e74696669657200000000000000000000604482015260640161090c565b61106186612b75565b6110c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e737570706f727465642063757272656e6379000000000000000000000000604482015260640161090c565b6110d086610e41565b851015611139576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f426f6e6420616d6f756e7420746f6f206c6f7700000000000000000000000000604482015260640161090c565b6040805161022081018252600061018082018181526101a083018290526101c08301829052336101e084015273ffffffffffffffffffffffffffffffffffffffff8c81166102008501529083528d8116602084015267ffffffffffffffff8516938301939093526060820152908716608082015260a081016111bb8984614194565b67ffffffffffffffff1681526020016000151581526020018481526020018581526020018681526020018a73ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152506004600084815260200190815260200160002060008201518160000160008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548160ff02191690831515021790555060608201518160000160036101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505060208201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550606082015181600201601c6101000a81548160ff02191690831515021790555060808201518160030160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160030160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060c082015181600301601c6101000a81548160ff02191690831515021790555060e08201518160040155610100820151816005015561012082015181600601556101408201518160070160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101608201518160080160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050600061151283612d68565b80519091501561157e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420616c6c6f7765640000000000000000000000604482015260640161090c565b600083815260046020908152604091829020908301519183015160609093015181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff1662010000911515919091027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff161761010093151593909302929092177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690151517905561164873ffffffffffffffffffffffffffffffffffffffff8716333088612e70565b838a73ffffffffffffffffffffffffffffffffffffffff16837fdb1513f0abeb57a364db56aa3eb52015cca5268f00fd67bc73aaf22bccab02b7868f8e8e338f8a6116939190614194565b8f8f6040516116a99897969594939291906141b5565b60405180910390a4506116e2600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b9998505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314611776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b6117806000612ece565b565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314611809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b670de0b6b3a764000081111561187b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4275726e656420626f6e642070657263656e74616765203e2031303000000000604482015260640161090c565b600081116118e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4275726e656420626f6e642070657263656e7461676520697320300000000000604482015260640161090c565b60058190556006805467ffffffffffffffff841674010000000000000000000000000000000000000000027fffffffff0000000000000000000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff8616171790556119797f4153534552545f5452555448000000000000000000000000000000000000000084611e24565b6040805173ffffffffffffffffffffffffffffffffffffffff8516815267ffffffffffffffff841660208201529081018290527fd0f09246d369018534c67fec6a6c3259c6f962ef82c5521c337ae0ccc104e4bd9060600160405180910390a1505050565b6000818152600460205260408120600201547c0100000000000000000000000000000000000000000000000000000000900460ff16611a2057611a208261084c565b611a2982612326565b92915050565b611a37612631565b611a64600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b73ffffffffffffffffffffffffffffffffffffffff8116611ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f44697370757465722063616e2774206265203000000000000000000000000000604482015260640161090c565b6000828152600460205260409020600281015473ffffffffffffffffffffffffffffffffffffffff16611b70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f417373657274696f6e20646f6573206e6f742065786973740000000000000000604482015260640161090c565b600881015473ffffffffffffffffffffffffffffffffffffffff1615611bf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f417373657274696f6e20616c7265616479206469737075746564000000000000604482015260640161090c565b42600382015474010000000000000000000000000000000000000000900467ffffffffffffffff1611611c81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f417373657274696f6e2069732065787069726564000000000000000000000000604482015260640161090c565b611c8a83612f4b565b611cf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f44697370757465206e6f7420616c6c6f77656400000000000000000000000000604482015260640161090c565b6008810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8481169190911790915560068201546003830154611d5092169033903090612e70565b60058101546002820154611d8791859174010000000000000000000000000000000000000000900467ffffffffffffffff1661303a565b611d90836130be565b8054610100900460ff1615611daa57611daa836000612776565b60405173ffffffffffffffffffffffffffffffffffffffff831690339085907f60133788b013c89f2a3756dbc47e3484997b87bd7e0af98a7d70232032c1ce2b90600090a450611e20600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b5050565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4f7261636c65000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd473ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401602060405180830381865afa158015611ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef29190614225565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055611f3f6131e7565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b836040518263ffffffff1660e01b8152600401611f7991815260200190565b602060405180830381865afa158015611f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fba9190614252565b600083815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611ffd61327c565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301529190911690633a3ab67290602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190614252565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556120e9612973565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301529190911690635b97aadd90602401602060405180830381865afa158015612157573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217b919061426d565b5173ffffffffffffffffffffffffffffffffffffffff90911660009081526002602052604090206001015550565b60608167ffffffffffffffff8111156121c4576121c4613b02565b6040519080825280602002602001820160405280156121f757816020015b60608152602001906001900390816121e25790505b50905060005b82811015612314576000803086868581811061221b5761221b6142af565b905060200281019061222d91906142de565b60405161223b92919061434a565b600060405180830381855af49150503d8060008114612276576040519150601f19603f3d011682016040523d82523d6000602084013e61227b565b606091505b5091509150816122e15760448151101561229457600080fd5b600481019050808060200190518101906122ae919061435a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090c9190613fbc565b808484815181106122f4576122f46142af565b60200260200101819052505050808061230c906143d1565b9150506121fd565b5092915050565b6060611a2982613311565b6000818152600460208181526040808420815161022081018352815460ff80821615156101808401908152610100808404831615156101a0860152620100008404831615156101c086015273ffffffffffffffffffffffffffffffffffffffff630100000090940484166101e08601526001860154841661020086015290845260028501548084169785019790975267ffffffffffffffff740100000000000000000000000000000000000000008089048216978601979097527c010000000000000000000000000000000000000000000000000000000097889004831615156060860152600386015480851660808701529687041660a085015295909404909316151560c08201529381015460e08501526005810154928401929092526006820154610120840152600782015481166101408401526008909101541661016082018190521580159061247b57508051602001515b156124895750600092915050565b80606001516124f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f417373657274696f6e206e6f7420736574746c65640000000000000000000000604482015260640161090c565b60c0015192915050565b60005473ffffffffffffffffffffffffffffffffffffffff610100909104163314612585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161090c565b73ffffffffffffffffffffffffffffffffffffffff8116612628576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161090c565b610e3e81612ece565b60005460ff16611780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161090c565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526127719084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526133c9565b505050565b6000828152600460205260409020600781015460019091015473ffffffffffffffffffffffffffffffffffffffff91821691168115612838576040517ff1b156b200000000000000000000000000000000000000000000000000000000815260048101859052831515602482015273ffffffffffffffffffffffffffffffffffffffff83169063f1b156b290604401600060405180830381600087803b15801561281f57600080fd5b505af1158015612833573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff8116156128dd576040517ff1b156b200000000000000000000000000000000000000000000000000000000815260048101859052831515602482015273ffffffffffffffffffffffffffffffffffffffff82169063f1b156b290604401600060405180830381600087803b1580156128c457600080fd5b505af11580156128d8573d6000803e3d6000fd5b505050505b50505050565b60006128ee846134d5565b73ffffffffffffffffffffffffffffffffffffffff1663719c6d56848461291488613311565b6040518463ffffffff1660e01b815260040161293293929190614409565b602060405180830381865afa15801561294f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108429190614428565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f53746f726500000000000000000000000000000000000000000000000000000060048201526000907f000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd473ffffffffffffffffffffffffffffffffffffffff169063aafd5e40906024015b602060405180830381865afa158015612a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a459190614225565b905090565b6000888888888888888833604051602001612a6d99989796959493929190614441565b60405160208183030381529060405280519060200120905098975050505050505050565b60008181526003602052604081205460ff1615612ab057506001919050565b612ab86131e7565b73ffffffffffffffffffffffffffffffffffffffff166390978d1b836040518263ffffffff1660e01b8152600401612af291815260200190565b602060405180830381865afa158015612b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b339190614252565b60009283526003602052604090922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001692151592831790555060ff1690565b73ffffffffffffffffffffffffffffffffffffffff811660009081526002602052604081205460ff1615612bab57506001919050565b612bb361327c565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529190911690633a3ab67290602401602060405180830381865afa158015612c21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c459190614252565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612c9f612973565b6040517f5b97aadd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529190911690635b97aadd90602401602060405180830381865afa158015612d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d31919061426d565b5173ffffffffffffffffffffffffffffffffffffffff90921660009081526002602052604090206001810192909255505460ff1690565b60408051608081018252600080825260208083018290528284018290526060830182905284825260049052919091206001015473ffffffffffffffffffffffffffffffffffffffff1680612de1575050604080516080810182526000808252602082018190529181018290526060810191909152919050565b6040517fa6b011a70000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff82169063a6b011a790602401608060405180830381865afa158015612e4c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084591906144b7565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526128dd9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016126ef565b6000805473ffffffffffffffffffffffffffffffffffffffff8381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60008181526004602052604081205462010000900460ff16612f6f57506001919050565b60008281526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff1680612fa55750600192915050565b6040517f6b915d910000000000000000000000000000000000000000000000000000000081526004810184905233602482015273ffffffffffffffffffffffffffffffffffffffff821690636b915d9190604401602060405180830381865afa158015613016573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108459190614252565b613043836134d5565b73ffffffffffffffffffffffffffffffffffffffff1663216666a4838361306987613311565b6040518463ffffffff1660e01b815260040161308793929190614409565b600060405180830381600087803b1580156130a157600080fd5b505af11580156130b5573d6000803e3d6000fd5b50505050505050565b6000818152600460205260409020600781015460019091015473ffffffffffffffffffffffffffffffffffffffff91821691168115613178576040517fd448a4ec0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff83169063d448a4ec90602401600060405180830381600087803b15801561315f57600080fd5b505af1158015613173573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff811615612771576040517fd448a4ec0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff82169063d448a4ec90602401613087565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f4964656e74696669657257686974656c6973740000000000000000000000000060048201526000907f000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd473ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401612a04565b6040517faafd5e400000000000000000000000000000000000000000000000000000000081527f436f6c6c61746572616c57686974656c6973740000000000000000000000000060048201526000907f000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd473ffffffffffffffffffffffffffffffffffffffff169063aafd5e4090602401612a04565b6060611a29613365604051806020016040528060008152506040518060400160405280600b81526020017f617373657274696f6e496400000000000000000000000000000000000000000081525085613537565b604080518082018252600a81527f6f6f41737365727465720000000000000000000000000000000000000000000060208083019190915260008781526004909152919091206002015473ffffffffffffffffffffffffffffffffffffffff1661357d565b600061342b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166135989092919063ffffffff16565b80519091501561277157808060200190518101906134499190614252565b612771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161090c565b60008181526004602052604081205460ff16156135195760008281526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff16611a29565b505060015473ffffffffffffffffffffffffffffffffffffffff1690565b6060600061354585856135a7565b90508481613552856135e9565b60405160200161356493929190614534565b6040516020818303038152906040529150509392505050565b6060600061358b85856135a7565b905084816135528561362a565b606061084284846000856136a2565b8151606090156135d857816040516020016135c29190614577565b6040516020818303038152906040529050611a29565b816040516020016135c291906145e3565b60606135f8608083901c613822565b61360183613822565b6040805160208101939093528201526060015b6040516020818303038152906040529050919050565b606061364b6fffffffffffffffffffffffffffffffff602084901c16613822565b6136668360601b6bffffffffffffffffffffffff1916613822565b6040516020016136149291909182527fffffffffffffffff00000000000000000000000000000000000000000000000016602082015260280190565b606082471015613734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161090c565b843b61379c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161090c565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516137c59190614624565b60006040518083038185875af1925050503d8060008114613802576040519150601f19603f3d011682016040523d82523d6000602084013e613807565b606091505b50915091506138178282866139c4565b979650505050505050565b6000808260001c9050806fffffffffffffffffffffffffffffffff169050806801000000000000000002811777ffffffffffffffff0000000000000000ffffffffffffffff169050806401000000000281177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16905080620100000281177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff169050806101000281177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff1690508060100281177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16905060006008827f0808080808080808080808080808080808080808080808080808080808080808168161394657613946614117565b0460047f040404040404040404040404040404040404040404040404040404040404040484160460027f020202020202020202020202020202020202020202020202020202020202020285160417166027029091017f3030303030303030303030303030303030303030303030303030303030303030019392505050565b606083156139d3575081610845565b8251156139e35782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161090c9190613fbc565b73ffffffffffffffffffffffffffffffffffffffff81168114610e3e57600080fd5b8035613a4481613a17565b919050565b600080600060408486031215613a5e57600080fd5b833567ffffffffffffffff80821115613a7657600080fd5b818601915086601f830112613a8a57600080fd5b813581811115613a9957600080fd5b876020828501011115613aab57600080fd5b60209283019550935050840135613ac181613a17565b809150509250925092565b600060208284031215613ade57600080fd5b5035919050565b600060208284031215613af757600080fd5b813561084581613a17565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b7857613b78613b02565b604052919050565b600067ffffffffffffffff821115613b9a57613b9a613b02565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b803567ffffffffffffffff81168114613a4457600080fd5b60008060008060008060008060006101208a8c031215613bfd57600080fd5b893567ffffffffffffffff811115613c1457600080fd5b8a01601f81018c13613c2557600080fd5b8035613c38613c3382613b80565b613b31565b8181528d6020838501011115613c4d57600080fd5b81602084016020830137600060208383010152809b50505050613c7260208b01613a39565b9750613c8060408b01613a39565b9650613c8e60608b01613a39565b9550613c9c60808b01613bc6565b9450613caa60a08b01613a39565b935060c08a0135925060e08a013591506101008a013590509295985092959850929598565b600080600060608486031215613ce457600080fd5b8335613cef81613a17565b9250613cfd60208501613bc6565b9150604084013590509250925092565b815180511515825260208082015115158184015260408083015115158185015260608084015173ffffffffffffffffffffffffffffffffffffffff9081168287015260809485015181168587015292860151831660a08601529085015167ffffffffffffffff1660c0850152840151151560e084015290830151908116610100808401919091526102008301919060a08501519150610120613dba8186018467ffffffffffffffff169052565b60c08601519250610140613dd18187018515159052565b60e08701516101608781019190915292870151610180870152908601516101a086015285015173ffffffffffffffffffffffffffffffffffffffff9081166101c0860152908501519081166101e08501529050612314565b60008060408385031215613e3c57600080fd5b823591506020830135613e4e81613a17565b809150509250929050565b60008060208385031215613e6c57600080fd5b823567ffffffffffffffff80821115613e8457600080fd5b818501915085601f830112613e9857600080fd5b813581811115613ea757600080fd5b8660208260051b8501011115613ebc57600080fd5b60209290920196919550909350505050565b60005b83811015613ee9578181015183820152602001613ed1565b50506000910152565b60008151808452613f0a816020860160208601613ece565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613faf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613f9d858351613ef2565b94509285019290850190600101613f63565b5092979650505050505050565b6020815260006108456020830184613ef2565b610200810161402b828f805115158252602081015115156020830152604081015115156040830152606081015173ffffffffffffffffffffffffffffffffffffffff808216606085015280608084015116608085015250505050565b73ffffffffffffffffffffffffffffffffffffffff9c8d1660a083015267ffffffffffffffff9b8c1660c083015299151560e0820152978b16610100890152959098166101208701529215156101408601526101608501919091526101808401526101a08301529284166101c0820152919092166101e090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614112576141126140ab565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261417c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115611a2957611a296140ab565b67ffffffffffffffff818116838216019080821115612314576123146140ab565b60006101008a83528060208401526141cf8184018b613ef2565b73ffffffffffffffffffffffffffffffffffffffff998a16604085015297891660608401525050938616608085015267ffffffffffffffff9290921660a084015290931660c082015260e0019190915292915050565b60006020828403121561423757600080fd5b815161084581613a17565b80518015158114613a4457600080fd5b60006020828403121561426457600080fd5b61084582614242565b60006020828403121561427f57600080fd5b6040516020810181811067ffffffffffffffff821117156142a2576142a2613b02565b6040529151825250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261431357600080fd5b83018035915067ffffffffffffffff82111561432e57600080fd5b60200191503681900382131561434357600080fd5b9250929050565b8183823760009101908152919050565b60006020828403121561436c57600080fd5b815167ffffffffffffffff81111561438357600080fd5b8201601f8101841361439457600080fd5b80516143a2613c3382613b80565b8181528560208385010111156143b757600080fd5b6143c8826020830160208601613ece565b95945050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614402576144026140ab565b5060010190565b8381528260208201526060604082015260006143c86060830184613ef2565b60006020828403121561443a57600080fd5b5051919050565b60006101208083526144558184018d613ef2565b602084019b909b525050604081019790975267ffffffffffffffff95909516606087015273ffffffffffffffffffffffffffffffffffffffff938416608087015291831660a0860152821660c085015260e08401521661010090910152919050565b6000608082840312156144c957600080fd5b6040516080810181811067ffffffffffffffff821117156144ec576144ec613b02565b6040526144f883614242565b815261450660208401614242565b602082015261451760408401614242565b604082015261452860608401614242565b60608201529392505050565b60008451614546818460208901613ece565b84519083019061455a818360208901613ece565b845191019061456d818360208801613ece565b0195945050505050565b7f2c000000000000000000000000000000000000000000000000000000000000008152600082516145af816001850160208701613ece565b7f3a000000000000000000000000000000000000000000000000000000000000006001939091019283015250600201919050565b600082516145f5818460208701613ece565b7f3a00000000000000000000000000000000000000000000000000000000000000920191825250600101919050565b60008251614636818460208701613ece565b919091019291505056fea2646970667358221220f03b241d1c61d5494f1c346bd67521c49226c51304400e4ef1a5a988d347aaf364736f6c63430008100033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd4000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a830000000000000000000000000000000000000000000000000000000000001c20

-----Decoded View---------------
Arg [0] : _finder (address): 0xef684c38f94f48775959ecf2012d7e864ffb9dd4
Arg [1] : _defaultCurrency (address): 0xddafbb505ad214d7b80b1f830fccc89b60fb7a83
Arg [2] : _defaultLiveness (uint64): 7200

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000ef684c38f94f48775959ecf2012d7e864ffb9dd4
Arg [1] : 000000000000000000000000ddafbb505ad214d7b80b1f830fccc89b60fb7a83
Arg [2] : 0000000000000000000000000000000000000000000000000000000000001c20


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.