POL Price: $0.185132 (+12.95%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Resolve787169962025-11-07 18:07:371 min ago1762538857IN
0x65070BE9...056C2f2A7
0 POL0.06261018255.92260529
Resolve787169952025-11-07 18:07:351 min ago1762538855IN
0x65070BE9...056C2f2A7
0 POL0.0625587255.71215951
Initialize787167802025-11-07 18:00:259 mins ago1762538425IN
0x65070BE9...056C2f2A7
0 POL0.36025856269.6558282
Initialize787167802025-11-07 18:00:259 mins ago1762538425IN
0x65070BE9...056C2f2A7
0 POL0.3665251269.6558282
Initialize787167802025-11-07 18:00:259 mins ago1762538425IN
0x65070BE9...056C2f2A7
0 POL0.36653157269.6558282
Initialize787167802025-11-07 18:00:259 mins ago1762538425IN
0x65070BE9...056C2f2A7
0 POL0.36652833269.6558282
Resolve787166922025-11-07 17:57:2912 mins ago1762538249IN
0x65070BE9...056C2f2A7
0 POL0.06597535269.69114179
Resolve787166642025-11-07 17:56:3312 mins ago1762538193IN
0x65070BE9...056C2f2A7
0 POL0.05463748278.30120697
Resolve787166632025-11-07 17:56:3112 mins ago1762538191IN
0x65070BE9...056C2f2A7
0 POL0.05403456278.6824049
Resolve787162012025-11-07 17:41:0728 mins ago1762537267IN
0x65070BE9...056C2f2A7
0 POL0.10705664341.84397871
Initialize787157312025-11-07 17:25:2744 mins ago1762536327IN
0x65070BE9...056C2f2A7
0 POL0.50518438441.84849309
Initialize787157312025-11-07 17:25:2744 mins ago1762536327IN
0x65070BE9...056C2f2A7
0 POL0.50517377441.84849309
Initialize787157312025-11-07 17:25:2744 mins ago1762536327IN
0x65070BE9...056C2f2A7
0 POL0.50497671441.84849309
Initialize787157312025-11-07 17:25:2744 mins ago1762536327IN
0x65070BE9...056C2f2A7
0 POL0.48416476441.84849309
Initialize787157302025-11-07 17:25:2544 mins ago1762536325IN
0x65070BE9...056C2f2A7
0 POL0.50649201443.09604447
Initialize787157302025-11-07 17:25:2544 mins ago1762536325IN
0x65070BE9...056C2f2A7
0 POL0.48537715443.09604447
Initialize787157302025-11-07 17:25:2544 mins ago1762536325IN
0x65070BE9...056C2f2A7
0 POL0.49593258443.09604447
Initialize787156452025-11-07 17:22:3546 mins ago1762536155IN
0x65070BE9...056C2f2A7
0 POL0.48883918410.44156132
Initialize787156452025-11-07 17:22:3546 mins ago1762536155IN
0x65070BE9...056C2f2A7
0 POL0.49843202410.44156132
Initialize787156452025-11-07 17:22:3546 mins ago1762536155IN
0x65070BE9...056C2f2A7
0 POL0.4790444410.44156132
Initialize787156402025-11-07 17:22:2547 mins ago1762536145IN
0x65070BE9...056C2f2A7
0 POL0.46822328409.6172887
Initialize787156402025-11-07 17:22:2547 mins ago1762536145IN
0x65070BE9...056C2f2A7
0 POL0.50707957409.6172887
Initialize787156392025-11-07 17:22:2347 mins ago1762536143IN
0x65070BE9...056C2f2A7
0 POL0.4649305406.81281954
Initialize787156392025-11-07 17:22:2347 mins ago1762536143IN
0x65070BE9...056C2f2A7
0 POL0.47480914406.81281954
Initialize787156392025-11-07 17:22:2347 mins ago1762536143IN
0x65070BE9...056C2f2A7
0 POL0.45547129406.81281954
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UmaCtfAdapter

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
london EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { IERC20 } from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

import { Auth } from "./mixins/Auth.sol";
import { BulletinBoard } from "./mixins/BulletinBoard.sol";

import { TransferHelper } from "./libraries/TransferHelper.sol";
import { PayoutHelperLib } from "./libraries/PayoutHelperLib.sol";
import { AncillaryDataLib } from "./libraries/AncillaryDataLib.sol";

import { IFinder } from "./interfaces/IFinder.sol";
import { IAddressWhitelist } from "./interfaces/IAddressWhitelist.sol";
import { IConditionalTokens } from "./interfaces/IConditionalTokens.sol";
import { IOptimisticOracleV2 } from "./interfaces/IOptimisticOracleV2.sol";
import { IOptimisticRequester } from "./interfaces/IOptimisticRequester.sol";

import { QuestionData, IUmaCtfAdapter } from "./interfaces/IUmaCtfAdapter.sol";

/// @title UmaCtfAdapter
/// @notice Enables resolution of Polymarket CTF markets via UMA's Optimistic Oracle
contract UmaCtfAdapter is IUmaCtfAdapter, Auth, BulletinBoard, IOptimisticRequester {
    /*///////////////////////////////////////////////////////////////////
                            IMMUTABLES 
    //////////////////////////////////////////////////////////////////*/

    /// @notice Conditional Tokens Framework
    IConditionalTokens public immutable ctf;

    /// @notice Optimistic Oracle
    IOptimisticOracleV2 public immutable optimisticOracle;

    /// @notice Collateral Whitelist
    IAddressWhitelist public immutable collateralWhitelist;

    /// @notice Time period after which an admin can manually resolve a condition
    uint256 public constant SAFETY_PERIOD = 1 hours;

    /// @notice Unique query identifier for the Optimistic Oracle
    /// From UMIP-107
    bytes32 public constant YES_OR_NO_IDENTIFIER = "YES_OR_NO_QUERY";

    /// @notice Maximum ancillary data length
    /// From OOV2 function OO_ANCILLARY_DATA_LIMIT
    uint256 public constant MAX_ANCILLARY_DATA = 8139;

    /// @notice Mapping of questionID to QuestionData
    mapping(bytes32 => QuestionData) public questions;

    modifier onlyOptimisticOracle() {
        if (msg.sender != address(optimisticOracle)) revert NotOptimisticOracle();
        _;
    }

    /// @param _ctf     - The Conditional Token Framework Address
    ///                 - When deployed for negative risk markets, this should be the `NegRiskOperator` contract address
    /// @param _finder  - The UMA Finder contract address
    /// @param _oo      - The Optimistic Oracle contract address
    constructor(address _ctf, address _finder, address _oo) {
        ctf = IConditionalTokens(_ctf);
        IFinder finder = IFinder(_finder);
        optimisticOracle = IOptimisticOracleV2(_oo);
        collateralWhitelist = IAddressWhitelist(finder.getImplementationAddress("CollateralWhitelist"));
    }

    /*///////////////////////////////////////////////////////////////////
                            PUBLIC FUNCTIONS 
    //////////////////////////////////////////////////////////////////*/

    /// @notice Initializes a question
    /// Atomically adds the question to the Adapter, prepares it on the ConditionalTokens Framework and requests a price from the OO.
    /// If a reward is provided, the caller must have approved the Adapter as spender and have enough rewardToken
    /// to pay for the price request.
    /// Prepares the condition using the Adapter as the oracle and a fixed outcome slot count = 2.
    /// @param ancillaryData - Data used to resolve a question
    /// @param rewardToken   - ERC20 token address used for payment of rewards and fees
    /// @param reward        - Reward offered to a successful OO proposer. 
    ///                        Must be chosen carefully, to properly economically incentize OO proposers.
    /// @param proposalBond  - Bond required to be posted by OO proposers/disputers.
    ///                        If 0, the default OO bond is used.
    ///                        Must be chosen carefully, to properly economically incentize OO proposers and disputers.
    ///                        Questions expected to secure a large amount of value should consider a larger proposal bond. 
    /// @param liveness      - OO liveness period in seconds. 
    ///                        If 0, the default liveness period of 2 hours is used.
    ///                        Must be chosen carefully, depending on the value backed by the question.
    ///                        Questions expected to secure a large amount of value should consider a longer liveness period.
    function initialize(
        bytes memory ancillaryData,
        address rewardToken,
        uint256 reward,
        uint256 proposalBond,
        uint256 liveness
    ) external returns (bytes32 questionID) {
        if (!collateralWhitelist.isOnWhitelist(rewardToken)) revert UnsupportedToken();

        bytes memory data = AncillaryDataLib._appendAncillaryData(msg.sender, ancillaryData);
        if (ancillaryData.length == 0 || data.length > MAX_ANCILLARY_DATA) revert InvalidAncillaryData();

        questionID = keccak256(data);

        if (_isInitialized(questions[questionID])) revert Initialized();

        uint256 timestamp = block.timestamp;

        // Persist the question parameters in storage
        _saveQuestion(msg.sender, questionID, data, timestamp, rewardToken, reward, proposalBond, liveness);

        // Prepare the question on the CTF
        ctf.prepareCondition(address(this), questionID, 2);

        // Request a price for the question from the OO
        _requestPrice(msg.sender, timestamp, data, rewardToken, reward, proposalBond, liveness);

        emit QuestionInitialized(questionID, timestamp, msg.sender, data, rewardToken, reward, proposalBond);
    }

    /// @notice Checks whether a questionID is ready to be resolved
    /// @param questionID - The unique questionID
    function ready(bytes32 questionID) public view returns (bool) {
        return _ready(questions[questionID]);
    }

    /// @notice Resolves a question
    /// Pulls price information from the OO and resolves the underlying CTF market.
    /// Reverts if price is not available on the OO
    /// Resets the question if the price returned by the OO is the Ignore price
    /// @param questionID - The unique questionID of the question
    function resolve(bytes32 questionID) external {
        QuestionData storage questionData = questions[questionID];

        if (!_isInitialized(questionData)) revert NotInitialized();
        if (questionData.paused) revert Paused();
        if (questionData.resolved) revert Resolved();
        if (!_hasPrice(questionData)) revert NotReadyToResolve();

        // Resolve the underlying market
        return _resolve(questionID, questionData);
    }

    /// @notice Retrieves the expected payout array of the question
    /// @param questionID - The unique questionID of the question
    function getExpectedPayouts(bytes32 questionID) public view returns (uint256[] memory) {
        QuestionData storage questionData = questions[questionID];

        if (!_isInitialized(questionData)) revert NotInitialized();
        if (_isFlagged(questionData)) revert Flagged();
        if (questionData.paused) revert Paused();

        if (!_hasPrice(questionData)) revert PriceNotAvailable();

        // Fetches price from OO
        int256 price = optimisticOracle.getRequest(
            address(this), YES_OR_NO_IDENTIFIER, questionData.requestTimestamp, questionData.ancillaryData
        ).resolvedPrice;

        return _constructPayouts(price);
    }

    /// @notice Callback which is executed on dispute
    /// Resets the question and sends out a new price request to the OO
    /// @param ancillaryData    - Ancillary data of the request
    function priceDisputed(bytes32, uint256, bytes memory ancillaryData, uint256) external onlyOptimisticOracle {
        bytes32 questionID = keccak256(ancillaryData);
        QuestionData storage questionData = questions[questionID];

        // If a Question is already resolved, e.g by resolveManually, the priceDisputed callback should not update
        // any storage parameters.
        // Refund the reward to the question creator
        if (questionData.resolved) {
            TransferHelper._transfer(questionData.rewardToken, questionData.creator, questionData.reward);
            return;
        }

        if (questionData.reset) {
            questionData.refund = true;
            return;
        }

        // If the question has not been reset previously, reset the question
        // Ensures that there are at most 2 OO Requests at a time for a question
        _reset(address(this), questionID, false, questionData);
    }

    /// @notice Checks if a question is initialized
    /// @param questionID - The unique questionID
    function isInitialized(bytes32 questionID) public view returns (bool) {
        return _isInitialized(questions[questionID]);
    }

    /// @notice Checks if a question has been flagged for manual resolution
    /// @param questionID - The unique questionID
    function isFlagged(bytes32 questionID) public view returns (bool) {
        return _isFlagged(questions[questionID]);
    }

    /// @notice Gets the QuestionData for the given questionID
    /// @param questionID - The unique questionID
    function getQuestion(bytes32 questionID) external view returns (QuestionData memory) {
        return questions[questionID];
    }

    /*////////////////////////////////////////////////////////////////////
                            ADMIN ONLY FUNCTIONS 
    ///////////////////////////////////////////////////////////////////*/

    /// @notice Flags a market for manual resolution
    /// @param questionID - The unique questionID of the question
    function flag(bytes32 questionID) external onlyAdmin {
        QuestionData storage questionData = questions[questionID];

        if (!_isInitialized(questionData)) revert NotInitialized();
        if (_isFlagged(questionData)) revert Flagged();
        if (questionData.resolved) revert Resolved();

        questionData.manualResolutionTimestamp = block.timestamp + SAFETY_PERIOD;
        questionData.paused = true;

        emit QuestionFlagged(questionID);
    }

    /// @notice Unflags a market for manual resolution
    /// @param questionID - The unique questionID of the question
    function unflag(bytes32 questionID) external onlyAdmin {
        QuestionData storage questionData = questions[questionID];

        if (!_isInitialized(questionData)) revert NotInitialized();
        if (!_isFlagged(questionData)) revert NotFlagged();
        if (questionData.resolved) revert Resolved();
        if (block.timestamp > questionData.manualResolutionTimestamp) revert SafetyPeriodPassed();

        questionData.manualResolutionTimestamp = 0;
        questionData.paused = false;

        emit QuestionUnflagged(questionID);
    }

    /// @notice Allows an admin to reset a question, sending out a new price request to the OO.
    /// Failsafe to be used if the priceDisputed callback reverts during execution.
    /// @param questionID - The unique questionID
    function reset(bytes32 questionID) external onlyAdmin {
        QuestionData storage questionData = questions[questionID];
        if (!_isInitialized(questionData)) revert NotInitialized();
        if (questionData.resolved) revert Resolved();

        // Refund the reward to the question creator if necessary
        if (questionData.refund) _refund(questionData);

        // Reset the question, paying for the price request from the caller
        _reset(msg.sender, questionID, true, questionData);
    }

    /// @notice Allows an admin to resolve a CTF market manually
    /// @param questionID   - The unique questionID of the question
    /// @param payouts      - Array of position payouts for the referenced question
    function resolveManually(bytes32 questionID, uint256[] calldata payouts) external onlyAdmin {
        QuestionData storage questionData = questions[questionID];

        if (!_isValidPayoutArray(payouts)) revert InvalidPayouts();
        if (!_isInitialized(questionData)) revert NotInitialized();
        if (!_isFlagged(questionData)) revert NotFlagged();
        if (block.timestamp < questionData.manualResolutionTimestamp) revert SafetyPeriodNotPassed();

        questionData.resolved = true;

        // Refund the reward to the question creator if necessary
        if (questionData.refund) _refund(questionData);

        ctf.reportPayouts(questionID, payouts);
        emit QuestionManuallyResolved(questionID, payouts);
    }

    /// @notice Allows an admin to pause market resolution
    /// @param questionID - The unique questionID of the question
    function pause(bytes32 questionID) external onlyAdmin {
        QuestionData storage questionData = questions[questionID];

        if (!_isInitialized(questionData)) revert NotInitialized();
        if (questionData.resolved) revert Resolved();

        questionData.paused = true;
        emit QuestionPaused(questionID);
    }

    /// @notice Allows an admin to unpause market resolution
    /// @param questionID - The unique questionID of the question
    function unpause(bytes32 questionID) external onlyAdmin {
        QuestionData storage questionData = questions[questionID];
        if (!_isInitialized(questionData)) revert NotInitialized();

        questionData.paused = false;
        emit QuestionUnpaused(questionID);
    }

    /*///////////////////////////////////////////////////////////////////
                            INTERNAL FUNCTIONS 
    //////////////////////////////////////////////////////////////////*/

    function _ready(QuestionData storage questionData) internal view returns (bool) {
        if (!_isInitialized(questionData)) return false;
        if (questionData.paused) return false;
        if (questionData.resolved) return false;
        return _hasPrice(questionData);
    }

    function _saveQuestion(
        address creator,
        bytes32 questionID,
        bytes memory ancillaryData,
        uint256 requestTimestamp,
        address rewardToken,
        uint256 reward,
        uint256 proposalBond,
        uint256 liveness
    ) internal {
        questions[questionID] = QuestionData({
            requestTimestamp: requestTimestamp,
            reward: reward,
            proposalBond: proposalBond,
            liveness: liveness,
            manualResolutionTimestamp: 0,
            resolved: false,
            paused: false,
            reset: false,
            refund: false,
            rewardToken: rewardToken,
            creator: creator,
            ancillaryData: ancillaryData
        });
    }

    /// @notice Request a price from the Optimistic Oracle
    /// Transfers reward token from the requestor if non-zero reward is specified
    /// @param requestor        - Address of the requestor
    /// @param requestTimestamp - Timestamp used in the OO request
    /// @param ancillaryData    - Data used to resolve a question
    /// @param rewardToken      - Address of the reward token
    /// @param reward           - Reward amount, denominated in rewardToken
    /// @param bond             - Bond amount used, denominated in rewardToken
    /// @param liveness         - UMA liveness period, will be the default liveness period if 0.
    function _requestPrice(
        address requestor,
        uint256 requestTimestamp,
        bytes memory ancillaryData,
        address rewardToken,
        uint256 reward,
        uint256 bond,
        uint256 liveness
    ) internal {
        if (reward > 0) {
            // If the requestor is not the Adapter, the requestor pays for the price request
            // If not, the Adapter pays for the price request
            if (requestor != address(this)) {
                TransferHelper._transferFromERC20(rewardToken, requestor, address(this), reward);
            }

            // Approve the OO as spender on the reward token from the Adapter
            if (IERC20(rewardToken).allowance(address(this), address(optimisticOracle)) < reward) {
                IERC20(rewardToken).approve(address(optimisticOracle), type(uint256).max);
            }
        }

        // Send a price request to the Optimistic oracle
        optimisticOracle.requestPrice(
            YES_OR_NO_IDENTIFIER, requestTimestamp, ancillaryData, IERC20(rewardToken), reward
        );

        // Ensure the price request is event based
        optimisticOracle.setEventBased(YES_OR_NO_IDENTIFIER, requestTimestamp, ancillaryData);

        // Ensure that the dispute callback flag is set
        optimisticOracle.setCallbacks(
            YES_OR_NO_IDENTIFIER,
            requestTimestamp,
            ancillaryData,
            false, // DO NOT set callback on priceProposed
            true, // DO set callback on priceDisputed
            false // DO NOT set callback on priceSettled
        );

        // Update the proposal bond on the Optimistic oracle if necessary
        if (bond > 0) optimisticOracle.setBond(YES_OR_NO_IDENTIFIER, requestTimestamp, ancillaryData, bond);
        if (liveness > 0) {
            optimisticOracle.setCustomLiveness(YES_OR_NO_IDENTIFIER, requestTimestamp, ancillaryData, liveness);
        }
    }

    /// @notice Reset the question by updating the requestTimestamp field and sending a new price request to the OO
    /// @param questionID - The unique questionID
    function _reset(address requestor, bytes32 questionID, bool resetRefund, QuestionData storage questionData)
        internal
    {
        uint256 requestTimestamp = block.timestamp;
        // Update the question parameters in storage
        questionData.requestTimestamp = requestTimestamp;
        questionData.reset = true;
        if (resetRefund) questionData.refund = false;

        // Send out a new price request with the new timestamp
        _requestPrice(
            requestor,
            requestTimestamp,
            questionData.ancillaryData,
            questionData.rewardToken,
            questionData.reward,
            questionData.proposalBond,
            questionData.liveness
        );

        emit QuestionReset(questionID);
    }

    /// @notice Resolves the underlying CTF market
    /// @param questionID   - The unique questionID of the question
    /// @param questionData - The question data parameters
    function _resolve(bytes32 questionID, QuestionData storage questionData) internal {
        // Get the price from the OO
        int256 price = optimisticOracle.settleAndGetPrice(
            YES_OR_NO_IDENTIFIER, questionData.requestTimestamp, questionData.ancillaryData
        );

        // If the OO returns the ignore price, reset the question
        if (price == _ignorePrice()) return _reset(address(this), questionID, true, questionData);

        // Set resolved flag
        questionData.resolved = true;

        // If refund flag is set, this indicates that the question's reward now sits on the Adapter.
        // Refund the reward to the question creator on resolution
        if (questionData.refund) _refund(questionData);

        // Construct the payout array for the question
        uint256[] memory payouts = _constructPayouts(price);

        // Resolve the underlying CTF market
        ctf.reportPayouts(questionID, payouts);

        emit QuestionResolved(questionID, price, payouts);
    }

    function _hasPrice(QuestionData storage questionData) internal view returns (bool) {
        return optimisticOracle.hasPrice(
            address(this), YES_OR_NO_IDENTIFIER, questionData.requestTimestamp, questionData.ancillaryData
        );
    }

    function _refund(QuestionData storage questionData) internal {
        return TransferHelper._transfer(questionData.rewardToken, questionData.creator, questionData.reward);
    }

    function _isFlagged(QuestionData storage questionData) internal view returns (bool) {
        return questionData.manualResolutionTimestamp > 0;
    }

    function _isInitialized(QuestionData storage questionData) internal view returns (bool) {
        return questionData.ancillaryData.length > 0;
    }

    /// @notice Construct the payout array given the price
    /// @param price - The price retrieved from the OO
    function _constructPayouts(int256 price) internal pure returns (uint256[] memory) {
        // Payouts: [YES, NO]
        uint256[] memory payouts = new uint256[](2);
        // Valid prices are 0, 0.5 and 1
        if (price != 0 && price != 0.5 ether && price != 1 ether) revert InvalidOOPrice();

        if (price == 0) {
            // NO: Report [Yes, No] as [0, 1]
            payouts[0] = 0;
            payouts[1] = 1;
        } else if (price == 0.5 ether) {
            // UNKNOWN: Report [Yes, No] as [1, 1], 50/50
            // Note that a tie is not a valid outcome when used with the `NegRiskOperator`
            payouts[0] = 1;
            payouts[1] = 1;
        } else {
            // YES: Report [Yes, No] as [1, 0]
            payouts[0] = 1;
            payouts[1] = 0;
        }
        return payouts;
    }

    /// @notice Validates a payout array from the admin
    /// @param payouts - The payout array
    function _isValidPayoutArray(uint256[] calldata payouts) internal pure returns (bool) {
        return PayoutHelperLib.isValidPayoutArray(payouts);
    }

    function _ignorePrice() internal pure returns (int256) {
        return type(int256).min;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { IAuth } from "../interfaces/IAuth.sol";

/// @title Auth
/// @notice Provides access control modifiers
abstract contract Auth is IAuth {
    /// @notice Auth
    mapping(address => uint256) public admins;

    modifier onlyAdmin() {
        if (admins[msg.sender] != 1) revert NotAdmin();
        _;
    }

    constructor() {
        admins[msg.sender] = 1;
    }

    /// @notice Adds an Admin
    /// @param admin - The address of the admin
    function addAdmin(address admin) external onlyAdmin {
        admins[admin] = 1;
        emit NewAdmin(msg.sender, admin);
    }

    /// @notice Removes an admin
    /// @param admin - The address of the admin to be removed
    function removeAdmin(address admin) external onlyAdmin {
        admins[admin] = 0;
        emit RemovedAdmin(msg.sender, admin);
    }

    /// @notice Renounces Admin privileges from the caller
    function renounceAdmin() external onlyAdmin {
        admins[msg.sender] = 0;
        emit RemovedAdmin(msg.sender, msg.sender);
    }

    /// @notice Checks if an address is an admin
    /// @param addr - The address to be checked
    function isAdmin(address addr) external view returns (bool) {
        return admins[addr] == 1;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { IBulletinBoard, AncillaryDataUpdate } from "src/interfaces/IBulletinBoard.sol";

/// @title Bulletin Board
/// @notice A registry containing ancillary data updates
abstract contract BulletinBoard is IBulletinBoard {
    /// @notice Mapping to an array of Ancillary data updates for questions
    mapping(bytes32 => AncillaryDataUpdate[]) public updates;

    /// @notice Post an update for the question
    /// Anyone can post an update for any questionID, but users should only consider updates posted by the question creator
    /// @param questionID   - The unique questionID
    /// @param update       - The update for the question
    function postUpdate(bytes32 questionID, bytes memory update) external {
        bytes32 id = keccak256(abi.encode(questionID, msg.sender));
        updates[id].push(AncillaryDataUpdate({ timestamp: block.timestamp, update: update }));
        emit AncillaryDataUpdated(questionID, msg.sender, update);
    }

    /// @notice Gets all updates for a questionID and owner
    /// @param questionID   - The unique questionID
    /// @param owner        - The address of the question initializer
    function getUpdates(bytes32 questionID, address owner) public view returns (AncillaryDataUpdate[] memory) {
        return updates[keccak256(abi.encode(questionID, owner))];
    }

    /// @notice Gets the latest update for a questionID and owner
    /// @param questionID   - The unique questionID
    /// @param owner        - The address of the question initializer
    function getLatestUpdate(bytes32 questionID, address owner) external view returns (AncillaryDataUpdate memory) {
        AncillaryDataUpdate[] memory currentUpdates = getUpdates(questionID, owner);
        if (currentUpdates.length == 0) return AncillaryDataUpdate({ timestamp: 0, update: "" });
        return currentUpdates[currentUpdates.length - 1];
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { SafeTransferLib, ERC20 } from "lib/solmate/src/utils/SafeTransferLib.sol";

/// @title TransferHelper
/// @notice Helper library to transfer tokens
library TransferHelper {
    /// @notice Transfers tokens from the targeted address to the given destination
    /// @param token    - The contract address of the token to be transferred
    /// @param from     - The originating address from which the tokens will be transferred
    /// @param to       - The destination address of the transfer
    /// @param amount   - The amount to be transferred
    function _transferFromERC20(address token, address from, address to, uint256 amount) internal {
        SafeTransferLib.safeTransferFrom(ERC20(token), from, to, amount);
    }

    /// @notice Transfers tokens from the current address to the given destination
    /// @param token    - The contract address of the token to be transferred
    /// @param to       - The destination address of the transfer
    /// @param amount   - The amount to be transferred
    function _transfer(address token, address to, uint256 amount) internal {
        SafeTransferLib.safeTransfer(ERC20(token), to, amount);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

library PayoutHelperLib {

    function isValidPayoutArray(uint256[] memory payouts) internal pure returns (bool) {
        if (payouts.length != 2) return false;

        // Payout must be [0,1], [1,0] or [1,1]
        // if payout[0] is 1, payout[1] must be 0 or 1
        if ((payouts[0] == 1) && (payouts[1] == 0 || payouts[1] == 1)) {
            return true;
        }

        // If payout[0] is 0, payout[1] must be 1 
        if ((payouts[0] == 0) && (payouts[1] == 1)) {
            return true;
        }
        return false;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

library AncillaryDataLib {
    string private constant INITIALIZER_PREFIX = ",initializer:";

    /// @notice Appends the initializer address to the ancillaryData
    /// @param initializer      - The initializer address
    /// @param ancillaryData    - The ancillary data
    function _appendAncillaryData(address initializer, bytes memory ancillaryData)
        internal
        pure
        returns (bytes memory)
    {
        return abi.encodePacked(ancillaryData, INITIALIZER_PREFIX, _toUtf8BytesAddress(initializer));
    }

    /// @notice Returns a UTF8-encoded address
    /// Source: UMA Protocol's AncillaryDataLib
    /// https://github.com/UMAprotocol/protocol/blob/9967e70e7db3f262fde0dc9d89ea04d4cd11ed97/packages/core/contracts/common/implementation/AncillaryData.sol
    /// Will return address in all lower case characters and without the leading 0x.
    /// @param addr - The address to encode.
    function _toUtf8BytesAddress(address addr) internal pure returns (bytes memory) {
        return abi.encodePacked(
            _toUtf8Bytes32Bottom(bytes32(bytes20(addr)) >> 128), bytes8(_toUtf8Bytes32Bottom(bytes20(addr)))
        );
    }

    /// @notice 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);
        }
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

/**
 * @title Provides addresses of the live contracts implementing certain interfaces.
 * @dev Examples are the Oracle or Store interfaces.
 */
interface IFinder {
    /**
     * @notice Updates the address of the contract that implements `interfaceName`.
     * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.
     * @param implementationAddress address of the deployed contract that implements the interface.
     */
    function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;

    /**
     * @notice Gets the address of the contract that implements the given `interfaceName`.
     * @param interfaceName queried interface.
     * @return implementationAddress address of the deployed contract that implements the interface.
     */
    function getImplementationAddress(bytes32 interfaceName) external view returns (address);
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

interface IAddressWhitelist {
    function addToWhitelist(address) external;

    function removeFromWhitelist(address) external;

    function isOnWhitelist(address) external view returns (bool);

    function getWhitelist() external view returns (address[] memory);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { IERC20 } from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

interface IConditionalTokens {
    /// Mapping key is an condition ID. Value represents numerators of the payout vector associated with the condition. This array is initialized with a length equal to the outcome slot count. E.g. Condition with 3 outcomes [A, B, C] and two of those correct [0.5, 0.5, 0]. In Ethereum there are no decimal values, so here, 0.5 is represented by fractions like 1/2 == 0.5. That's why we need numerator and denominator values. Payout numerators are also used as a check of initialization. If the numerators array is empty (has length zero), the condition was not created/prepared. See getOutcomeSlotCount.
    function payoutNumerators(bytes32) external returns (uint256[] memory);

    /// Denominator is also used for checking if the condition has been resolved. If the denominator is non-zero, then the condition has been resolved.
    function payoutDenominator(bytes32) external returns (uint256);

    /// @dev This function prepares a condition by initializing a payout vector associated with the condition.
    /// @param oracle The account assigned to report the result for the prepared condition.
    /// @param questionId An identifier for the question to be answered by the oracle.
    /// @param outcomeSlotCount The number of outcome slots which should be used for this condition. Must not exceed 256.
    function prepareCondition(address oracle, bytes32 questionId, uint256 outcomeSlotCount) external;

    /// @dev Called by the oracle for reporting results of conditions. Will set the payout vector for the condition with the ID ``keccak256(abi.encodePacked(oracle, questionId, outcomeSlotCount))``, where oracle is the message sender, questionId is one of the parameters of this function, and outcomeSlotCount is the length of the payouts parameter, which contains the payoutNumerators for each outcome slot of the condition.
    /// @param questionId The question ID the oracle is answering for
    /// @param payouts The oracle's answer
    function reportPayouts(bytes32 questionId, uint256[] calldata payouts) external;

    /// @dev This function splits a position. If splitting from the collateral, this contract will attempt to transfer `amount` collateral from the message sender to itself. Otherwise, this contract will burn `amount` stake held by the message sender in the position being split worth of EIP 1155 tokens. Regardless, if successful, `amount` stake will be minted in the split target positions. If any of the transfers, mints, or burns fail, the transaction will revert. The transaction will also revert if the given partition is trivial, invalid, or refers to more slots than the condition is prepared with.
    /// @param collateralToken The address of the positions' backing collateral token.
    /// @param parentCollectionId The ID of the outcome collections common to the position being split and the split target positions. May be null, in which only the collateral is shared.
    /// @param conditionId The ID of the condition to split on.
    /// @param partition An array of disjoint index sets representing a nontrivial partition of the outcome slots of the given condition. E.g. A|B and C but not A|B and B|C (is not disjoint). Each element's a number which, together with the condition, represents the outcome collection. E.g. 0b110 is A|B, 0b010 is B, etc.
    /// @param amount The amount of collateral or stake to split.
    function splitPosition(
        IERC20 collateralToken,
        bytes32 parentCollectionId,
        bytes32 conditionId,
        uint256[] calldata partition,
        uint256 amount
    ) external;

    function mergePositions(
        IERC20 collateralToken,
        bytes32 parentCollectionId,
        bytes32 conditionId,
        uint256[] calldata partition,
        uint256 amount
    ) external;

    function redeemPositions(
        IERC20 collateralToken,
        bytes32 parentCollectionId,
        bytes32 conditionId,
        uint256[] calldata indexSets
    ) external;

    /// @dev Gets the outcome slot count of a condition.
    /// @param conditionId ID of the condition.
    /// @return Number of outcome slots associated with a condition, or zero if condition has not been prepared yet.
    function getOutcomeSlotCount(bytes32 conditionId) external view returns (uint256);

    /// @dev Constructs a condition ID from an oracle, a question ID, and the outcome slot count for the question.
    /// @param oracle The account assigned to report the result for the prepared condition.
    /// @param questionId An identifier for the question to be answered by the oracle.
    /// @param outcomeSlotCount The number of outcome slots which should be used for this condition. Must not exceed 256.
    function getConditionId(address oracle, bytes32 questionId, uint256 outcomeSlotCount)
        external
        pure
        returns (bytes32);

    /// @dev Constructs an outcome collection ID from a parent collection and an outcome collection.
    /// @param parentCollectionId Collection ID of the parent outcome collection, or bytes32(0) if there's no parent.
    /// @param conditionId Condition ID of the outcome collection to combine with the parent outcome collection.
    /// @param indexSet Index set of the outcome collection to combine with the parent outcome collection.
    function getCollectionId(bytes32 parentCollectionId, bytes32 conditionId, uint256 indexSet)
        external
        view
        returns (bytes32);

    /// @dev Constructs a position ID from a collateral token and an outcome collection. These IDs are used as the ERC-1155 ID for this contract.
    /// @param collateralToken Collateral token which backs the position.
    /// @param collectionId ID of the outcome collection associated with this position.
    function getPositionId(IERC20 collateralToken, bytes32 collectionId) external pure returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

struct RequestSettings {
    bool eventBased; // True if the request is set to be event-based.
    bool refundOnDispute; // True if the requester should be refunded their reward on dispute.
    bool callbackOnPriceProposed; // True if callbackOnPriceProposed callback is required.
    bool callbackOnPriceDisputed; // True if callbackOnPriceDisputed callback is required.
    bool callbackOnPriceSettled; // True if callbackOnPriceSettled callback is required.
    uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.
    uint256 customLiveness; // Custom liveness value set by the requester.
}

// Struct representing a price request.
struct Request {
    address proposer; // Address of the proposer.
    address disputer; // Address of the disputer.
    IERC20 currency; // ERC20 token used to pay rewards and fees.
    bool settled; // True if the request is settled.
    RequestSettings requestSettings; // Custom settings associated with a request.
    int256 proposedPrice; // Price that the proposer submitted.
    int256 resolvedPrice; // Price resolved once the request is settled.
    uint256 expirationTime; // Time at which the request auto-settles without a dispute.
    uint256 reward; // Amount of the currency to pay to the proposer on settlement.
    uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.
}

/// @title Optimistic Oracle V2 Interface
interface IOptimisticOracleV2 {
    /// @notice Requests a new price.
    /// @param identifier price identifier being requested.
    /// @param timestamp timestamp of the price being requested.
    /// @param ancillaryData ancillary data representing additional args being passed with the price request.
    /// @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
    /// @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,
    ///               which could make sense if the contract requests and proposes the value in the same call or
    ///               provides its own reward system.
    /// @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.
    /// This can be changed with a subsequent call to setBond().
    function requestPrice(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        IERC20 currency,
        uint256 reward
    ) external returns (uint256 totalBond);

    /// @notice Proposes a price value for an existing price request.
    /// @param requester sender of the initial price request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @param proposedPrice price being proposed.
    /// @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to
    /// the proposer once settled if the proposal is correct.
    function proposePrice(
        address requester,
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        int256 proposedPrice
    ) external returns (uint256 totalBond);

    /// @notice Disputes a price value for an existing price request with an active proposal.
    /// @param requester sender of the initial price request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to
    /// the disputer once settled if the dispute was valid (the proposal was incorrect).
    function disputePrice(address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData)
        external
        returns (uint256 totalBond);

    /// @notice Set the proposal bond associated with a price request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @param bond custom bond amount to set.
    /// @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be
    /// changed again with a subsequent call to setBond().
    function setBond(bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 bond)
        external
        returns (uint256 totalBond);

    /// @notice Sets the request to be an "event-based" request.
    /// @dev Calling this method has a few impacts on the request:
    ///
    /// 1. The timestamp at which the request is evaluated is the time of the proposal, not the timestamp associated
    ///    with the request.
    ///
    /// 2. The proposer cannot propose the "too early" value (TOO_EARLY_RESPONSE). This is to ensure that a proposer who
    ///    prematurely proposes a response loses their bond.
    ///
    /// 3. RefundoOnDispute is automatically set, meaning disputes trigger the reward to be automatically refunded to
    ///    the requesting contract.
    ///
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    function setEventBased(bytes32 identifier, uint256 timestamp, bytes memory ancillaryData) external;

    /// @notice Sets which callbacks should be enabled for the request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @param callbackOnPriceProposed whether to enable the callback onPriceProposed.
    /// @param callbackOnPriceDisputed whether to enable the callback onPriceDisputed.
    /// @param callbackOnPriceSettled whether to enable the callback onPriceSettled.
    function setCallbacks(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        bool callbackOnPriceProposed,
        bool callbackOnPriceDisputed,
        bool callbackOnPriceSettled
    ) external;

    /// @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before
    /// being auto-resolved.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @param customLiveness new custom liveness.
    function setCustomLiveness(
        bytes32 identifier,
        uint256 timestamp,
        bytes memory ancillaryData,
        uint256 customLiveness
    ) external;

    /// @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.
    /// @param requester sender of the initial price request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes
    /// the returned bonds as well as additional rewards.
    function settle(address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData)
        external
        returns (uint256 payout);

    /// @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled
    /// or settleable. Note: this method is not view so that this call may actually settle the price request if it
    /// hasn't been settled.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @return resolved price.
    ////
    function settleAndGetPrice(bytes32 identifier, uint256 timestamp, bytes memory ancillaryData)
        external
        returns (int256);

    /// @notice Gets the current data structure containing all information about a price request.
    /// @param requester sender of the initial price request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @return the Request data structure.
    ////
    function getRequest(address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData)
        external
        view
        returns (Request memory);

    /// @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).
    /// @param requester sender of the initial price request.
    /// @param identifier price identifier to identify the existing request.
    /// @param timestamp timestamp to identify the existing request.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @return true if price has resolved or settled, false otherwise.
    function hasPrice(address requester, bytes32 identifier, uint256 timestamp, bytes memory ancillaryData)
        external
        view
        returns (bool);

    function defaultLiveness() external view returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

/// @title Optimistic Requester
interface IOptimisticRequester {
    /// @notice Callback for disputes.
    /// @param identifier price identifier being requested.
    /// @param timestamp timestamp of the price being requested.
    /// @param ancillaryData ancillary data of the price being requested.
    /// @param refund refund received in the case that refundOnDispute was enabled.
    function priceDisputed(bytes32 identifier, uint256 timestamp, bytes memory ancillaryData, uint256 refund)
        external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

struct QuestionData {
    /// @notice Request timestamp, set when a request is made to the Optimistic Oracle
    /// @dev Used to identify the request and NOT used by the DVM to determine validity
    uint256 requestTimestamp;
    /// @notice Reward offered to a successful proposer
    uint256 reward;
    /// @notice Additional bond required by Optimistic oracle proposers/disputers
    uint256 proposalBond;
    /// @notice Custom liveness period
    uint256 liveness;
    /// @notice Manual resolution timestamp, set when a market is flagged for manual resolution
    uint256 manualResolutionTimestamp;
    /// @notice Flag marking whether a question is resolved
    bool resolved;
    /// @notice Flag marking whether a question is paused
    bool paused;
    /// @notice Flag marking whether a question has been reset. A question can only be reset once
    bool reset;
    /// @notice Flag marking whether a question's reward should be refunded.
    bool refund;
    /// @notice ERC20 token address used for payment of rewards, proposal bonds and fees
    address rewardToken;
    /// @notice The address of the question creator
    address creator;
    /// @notice Data used to resolve a condition
    bytes ancillaryData;
}

interface IUmaCtfAdapterEE {
    error NotInitialized();
    error NotFlagged();
    error NotReadyToResolve();
    error Resolved();
    error Initialized();
    error UnsupportedToken();
    error Flagged();
    error Paused();
    error SafetyPeriodPassed();
    error SafetyPeriodNotPassed();
    error PriceNotAvailable();
    error InvalidAncillaryData();
    error NotOptimisticOracle();
    error InvalidOOPrice();
    error InvalidPayouts();

    /// @notice Emitted when a questionID is initialized
    event QuestionInitialized(
        bytes32 indexed questionID,
        uint256 indexed requestTimestamp,
        address indexed creator,
        bytes ancillaryData,
        address rewardToken,
        uint256 reward,
        uint256 proposalBond
    );

    /// @notice Emitted when a question is paused by an authorized user
    event QuestionPaused(bytes32 indexed questionID);

    /// @notice Emitted when a question is unpaused by an authorized user
    event QuestionUnpaused(bytes32 indexed questionID);

    /// @notice Emitted when a question is flagged by an admin for manual resolution
    event QuestionFlagged(bytes32 indexed questionID);

    /// @notice Emitted when a question is unflagged by an admin
    event QuestionUnflagged(bytes32 indexed questionID);

    /// @notice Emitted when a question is reset
    event QuestionReset(bytes32 indexed questionID);

    /// @notice Emitted when a question is resolved
    event QuestionResolved(bytes32 indexed questionID, int256 indexed settledPrice, uint256[] payouts);

    /// @notice Emitted when a question is manually resolved
    event QuestionManuallyResolved(bytes32 indexed questionID, uint256[] payouts);
}

interface IUmaCtfAdapter is IUmaCtfAdapterEE {
    function initialize(
        bytes memory ancillaryData,
        address rewardToken,
        uint256 reward,
        uint256 proposalBond,
        uint256 liveness
    ) external returns (bytes32);

    function ready(bytes32 questionID) external view returns (bool);

    function resolve(bytes32 questionID) external;

    function flag(bytes32 questionID) external;

    function reset(bytes32 questionID) external;

    function pause(bytes32 questionID) external;

    function unpause(bytes32 questionID) external;

    function getQuestion(bytes32 questionID) external returns (QuestionData memory);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

interface IAuthEE {
    error NotAdmin();

    /// @notice Emitted when a new admin is added
    event NewAdmin(address indexed admin, address indexed newAdminAddress);

    /// @notice Emitted when an admin is removed
    event RemovedAdmin(address indexed admin, address indexed removedAdmin);
}

interface IAuth is IAuthEE {
    function isAdmin(address) external view returns (bool);

    function addAdmin(address) external;

    function removeAdmin(address) external;

    function renounceAdmin() external;
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

struct AncillaryDataUpdate {
    uint256 timestamp;
    bytes update;
}

interface IBulletinBoardEE {
    /// @notice Emitted when an ancillary data update is posted
    event AncillaryDataUpdated(bytes32 indexed questionID, address indexed owner, bytes update);
}

interface IBulletinBoard is IBulletinBoardEE {
    function postUpdate(bytes32 questionID, bytes memory update) external;

    function getUpdates(bytes32 questionID, address owner) external view returns (AncillaryDataUpdate[] memory);

    function getLatestUpdate(bytes32 questionID, address owner) external view returns (AncillaryDataUpdate memory);
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_ctf","type":"address"},{"internalType":"address","name":"_finder","type":"address"},{"internalType":"address","name":"_oo","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Flagged","type":"error"},{"inputs":[],"name":"Initialized","type":"error"},{"inputs":[],"name":"InvalidAncillaryData","type":"error"},{"inputs":[],"name":"InvalidOOPrice","type":"error"},{"inputs":[],"name":"InvalidPayouts","type":"error"},{"inputs":[],"name":"NotAdmin","type":"error"},{"inputs":[],"name":"NotFlagged","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"NotOptimisticOracle","type":"error"},{"inputs":[],"name":"NotReadyToResolve","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"PriceNotAvailable","type":"error"},{"inputs":[],"name":"Resolved","type":"error"},{"inputs":[],"name":"SafetyPeriodNotPassed","type":"error"},{"inputs":[],"name":"SafetyPeriodPassed","type":"error"},{"inputs":[],"name":"UnsupportedToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes","name":"update","type":"bytes"}],"name":"AncillaryDataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdminAddress","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"QuestionFlagged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"requestTimestamp","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"indexed":false,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"proposalBond","type":"uint256"}],"name":"QuestionInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"payouts","type":"uint256[]"}],"name":"QuestionManuallyResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"QuestionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"QuestionReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"},{"indexed":true,"internalType":"int256","name":"settledPrice","type":"int256"},{"indexed":false,"internalType":"uint256[]","name":"payouts","type":"uint256[]"}],"name":"QuestionResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"QuestionUnflagged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"QuestionUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":true,"internalType":"address","name":"removedAdmin","type":"address"}],"name":"RemovedAdmin","type":"event"},{"inputs":[],"name":"MAX_ANCILLARY_DATA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFETY_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YES_OR_NO_IDENTIFIER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralWhitelist","outputs":[{"internalType":"contract IAddressWhitelist","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ctf","outputs":[{"internalType":"contract IConditionalTokens","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"flag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"getExpectedPayouts","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"getLatestUpdate","outputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"update","type":"bytes"}],"internalType":"struct AncillaryDataUpdate","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"getQuestion","outputs":[{"components":[{"internalType":"uint256","name":"requestTimestamp","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"proposalBond","type":"uint256"},{"internalType":"uint256","name":"liveness","type":"uint256"},{"internalType":"uint256","name":"manualResolutionTimestamp","type":"uint256"},{"internalType":"bool","name":"resolved","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bool","name":"reset","type":"bool"},{"internalType":"bool","name":"refund","type":"bool"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"internalType":"struct QuestionData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"getUpdates","outputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"update","type":"bytes"}],"internalType":"struct AncillaryDataUpdate[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"proposalBond","type":"uint256"},{"internalType":"uint256","name":"liveness","type":"uint256"}],"name":"initialize","outputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"isFlagged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optimisticOracle","outputs":[{"internalType":"contract IOptimisticOracleV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"},{"internalType":"bytes","name":"update","type":"bytes"}],"name":"postUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"priceDisputed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"questions","outputs":[{"internalType":"uint256","name":"requestTimestamp","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"proposalBond","type":"uint256"},{"internalType":"uint256","name":"liveness","type":"uint256"},{"internalType":"uint256","name":"manualResolutionTimestamp","type":"uint256"},{"internalType":"bool","name":"resolved","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bool","name":"reset","type":"bool"},{"internalType":"bool","name":"refund","type":"bool"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"ready","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"reset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"resolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"},{"internalType":"uint256[]","name":"payouts","type":"uint256[]"}],"name":"resolveManually","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"unflag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"questionID","type":"bytes32"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"updates","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"update","type":"bytes"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b506040516200415438038062004154833981016040819052620000349162000115565b3360009081526020819052604090819020600190556001600160a01b0384811660805282811660a05290516302abf57960e61b81527f436f6c6c61746572616c57686974656c697374000000000000000000000000006004820152839182169063aafd5e4090602401602060405180830381865afa158015620000bb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e191906200015f565b6001600160a01b031660c052506200018492505050565b80516001600160a01b03811681146200011057600080fd5b919050565b6000806000606084860312156200012b57600080fd5b6200013684620000f8565b92506200014660208501620000f8565b91506200015660408501620000f8565b90509250925092565b6000602082840312156200017257600080fd5b6200017d82620000f8565b9392505050565b60805160a05160c051613f376200021d600039600081816104b301526108270152600081816102450152818161062601528181610ceb0152818161221a015281816122d3015281816123ad0152818161248b015281816125510152818161262c0152818161270f015281816127e30152612a04015260008181610291015281816109ca015281816115f40152612b6a0152613f376000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80637048027511610104578063bf2dde38116100a2578063ed3c7d4011610071578063ed3c7d40146104d5578063ed56531a146104e8578063f7b637bb146104fb578063fcac49a21461050e57600080fd5b8063bf2dde3814610472578063c0cab0a214610485578063d1dfb2e9146104a5578063e4ee614a146104ae57600080fd5b806388697de4116100de57806388697de41461040b57806389ab08711461041e5780638bad0c0a1461043f57806395addb901461044757600080fd5b806370480275146103d257806378165a48146103e557806380696d85146103f857600080fd5b806327f8feac1161017c578063555c56fc1161014b578063555c56fc1461035857806358c039cd146103785780635c23bdf5146103985780636c66f07d146103ab57600080fd5b806327f8feac146102fc5780632f4dae9f1461030557806334e5e28e14610318578063429b62e51461033857600080fd5b8063185d1646116101b8578063185d16461461021a578063223029221461024057806322a9339f1461028c57806324d7806c146102b357600080fd5b8063072d1259146101df5780630d8f2372146101f45780631785f53c14610207575b600080fd5b6101f26101ed366004613289565b610521565b005b6101f26102023660046132d0565b61060e565b6101f261021536600461334a565b610744565b61022d610228366004613367565b6107df565b6040519081526020015b60405180910390f35b6102677f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610237565b6102677f000000000000000000000000000000000000000000000000000000000000000081565b6102ec6102c136600461334a565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460011490565b6040519015158152602001610237565b61022d611fcb81565b6101f26103133660046133d1565b610aab565b61032b6103263660046133d1565b610b9a565b6040516102379190613425565b61022d61034636600461334a565b60006020819052908152604090205481565b61036b610366366004613438565b610da0565b60405161023791906134fd565b61038b6103863660046133d1565b610ef7565b604051610237919061357d565b6101f26103a63660046133d1565b6110e9565b61022d7f5945535f4f525f4e4f5f5155455259000000000000000000000000000000000081565b6101f26103e036600461334a565b611206565b6101f26103f33660046133d1565b6112a2565b6101f261040636600461366a565b611421565b6101f26104193660046133d1565b61169f565b61043161042c3660046136e9565b61184c565b60405161023792919061370b565b6101f2611915565b61045a6104553660046133d1565b611999565b6040516102379c9b9a99989796959493929190613724565b6102ec6104803660046133d1565b611aab565b610498610493366004613438565b611ac4565b60405161023791906137cb565b61022d610e1081565b6102677f000000000000000000000000000000000000000000000000000000000000000081565b6101f26104e33660046133d1565b611b4d565b6101f26104f63660046133d1565b611c4c565b6102ec6105093660046133d1565b611d7e565b6102ec61051c3660046133d1565b611d95565b60408051602081018490523391810191909152600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012060008181526001808452848220868601909552428652858401888152855480830187559583529390912085516002909502019384559151909450908201906105b89082613877565b5050503373ffffffffffffffffffffffffffffffffffffffff16837e59e11815211969c0c4aaf3f498b52b6c2f2d14f286275d0862d70de22a836b846040516106019190613991565b60405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461067d576040517f05cef85500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151602080840191909120600081815260029092526040909120600581015460ff16156106e6576005810154600682015460018301546106df9273ffffffffffffffffffffffffffffffffffffffff6401000000009091048116921690611dac565b505061073e565b600581015462010000900460ff161561072e5760050180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1663010000001790555061073e565b61073b3083600084611dbc565b50505b50505050565b3360009081526020819052604090205460011461078d576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152602081905260408082208290555133917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a350565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690633a3ab67290602401602060405180830381865afa158015610870573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089491906139b9565b6108ca576040517f6a17288200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108d63388611f1d565b90508651600014806108ea5750611fcb8151115b15610921576040517f9702d51200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8080519060200120915061094660026000848152602001908152602001600020611f88565b1561097d576040517f5daa87a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4261098e338484848b8b8b8b611fa4565b6040517fd96ee75400000000000000000000000000000000000000000000000000000000815230600482015260248101849052600260448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d96ee75490606401600060405180830381600087803b158015610a2357600080fd5b505af1158015610a37573d6000803e3d6000fd5b50505050610a4a3382848a8a8a8a6121a8565b3373ffffffffffffffffffffffffffffffffffffffff1681847feee0897acd6893adcaf2ba5158191b3601098ab6bece35c5d57874340b64c5b7858b8b8b604051610a9894939291906139d4565b60405180910390a4505095945050505050565b33600090815260208190526040902054600114610af4576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600260205260409020610b0b81611f88565b610b41576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405182907f92d28918c5574e7fc0f4f948c39502682c81cfb4089b07b83f95b3264e5e5e0690600090a25050565b6000818152600260205260409020606090610bb481611f88565b610bea576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015415610c26576040517fe8e3a25900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810154610100900460ff1615610c6a576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c73816127a1565b610ca9576040517f579a480100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546040517fa9904f9b00000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163a9904f9b91610d479130917f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000916007890190600401613ab4565b61020060405180830381865afa158015610d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d899190613ba9565b60c001519050610d9881612880565b949350505050565b6060600160008484604051602001610dd892919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b604051602081830303815290604052805190602001208152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610eea578382906000526020600020906002020160405180604001604052908160008201548152602001600182018054610e59906137de565b80601f0160208091040260200160405190810160405280929190818152602001828054610e85906137de565b8015610ed25780601f10610ea757610100808354040283529160200191610ed2565b820191906000526020600020905b815481529060010190602001808311610eb557829003601f168201915b50505050508152505081526020019060010190610e1c565b5050505090505b92915050565b610f8f6040518061018001604052806000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600015158152602001600015158152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b6000828152600260208181526040928390208351610180810185528154815260018201549281019290925291820154928101929092526003810154606083015260048101546080830152600581015460ff808216151560a08501526101008083048216151560c08601526201000083048216151560e08601526301000000830490911615159084015273ffffffffffffffffffffffffffffffffffffffff640100000000909104811661012084015260068201541661014083015260078101805461016084019190611060906137de565b80601f016020809104026020016040519081016040528092919081815260200182805461108c906137de565b80156110d95780601f106110ae576101008083540402835291602001916110d9565b820191906000526020600020905b8154815290600101906020018083116110bc57829003601f168201915b5050505050815250509050919050565b600081815260026020526040902061110081611f88565b611136576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810154610100900460ff161561117a576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff16156111b9576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111c2816127a1565b6111f8576040517fb488fe4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61120282826129c2565b5050565b3360009081526020819052604090205460011461124f576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116600081815260208190526040808220600190555133917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a350565b336000908152602081905260409020546001146112eb576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020526040902061130281611f88565b611338576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015415611374576040517fe8e3a25900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff16156113b3576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113bf610e1042613c83565b60048201556005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560405182907f2435a0347185933b12027c6f394a5fd9c03646dba233e956f50658719dfc0b3590600090a25050565b3360009081526020819052604090205460011461146a576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526002602052604090206114828383612c12565b6114b8576040517f663493a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114c181611f88565b6114f7576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810154611532576040517fbb825d1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060040154421015611570576040517f2a2c257c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190556301000000900460ff16156115b7576115b781612c57565b6040517fc49298ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c49298ac9061162d90879087908790600401613cea565b600060405180830381600087803b15801561164757600080fd5b505af115801561165b573d6000803e3d6000fd5b50505050837f5909815fe7fe0a550d5fcb95fbf33821b580521d3c97089c6ce12808d1cd05668484604051611691929190613d0d565b60405180910390a250505050565b336000908152602081905260409020546001146116e8576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526002602052604090206116ff81611f88565b611735576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810154611770576040517fbb825d1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff16156117af576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600401544211156117ed576040517fab0bf2ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600482018190556005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405183917f052435bc04fc49113a7bfd9198a92c0852ca622a621800f6da66d4b29b786c0591a25050565b6001602052816000526040600020818154811061186857600080fd5b906000526020600020906002020160009150915050806000015490806001018054611892906137de565b80601f01602080910402602001604051908101604052809291908181526020018280546118be906137de565b801561190b5780601f106118e05761010080835404028352916020019161190b565b820191906000526020600020905b8154815290600101906020018083116118ee57829003601f168201915b5050505050905082565b3360009081526020819052604090205460011461195e576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152602081905260408082208290555182917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a3565b60026020819052600091825260409091208054600182015492820154600383015460048401546005850154600686015460078701805496989795969495939460ff808516956101008604821695620100008104831695630100000082049093169464010000000090910473ffffffffffffffffffffffffffffffffffffffff90811694931692611a28906137de565b80601f0160208091040260200160405190810160405280929190818152602001828054611a54906137de565b8015611aa15780601f10611a7657610100808354040283529160200191611aa1565b820191906000526020600020905b815481529060010190602001808311611a8457829003601f168201915b505050505090508c565b6000818152600260205260408120600401541515610ef1565b6040805180820190915260008152606060208201526000611ae58484610da0565b90508051600003611b1d5760405180604001604052806000815260200160405180602001604052806000815250815250915050610ef1565b8060018251611b2c9190613d21565b81518110611b3c57611b3c613d38565b602002602001015191505092915050565b33600090815260208190526040902054600114611b96576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600260205260409020611bad81611f88565b611be3576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff1615611c22576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60058101546301000000900460ff1615611c3f57611c3f81612c57565b6112023383600184611dbc565b33600090815260208190526040902054600114611c95576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600260205260409020611cac81611f88565b611ce2576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff1615611d21576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560405182907f6ded7250a9d5f79aef5add44600fc20a74a0af6f4730baa4fc4ab87bf484b81290600090a25050565b6000818152600260205260408120610ef190611f88565b6000818152600260205260408120610ef190612c95565b611db7838383612ce4565b505050565b428082556005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff16620100001790558215611e20576005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1690555b611eeb8582846007018054611e34906137de565b80601f0160208091040260200160405190810160405280929190818152602001828054611e60906137de565b8015611ead5780601f10611e8257610100808354040283529160200191611ead565b820191906000526020600020905b815481529060010190602001808311611e9057829003601f168201915b50505050508560050160049054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660010154876002015488600301546121a8565b60405184907f7981b5832932948db4e32a4a16a0f44b2ce7ff088574afb9364b313f70f82e8f90600090a25050505050565b6060816040518060400160405280600d81526020017f2c696e697469616c697a65723a00000000000000000000000000000000000000815250611f5f85612da2565b604051602001611f7193929190613d67565b604051602081830303815290604052905092915050565b600080826007018054611f9a906137de565b9050119050919050565b604051806101800160405280868152602001848152602001838152602001828152602001600081526020016000151581526020016000151581526020016000151581526020016000151581526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff1681526020018781525060026000898152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a08201518160050160006101000a81548160ff02191690831515021790555060c08201518160050160016101000a81548160ff02191690831515021790555060e08201518160050160026101000a81548160ff0219169083151502179055506101008201518160050160036101000a81548160ff0219169083151502179055506101208201518160050160046101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101408201518160060160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061016082015181600701908161219b9190613877565b5050505050505050505050565b82156123705773ffffffffffffffffffffffffffffffffffffffff871630146121d7576121d784883086612e30565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116602483015284919086169063dd62ed3e90604401602060405180830381865afa15801561226c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122909190613daa565b1015612370576040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602483015285169063095ea7b3906044016020604051808303816000875af115801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e91906139b9565b505b6040517f11df92f100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906311df92f19061240a907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a908a908a90600401613dc3565b6020604051808303816000875af1158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d9190613daa565b506040517f120698af00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063120698af906124e4907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a90600401613e0c565b600060405180830381600087803b1580156124fe57600080fd5b505af1158015612512573d6000803e3d6000fd5b50506040517ff327b07500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016925063f327b07591506125b4907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a906000906001908290600401613e2b565b600060405180830381600087803b1580156125ce57600080fd5b505af11580156125e2573d6000803e3d6000fd5b5050505060008211156126cc576040517fad5a755a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063ad5a755a90612687907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a908890600401613e6a565b6020604051808303816000875af11580156126a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ca9190613daa565b505b8015612798576040517f473c45fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063473c45fe9061276a907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a908790600401613e6a565b600060405180830381600087803b15801561278457600080fd5b505af115801561219b573d6000803e3d6000fd5b50505050505050565b80546040517fbc58ccaa00000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163bc58ccaa9161283f9130917f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000916007890190600401613ab4565b602060405180830381865afa15801561285c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef191906139b9565b6040805160028082526060808301845292600092919060208301908036833701905050905082158015906128bc5750826706f05b59d3b2000014155b80156128d0575082670de0b6b3a764000014155b15612907576040517f86c9649e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036129565760008160008151811061292457612924613d38565b60200260200101818152505060018160018151811061294557612945613d38565b602002602001018181525050610ef1565b826706f05b59d3b200000361297a5760018160008151811061292457612924613d38565b60018160008151811061298f5761298f613d38565b6020026020010181815250506000816001815181106129b0576129b0613d38565b60200260200101818152505092915050565b80546040517f53b5923900000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016916353b5923991612a5f917f5945535f4f525f4e4f5f5155455259000000000000000000000000000000000091906007880190600401613e9a565b6020604051808303816000875af1158015612a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa29190613daa565b90507f80000000000000000000000000000000000000000000000000000000000000008103612ad857611db73084600185611dbc565b6005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190556301000000900460ff1615612b1f57612b1f82612c57565b6000612b2a82612880565b6040517fc49298ac00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c49298ac90612ba19087908590600401613eb9565b600060405180830381600087803b158015612bbb57600080fd5b505af1158015612bcf573d6000803e3d6000fd5b5050505081847f566c3fbdd12dd86bb341787f6d531f79fd7ad4ce7e3ae2d15ac0ca1b601af9df83604051612c049190613425565b60405180910390a350505050565b6000612c50838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612e3c92505050565b9392505050565b600581015460068201546001830154612c929273ffffffffffffffffffffffffffffffffffffffff6401000000009091048116921690611dac565b50565b6000612ca082611f88565b612cac57506000919050565b6005820154610100900460ff1615612cc657506000919050565b600582015460ff1615612cdb57506000919050565b610ef1826127a1565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061073e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064015b60405180910390fd5b6060612dc36fffffffffffffffffffffffffffffffff602084901c16612f1d565b612dde8360601b6bffffffffffffffffffffffff1916612f1d565b604051602001612e1a9291909182527fffffffffffffffff00000000000000000000000000000000000000000000000016602082015260280190565b6040516020818303038152906040529050919050565b61073e848484846130bf565b60008151600214612e4f57506000919050565b81600081518110612e6257612e62613d38565b60200260200101516001148015612eb7575081600181518110612e8757612e87613d38565b602002602001015160001480612eb7575081600181518110612eab57612eab613d38565b60200260200101516001145b15612ec457506001919050565b81600081518110612ed757612ed7613d38565b60200260200101516000148015612f08575081600181518110612efc57612efc613d38565b60200260200101516001145b15612f1557506001919050565b506000919050565b6000808260001c9050806fffffffffffffffffffffffffffffffff169050806801000000000000000002811777ffffffffffffffff0000000000000000ffffffffffffffff169050806401000000000281177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16905080620100000281177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff169050806101000281177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff1690508060100281177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16905060006008827f0808080808080808080808080808080808080808080808080808080808080808168161304157613041613ed2565b0460047f040404040404040404040404040404040404040404040404040404040404040484160460027f020202020202020202020202020202020202020202020202020202020202020285160417166027029091017f3030303030303030303030303030303030303030303030303030303030303030019392505050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061317e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401612d99565b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156131d8576131d8613185565b60405290565b600082601f8301126131ef57600080fd5b813567ffffffffffffffff8082111561320a5761320a613185565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561325057613250613185565b8160405283815286602085880101111561326957600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561329c57600080fd5b82359150602083013567ffffffffffffffff8111156132ba57600080fd5b6132c6858286016131de565b9150509250929050565b600080600080608085870312156132e657600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561330b57600080fd5b613317878288016131de565b949793965093946060013593505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612c9257600080fd5b60006020828403121561335c57600080fd5b8135612c5081613328565b600080600080600060a0868803121561337f57600080fd5b853567ffffffffffffffff81111561339657600080fd5b6133a2888289016131de565b95505060208601356133b381613328565b94979496505050506040830135926060810135926080909101359150565b6000602082840312156133e357600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561341a578151875295820195908201906001016133fe565b509495945050505050565b602081526000612c5060208301846133ea565b6000806040838503121561344b57600080fd5b82359150602083013561345d81613328565b809150509250929050565b60005b8381101561348357818101518382015260200161346b565b8381111561073e5750506000910152565b600081518084526134ac816020860160208601613468565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805182526000602082015160406020850152610d986040850182613494565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613570577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261355e8583516134de565b94509285019290850190600101613524565b5092979650505050505050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a0820152600060a08301516135c560c084018215159052565b5060c083015180151560e08401525060e08301516101006135e98185018315159052565b84015190506101206135fe8482018315159052565b84015190506101406136278482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101606136508482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101529050610d986101a0840182613494565b60008060006040848603121561367f57600080fd5b83359250602084013567ffffffffffffffff8082111561369e57600080fd5b818601915086601f8301126136b257600080fd5b8135818111156136c157600080fd5b8760208260051b85010111156136d657600080fd5b6020830194508093505050509250925092565b600080604083850312156136fc57600080fd5b50508035926020909101359150565b828152604060208201526000610d986040830184613494565b60006101808e83528d60208401528c60408401528b60608401528a608084015289151560a084015288151560c084015287151560e084015286151561010084015273ffffffffffffffffffffffffffffffffffffffff86166101208401526137a561014084018673ffffffffffffffffffffffffffffffffffffffff169052565b806101608401526137b881840185613494565b9f9e505050505050505050505050505050565b602081526000612c5060208301846134de565b600181811c908216806137f257607f821691505b60208210810361382b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115611db757600081815260208120601f850160051c810160208610156138585750805b601f850160051c820191505b8181101561073b57828155600101613864565b815167ffffffffffffffff81111561389157613891613185565b6138a58161389f84546137de565b84613831565b602080601f8311600181146138f857600084156138c25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561073b565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561394557888601518255948401946001909101908401613926565b508582101561398157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000612c506020830184613494565b805180151581146139b457600080fd5b919050565b6000602082840312156139cb57600080fd5b612c50826139a4565b6080815260006139e76080830187613494565b73ffffffffffffffffffffffffffffffffffffffff959095166020830152506040810192909252606090910152919050565b60008154613a26816137de565b808552602060018381168015613a435760018114613a7b57613aa9565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550613aa9565b866000528260002060005b85811015613aa15781548a8201860152908301908401613a86565b890184019650505b505050505092915050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613aef6080830184613a19565b9695505050505050565b80516139b481613328565b600060e08284031215613b1657600080fd5b60405160e0810181811067ffffffffffffffff82111715613b3957613b39613185565b604052905080613b48836139a4565b8152613b56602084016139a4565b6020820152613b67604084016139a4565b6040820152613b78606084016139a4565b6060820152613b89608084016139a4565b608082015260a083015160a082015260c083015160c08201525092915050565b60006102008284031215613bbc57600080fd5b613bc46131b4565b613bcd83613af9565b8152613bdb60208401613af9565b6020820152613bec60408401613af9565b6040820152613bfd606084016139a4565b6060820152613c0f8460808501613b04565b608082015261016083015160a082015261018083015160c08201526101a083015160e08201526101c08301516101008201526101e09092015161012083015250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115613c9657613c96613c54565b500190565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613ccd57600080fd5b8260051b8083602087013760009401602001938452509192915050565b838152604060208201526000613d04604083018486613c9b565b95945050505050565b602081526000610d98602083018486613c9b565b600082821015613d3357613d33613c54565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008451613d79818460208901613468565b845190830190613d8d818360208901613468565b8451910190613da0818360208801613468565b0195945050505050565b600060208284031215613dbc57600080fd5b5051919050565b85815284602082015260a060408201526000613de260a0830186613494565b73ffffffffffffffffffffffffffffffffffffffff94909416606083015250608001529392505050565b838152826020820152606060408201526000613d046060830184613494565b86815285602082015260c060408201526000613e4a60c0830187613494565b9415156060830152509115156080830152151560a0909101529392505050565b848152836020820152608060408201526000613e896080830185613494565b905082606083015295945050505050565b838152826020820152606060408201526000613d046060830184613a19565b828152604060208201526000610d9860408301846133ea565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea26469706673582212203daeab65c5c432054355e435a5cc15b094855e2349c1a5f22dfdc0fbc73dc4f164736f6c634300080f00330000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604500000000000000000000000009aea4b2242abc8bb4bb78d537a67a245a7bec640000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101da5760003560e01c80637048027511610104578063bf2dde38116100a2578063ed3c7d4011610071578063ed3c7d40146104d5578063ed56531a146104e8578063f7b637bb146104fb578063fcac49a21461050e57600080fd5b8063bf2dde3814610472578063c0cab0a214610485578063d1dfb2e9146104a5578063e4ee614a146104ae57600080fd5b806388697de4116100de57806388697de41461040b57806389ab08711461041e5780638bad0c0a1461043f57806395addb901461044757600080fd5b806370480275146103d257806378165a48146103e557806380696d85146103f857600080fd5b806327f8feac1161017c578063555c56fc1161014b578063555c56fc1461035857806358c039cd146103785780635c23bdf5146103985780636c66f07d146103ab57600080fd5b806327f8feac146102fc5780632f4dae9f1461030557806334e5e28e14610318578063429b62e51461033857600080fd5b8063185d1646116101b8578063185d16461461021a578063223029221461024057806322a9339f1461028c57806324d7806c146102b357600080fd5b8063072d1259146101df5780630d8f2372146101f45780631785f53c14610207575b600080fd5b6101f26101ed366004613289565b610521565b005b6101f26102023660046132d0565b61060e565b6101f261021536600461334a565b610744565b61022d610228366004613367565b6107df565b6040519081526020015b60405180910390f35b6102677f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b181565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610237565b6102677f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604581565b6102ec6102c136600461334a565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460011490565b6040519015158152602001610237565b61022d611fcb81565b6101f26103133660046133d1565b610aab565b61032b6103263660046133d1565b610b9a565b6040516102379190613425565b61022d61034636600461334a565b60006020819052908152604090205481565b61036b610366366004613438565b610da0565b60405161023791906134fd565b61038b6103863660046133d1565b610ef7565b604051610237919061357d565b6101f26103a63660046133d1565b6110e9565b61022d7f5945535f4f525f4e4f5f5155455259000000000000000000000000000000000081565b6101f26103e036600461334a565b611206565b6101f26103f33660046133d1565b6112a2565b6101f261040636600461366a565b611421565b6101f26104193660046133d1565b61169f565b61043161042c3660046136e9565b61184c565b60405161023792919061370b565b6101f2611915565b61045a6104553660046133d1565b611999565b6040516102379c9b9a99989796959493929190613724565b6102ec6104803660046133d1565b611aab565b610498610493366004613438565b611ac4565b60405161023791906137cb565b61022d610e1081565b6102677f0000000000000000000000001020ae36548ab28bc0c41fd2a08d24132c82cc5581565b6101f26104e33660046133d1565b611b4d565b6101f26104f63660046133d1565b611c4c565b6102ec6105093660046133d1565b611d7e565b6102ec61051c3660046133d1565b611d95565b60408051602081018490523391810191909152600090606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012060008181526001808452848220868601909552428652858401888152855480830187559583529390912085516002909502019384559151909450908201906105b89082613877565b5050503373ffffffffffffffffffffffffffffffffffffffff16837e59e11815211969c0c4aaf3f498b52b6c2f2d14f286275d0862d70de22a836b846040516106019190613991565b60405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1161461067d576040517f05cef85500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151602080840191909120600081815260029092526040909120600581015460ff16156106e6576005810154600682015460018301546106df9273ffffffffffffffffffffffffffffffffffffffff6401000000009091048116921690611dac565b505061073e565b600581015462010000900460ff161561072e5760050180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1663010000001790555061073e565b61073b3083600084611dbc565b50505b50505050565b3360009081526020819052604090205460011461078d576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152602081905260408082208290555133917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a350565b6040517f3a3ab67200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000917f0000000000000000000000001020ae36548ab28bc0c41fd2a08d24132c82cc5590911690633a3ab67290602401602060405180830381865afa158015610870573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089491906139b9565b6108ca576040517f6a17288200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108d63388611f1d565b90508651600014806108ea5750611fcb8151115b15610921576040517f9702d51200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8080519060200120915061094660026000848152602001908152602001600020611f88565b1561097d576040517f5daa87a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4261098e338484848b8b8b8b611fa4565b6040517fd96ee75400000000000000000000000000000000000000000000000000000000815230600482015260248101849052600260448201527f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff169063d96ee75490606401600060405180830381600087803b158015610a2357600080fd5b505af1158015610a37573d6000803e3d6000fd5b50505050610a4a3382848a8a8a8a6121a8565b3373ffffffffffffffffffffffffffffffffffffffff1681847feee0897acd6893adcaf2ba5158191b3601098ab6bece35c5d57874340b64c5b7858b8b8b604051610a9894939291906139d4565b60405180910390a4505095945050505050565b33600090815260208190526040902054600114610af4576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600260205260409020610b0b81611f88565b610b41576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405182907f92d28918c5574e7fc0f4f948c39502682c81cfb4089b07b83f95b3264e5e5e0690600090a25050565b6000818152600260205260409020606090610bb481611f88565b610bea576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015415610c26576040517fe8e3a25900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810154610100900460ff1615610c6a576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c73816127a1565b610ca9576040517f579a480100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546040517fa9904f9b00000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1169163a9904f9b91610d479130917f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000916007890190600401613ab4565b61020060405180830381865afa158015610d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d899190613ba9565b60c001519050610d9881612880565b949350505050565b6060600160008484604051602001610dd892919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b604051602081830303815290604052805190602001208152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610eea578382906000526020600020906002020160405180604001604052908160008201548152602001600182018054610e59906137de565b80601f0160208091040260200160405190810160405280929190818152602001828054610e85906137de565b8015610ed25780601f10610ea757610100808354040283529160200191610ed2565b820191906000526020600020905b815481529060010190602001808311610eb557829003601f168201915b50505050508152505081526020019060010190610e1c565b5050505090505b92915050565b610f8f6040518061018001604052806000815260200160008152602001600081526020016000815260200160008152602001600015158152602001600015158152602001600015158152602001600015158152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b6000828152600260208181526040928390208351610180810185528154815260018201549281019290925291820154928101929092526003810154606083015260048101546080830152600581015460ff808216151560a08501526101008083048216151560c08601526201000083048216151560e08601526301000000830490911615159084015273ffffffffffffffffffffffffffffffffffffffff640100000000909104811661012084015260068201541661014083015260078101805461016084019190611060906137de565b80601f016020809104026020016040519081016040528092919081815260200182805461108c906137de565b80156110d95780601f106110ae576101008083540402835291602001916110d9565b820191906000526020600020905b8154815290600101906020018083116110bc57829003601f168201915b5050505050815250509050919050565b600081815260026020526040902061110081611f88565b611136576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810154610100900460ff161561117a576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff16156111b9576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111c2816127a1565b6111f8576040517fb488fe4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61120282826129c2565b5050565b3360009081526020819052604090205460011461124f576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116600081815260208190526040808220600190555133917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a350565b336000908152602081905260409020546001146112eb576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020526040902061130281611f88565b611338576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015415611374576040517fe8e3a25900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff16156113b3576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113bf610e1042613c83565b60048201556005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560405182907f2435a0347185933b12027c6f394a5fd9c03646dba233e956f50658719dfc0b3590600090a25050565b3360009081526020819052604090205460011461146a576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526002602052604090206114828383612c12565b6114b8576040517f663493a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114c181611f88565b6114f7576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810154611532576040517fbb825d1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060040154421015611570576040517f2a2c257c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190556301000000900460ff16156115b7576115b781612c57565b6040517fc49298ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045169063c49298ac9061162d90879087908790600401613cea565b600060405180830381600087803b15801561164757600080fd5b505af115801561165b573d6000803e3d6000fd5b50505050837f5909815fe7fe0a550d5fcb95fbf33821b580521d3c97089c6ce12808d1cd05668484604051611691929190613d0d565b60405180910390a250505050565b336000908152602081905260409020546001146116e8576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526002602052604090206116ff81611f88565b611735576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810154611770576040517fbb825d1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff16156117af576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600401544211156117ed576040517fab0bf2ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600482018190556005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405183917f052435bc04fc49113a7bfd9198a92c0852ca622a621800f6da66d4b29b786c0591a25050565b6001602052816000526040600020818154811061186857600080fd5b906000526020600020906002020160009150915050806000015490806001018054611892906137de565b80601f01602080910402602001604051908101604052809291908181526020018280546118be906137de565b801561190b5780601f106118e05761010080835404028352916020019161190b565b820191906000526020600020905b8154815290600101906020018083116118ee57829003601f168201915b5050505050905082565b3360009081526020819052604090205460011461195e576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152602081905260408082208290555182917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a3565b60026020819052600091825260409091208054600182015492820154600383015460048401546005850154600686015460078701805496989795969495939460ff808516956101008604821695620100008104831695630100000082049093169464010000000090910473ffffffffffffffffffffffffffffffffffffffff90811694931692611a28906137de565b80601f0160208091040260200160405190810160405280929190818152602001828054611a54906137de565b8015611aa15780601f10611a7657610100808354040283529160200191611aa1565b820191906000526020600020905b815481529060010190602001808311611a8457829003601f168201915b505050505090508c565b6000818152600260205260408120600401541515610ef1565b6040805180820190915260008152606060208201526000611ae58484610da0565b90508051600003611b1d5760405180604001604052806000815260200160405180602001604052806000815250815250915050610ef1565b8060018251611b2c9190613d21565b81518110611b3c57611b3c613d38565b602002602001015191505092915050565b33600090815260208190526040902054600114611b96576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600260205260409020611bad81611f88565b611be3576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff1615611c22576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60058101546301000000900460ff1615611c3f57611c3f81612c57565b6112023383600184611dbc565b33600090815260208190526040902054600114611c95576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600260205260409020611cac81611f88565b611ce2576040517f87138d5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015460ff1615611d21576040517fea00f1a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905560405182907f6ded7250a9d5f79aef5add44600fc20a74a0af6f4730baa4fc4ab87bf484b81290600090a25050565b6000818152600260205260408120610ef190611f88565b6000818152600260205260408120610ef190612c95565b611db7838383612ce4565b505050565b428082556005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff16620100001790558215611e20576005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1690555b611eeb8582846007018054611e34906137de565b80601f0160208091040260200160405190810160405280929190818152602001828054611e60906137de565b8015611ead5780601f10611e8257610100808354040283529160200191611ead565b820191906000526020600020905b815481529060010190602001808311611e9057829003601f168201915b50505050508560050160049054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660010154876002015488600301546121a8565b60405184907f7981b5832932948db4e32a4a16a0f44b2ce7ff088574afb9364b313f70f82e8f90600090a25050505050565b6060816040518060400160405280600d81526020017f2c696e697469616c697a65723a00000000000000000000000000000000000000815250611f5f85612da2565b604051602001611f7193929190613d67565b604051602081830303815290604052905092915050565b600080826007018054611f9a906137de565b9050119050919050565b604051806101800160405280868152602001848152602001838152602001828152602001600081526020016000151581526020016000151581526020016000151581526020016000151581526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff1681526020018781525060026000898152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a08201518160050160006101000a81548160ff02191690831515021790555060c08201518160050160016101000a81548160ff02191690831515021790555060e08201518160050160026101000a81548160ff0219169083151502179055506101008201518160050160036101000a81548160ff0219169083151502179055506101208201518160050160046101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101408201518160060160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061016082015181600701908161219b9190613877565b5050505050505050505050565b82156123705773ffffffffffffffffffffffffffffffffffffffff871630146121d7576121d784883086612e30565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b18116602483015284919086169063dd62ed3e90604401602060405180830381865afa15801561226c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122909190613daa565b1015612370576040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1811660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602483015285169063095ea7b3906044016020604051808303816000875af115801561234a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061236e91906139b9565b505b6040517f11df92f100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b116906311df92f19061240a907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a908a908a90600401613dc3565b6020604051808303816000875af1158015612429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061244d9190613daa565b506040517f120698af00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1169063120698af906124e4907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a90600401613e0c565b600060405180830381600087803b1580156124fe57600080fd5b505af1158015612512573d6000803e3d6000fd5b50506040517ff327b07500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b116925063f327b07591506125b4907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a906000906001908290600401613e2b565b600060405180830381600087803b1580156125ce57600080fd5b505af11580156125e2573d6000803e3d6000fd5b5050505060008211156126cc576040517fad5a755a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1169063ad5a755a90612687907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a908890600401613e6a565b6020604051808303816000875af11580156126a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ca9190613daa565b505b8015612798576040517f473c45fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1169063473c45fe9061276a907f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000908a908a908790600401613e6a565b600060405180830381600087803b15801561278457600080fd5b505af115801561219b573d6000803e3d6000fd5b50505050505050565b80546040517fbc58ccaa00000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1169163bc58ccaa9161283f9130917f5945535f4f525f4e4f5f51554552590000000000000000000000000000000000916007890190600401613ab4565b602060405180830381865afa15801561285c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef191906139b9565b6040805160028082526060808301845292600092919060208301908036833701905050905082158015906128bc5750826706f05b59d3b2000014155b80156128d0575082670de0b6b3a764000014155b15612907576040517f86c9649e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036129565760008160008151811061292457612924613d38565b60200260200101818152505060018160018151811061294557612945613d38565b602002602001018181525050610ef1565b826706f05b59d3b200000361297a5760018160008151811061292457612924613d38565b60018160008151811061298f5761298f613d38565b6020026020010181815250506000816001815181106129b0576129b0613d38565b60200260200101818152505092915050565b80546040517f53b5923900000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b116916353b5923991612a5f917f5945535f4f525f4e4f5f5155455259000000000000000000000000000000000091906007880190600401613e9a565b6020604051808303816000875af1158015612a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa29190613daa565b90507f80000000000000000000000000000000000000000000000000000000000000008103612ad857611db73084600185611dbc565b6005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117908190556301000000900460ff1615612b1f57612b1f82612c57565b6000612b2a82612880565b6040517fc49298ac00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045169063c49298ac90612ba19087908590600401613eb9565b600060405180830381600087803b158015612bbb57600080fd5b505af1158015612bcf573d6000803e3d6000fd5b5050505081847f566c3fbdd12dd86bb341787f6d531f79fd7ad4ce7e3ae2d15ac0ca1b601af9df83604051612c049190613425565b60405180910390a350505050565b6000612c50838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612e3c92505050565b9392505050565b600581015460068201546001830154612c929273ffffffffffffffffffffffffffffffffffffffff6401000000009091048116921690611dac565b50565b6000612ca082611f88565b612cac57506000919050565b6005820154610100900460ff1615612cc657506000919050565b600582015460ff1615612cdb57506000919050565b610ef1826127a1565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061073e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064015b60405180910390fd5b6060612dc36fffffffffffffffffffffffffffffffff602084901c16612f1d565b612dde8360601b6bffffffffffffffffffffffff1916612f1d565b604051602001612e1a9291909182527fffffffffffffffff00000000000000000000000000000000000000000000000016602082015260280190565b6040516020818303038152906040529050919050565b61073e848484846130bf565b60008151600214612e4f57506000919050565b81600081518110612e6257612e62613d38565b60200260200101516001148015612eb7575081600181518110612e8757612e87613d38565b602002602001015160001480612eb7575081600181518110612eab57612eab613d38565b60200260200101516001145b15612ec457506001919050565b81600081518110612ed757612ed7613d38565b60200260200101516000148015612f08575081600181518110612efc57612efc613d38565b60200260200101516001145b15612f1557506001919050565b506000919050565b6000808260001c9050806fffffffffffffffffffffffffffffffff169050806801000000000000000002811777ffffffffffffffff0000000000000000ffffffffffffffff169050806401000000000281177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff16905080620100000281177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff169050806101000281177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff1690508060100281177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f16905060006008827f0808080808080808080808080808080808080808080808080808080808080808168161304157613041613ed2565b0460047f040404040404040404040404040404040404040404040404040404040404040484160460027f020202020202020202020202020202020202020202020202020202020202020285160417166027029091017f3030303030303030303030303030303030303030303030303030303030303030019392505050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061317e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401612d99565b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff811182821017156131d8576131d8613185565b60405290565b600082601f8301126131ef57600080fd5b813567ffffffffffffffff8082111561320a5761320a613185565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561325057613250613185565b8160405283815286602085880101111561326957600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561329c57600080fd5b82359150602083013567ffffffffffffffff8111156132ba57600080fd5b6132c6858286016131de565b9150509250929050565b600080600080608085870312156132e657600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561330b57600080fd5b613317878288016131de565b949793965093946060013593505050565b73ffffffffffffffffffffffffffffffffffffffff81168114612c9257600080fd5b60006020828403121561335c57600080fd5b8135612c5081613328565b600080600080600060a0868803121561337f57600080fd5b853567ffffffffffffffff81111561339657600080fd5b6133a2888289016131de565b95505060208601356133b381613328565b94979496505050506040830135926060810135926080909101359150565b6000602082840312156133e357600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561341a578151875295820195908201906001016133fe565b509495945050505050565b602081526000612c5060208301846133ea565b6000806040838503121561344b57600080fd5b82359150602083013561345d81613328565b809150509250929050565b60005b8381101561348357818101518382015260200161346b565b8381111561073e5750506000910152565b600081518084526134ac816020860160208601613468565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805182526000602082015160406020850152610d986040850182613494565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613570577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261355e8583516134de565b94509285019290850190600101613524565b5092979650505050505050565b6020815281516020820152602082015160408201526040820151606082015260608201516080820152608082015160a0820152600060a08301516135c560c084018215159052565b5060c083015180151560e08401525060e08301516101006135e98185018315159052565b84015190506101206135fe8482018315159052565b84015190506101406136278482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101606136508482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101529050610d986101a0840182613494565b60008060006040848603121561367f57600080fd5b83359250602084013567ffffffffffffffff8082111561369e57600080fd5b818601915086601f8301126136b257600080fd5b8135818111156136c157600080fd5b8760208260051b85010111156136d657600080fd5b6020830194508093505050509250925092565b600080604083850312156136fc57600080fd5b50508035926020909101359150565b828152604060208201526000610d986040830184613494565b60006101808e83528d60208401528c60408401528b60608401528a608084015289151560a084015288151560c084015287151560e084015286151561010084015273ffffffffffffffffffffffffffffffffffffffff86166101208401526137a561014084018673ffffffffffffffffffffffffffffffffffffffff169052565b806101608401526137b881840185613494565b9f9e505050505050505050505050505050565b602081526000612c5060208301846134de565b600181811c908216806137f257607f821691505b60208210810361382b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115611db757600081815260208120601f850160051c810160208610156138585750805b601f850160051c820191505b8181101561073b57828155600101613864565b815167ffffffffffffffff81111561389157613891613185565b6138a58161389f84546137de565b84613831565b602080601f8311600181146138f857600084156138c25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561073b565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561394557888601518255948401946001909101908401613926565b508582101561398157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000612c506020830184613494565b805180151581146139b457600080fd5b919050565b6000602082840312156139cb57600080fd5b612c50826139a4565b6080815260006139e76080830187613494565b73ffffffffffffffffffffffffffffffffffffffff959095166020830152506040810192909252606090910152919050565b60008154613a26816137de565b808552602060018381168015613a435760018114613a7b57613aa9565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550613aa9565b866000528260002060005b85811015613aa15781548a8201860152908301908401613a86565b890184019650505b505050505092915050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613aef6080830184613a19565b9695505050505050565b80516139b481613328565b600060e08284031215613b1657600080fd5b60405160e0810181811067ffffffffffffffff82111715613b3957613b39613185565b604052905080613b48836139a4565b8152613b56602084016139a4565b6020820152613b67604084016139a4565b6040820152613b78606084016139a4565b6060820152613b89608084016139a4565b608082015260a083015160a082015260c083015160c08201525092915050565b60006102008284031215613bbc57600080fd5b613bc46131b4565b613bcd83613af9565b8152613bdb60208401613af9565b6020820152613bec60408401613af9565b6040820152613bfd606084016139a4565b6060820152613c0f8460808501613b04565b608082015261016083015160a082015261018083015160c08201526101a083015160e08201526101c08301516101008201526101e09092015161012083015250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115613c9657613c96613c54565b500190565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613ccd57600080fd5b8260051b8083602087013760009401602001938452509192915050565b838152604060208201526000613d04604083018486613c9b565b95945050505050565b602081526000610d98602083018486613c9b565b600082821015613d3357613d33613c54565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008451613d79818460208901613468565b845190830190613d8d818360208901613468565b8451910190613da0818360208801613468565b0195945050505050565b600060208284031215613dbc57600080fd5b5051919050565b85815284602082015260a060408201526000613de260a0830186613494565b73ffffffffffffffffffffffffffffffffffffffff94909416606083015250608001529392505050565b838152826020820152606060408201526000613d046060830184613494565b86815285602082015260c060408201526000613e4a60c0830187613494565b9415156060830152509115156080830152151560a0909101529392505050565b848152836020820152608060408201526000613e896080830185613494565b905082606083015295945050505050565b838152826020820152606060408201526000613d046060830184613a19565b828152604060208201526000610d9860408301846133ea565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea26469706673582212203daeab65c5c432054355e435a5cc15b094855e2349c1a5f22dfdc0fbc73dc4f164736f6c634300080f0033

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

0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604500000000000000000000000009aea4b2242abc8bb4bb78d537a67a245a7bec640000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1

-----Decoded View---------------
Arg [0] : _ctf (address): 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
Arg [1] : _finder (address): 0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64
Arg [2] : _oo (address): 0x2C0367a9DB231dDeBd88a94b4f6461a6e47C58B1

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045
Arg [1] : 00000000000000000000000009aea4b2242abc8bb4bb78d537a67a245a7bec64
Arg [2] : 0000000000000000000000002c0367a9db231ddebd88a94b4f6461a6e47c58b1


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.