POL Price: $0.699998 (+0.76%)
 

Overview

POL Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 POL

POL Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Merge Positions651815422024-12-07 5:42:2127 secs ago1733550141IN
0xd91E80cF...D0dA35296
0 POL0.0068877328.58633184
Merge Positions651814832024-12-07 5:40:152 mins ago1733550015IN
0xd91E80cF...D0dA35296
0 POL0.006871428.57050011
Split Position651811752024-12-07 5:28:0414 mins ago1733549284IN
0xd91E80cF...D0dA35296
0 POL0.0067018926.21000006
Split Position651807742024-12-07 5:13:5228 mins ago1733548432IN
0xd91E80cF...D0dA35296
0 POL0.0066039226.21000004
Merge Positions651805102024-12-07 5:04:1638 mins ago1733547856IN
0xd91E80cF...D0dA35296
0 POL0.0050703526.19000003
Split Position651804602024-12-07 5:02:3040 mins ago1733547750IN
0xd91E80cF...D0dA35296
0 POL0.0069571626.19000003
Merge Positions651803422024-12-07 4:58:2044 mins ago1733547500IN
0xd91E80cF...D0dA35296
0 POL0.0059948126.19000002
Merge Positions651803112024-12-07 4:57:1445 mins ago1733547434IN
0xd91E80cF...D0dA35296
0 POL0.0050705926.19000002
Split Position651788512024-12-07 4:05:281 hr ago1733544328IN
0xd91E80cF...D0dA35296
0 POL0.0066458625.99088078
Merge Positions651781212024-12-07 3:38:152 hrs ago1733542695IN
0xd91E80cF...D0dA35296
0 POL0.0059474625.99338107
Merge Positions651779172024-12-07 3:30:172 hrs ago1733542217IN
0xd91E80cF...D0dA35296
0 POL0.0047289725.9999589
Split Position651777832024-12-07 3:25:332 hrs ago1733541933IN
0xd91E80cF...D0dA35296
0 POL0.0066494526.00492436
Split Position651777792024-12-07 3:25:252 hrs ago1733541925IN
0xd91E80cF...D0dA35296
0 POL0.0063474926.00333581
Split Position651777572024-12-07 3:24:372 hrs ago1733541877IN
0xd91E80cF...D0dA35296
0 POL0.0072633426.00441244
Merge Positions651767042024-12-07 2:43:012 hrs ago1733539381IN
0xd91E80cF...D0dA35296
0 POL0.0068296530
Merge Positions651761822024-12-07 2:23:163 hrs ago1733538196IN
0xd91E80cF...D0dA35296
0 POL0.0049482625.55000029
Merge Positions651746772024-12-07 1:26:404 hrs ago1733534800IN
0xd91E80cF...D0dA35296
0 POL0.0065458834
Merge Positions651746462024-12-07 1:25:344 hrs ago1733534734IN
0xd91E80cF...D0dA35296
0 POL0.0054065232
Split Position651744302024-12-07 1:17:224 hrs ago1733534242IN
0xd91E80cF...D0dA35296
0 POL0.0065622628.49924444
Split Position651742982024-12-07 1:12:184 hrs ago1733533938IN
0xd91E80cF...D0dA35296
0 POL0.0065622628.49924433
Split Position651742912024-12-07 1:12:044 hrs ago1733533924IN
0xd91E80cF...D0dA35296
0 POL0.0072915328.49924432
Merge Positions651738982024-12-07 0:57:354 hrs ago1733533055IN
0xd91E80cF...D0dA35296
0 POL0.0051835528.49924454
Merge Positions651738892024-12-07 0:57:174 hrs ago1733533037IN
0xd91E80cF...D0dA35296
0 POL0.0065208228.49924456
Merge Positions651724002024-12-07 0:02:245 hrs ago1733529744IN
0xd91E80cF...D0dA35296
0 POL0.0054565230.00000004
Merge Positions651720152024-12-06 23:48:165 hrs ago1733528896IN
0xd91E80cF...D0dA35296
0 POL0.0068644830.00000002
View all transactions

Latest 4 internal transactions

Parent Transaction Hash Block From To
636863852024-10-30 20:22:5537 days ago1730319775
0xd91E80cF...D0dA35296
1 wei
636863052024-10-30 20:20:0537 days ago1730319605
0xd91E80cF...D0dA35296
1 wei
636422572024-10-29 18:05:5738 days ago1730225157
0xd91E80cF...D0dA35296
1 wei
505054032023-11-28 20:27:46374 days ago1701203266
0xd91E80cF...D0dA35296
 Contract Creation0 POL
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NegRiskAdapter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion
File 1 of 13 : NegRiskAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {ERC1155TokenReceiver} from "lib/solmate/src/tokens/ERC1155.sol";
import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "lib/solmate/src/utils/SafeTransferLib.sol";
import {WrappedCollateral} from "src/WrappedCollateral.sol";
import {MarketData, MarketStateManager, IMarketStateManagerEE} from "src/modules/MarketDataManager.sol";
import {CTHelpers} from "src/libraries/CTHelpers.sol";
import {Helpers} from "src/libraries/Helpers.sol";
import {NegRiskIdLib} from "src/libraries/NegRiskIdLib.sol";
import {IConditionalTokens} from "src/interfaces/IConditionalTokens.sol";
import {Auth} from "src/modules/Auth.sol";
import {IAuthEE} from "src/modules/interfaces/IAuth.sol";

/// @title INegRiskAdapterEE
/// @notice NegRiskAdapter Errors and Events
interface INegRiskAdapterEE is IMarketStateManagerEE, IAuthEE {
    error InvalidIndexSet();
    error LengthMismatch();
    error UnexpectedCollateralToken();
    error NoConvertiblePositions();
    error NotApprovedForAll();

    event MarketPrepared(bytes32 indexed marketId, address indexed oracle, uint256 feeBips, bytes data);
    event QuestionPrepared(bytes32 indexed marketId, bytes32 indexed questionId, uint256 index, bytes data);
    event OutcomeReported(bytes32 indexed marketId, bytes32 indexed questionId, bool outcome);
    event PositionSplit(address indexed stakeholder, bytes32 indexed conditionId, uint256 amount);
    event PositionsMerge(address indexed stakeholder, bytes32 indexed conditionId, uint256 amount);
    event PositionsConverted(
        address indexed stakeholder, bytes32 indexed marketId, uint256 indexed indexSet, uint256 amount
    );
    event PayoutRedemption(address indexed redeemer, bytes32 indexed conditionId, uint256[] amounts, uint256 payout);
}

/// @title NegRiskAdapter
/// @notice Adapter for the CTF enabling the linking of a set binary markets where only one can resolve true
/// @notice The adapter prevents more than one question in the same multi-outcome market from resolving true
/// @notice And the adapter allows for the conversion of a set of no positions, to collateral plus the set of
/// complementary yes positions
/// @author Mike Shrieve ([email protected])
contract NegRiskAdapter is ERC1155TokenReceiver, MarketStateManager, INegRiskAdapterEE, Auth {
    using SafeTransferLib for ERC20;

    /*//////////////////////////////////////////////////////////////
                                 STATE
    //////////////////////////////////////////////////////////////*/

    IConditionalTokens public immutable ctf;
    ERC20 public immutable col;
    WrappedCollateral public immutable wcol;
    address public immutable vault;

    address public constant NO_TOKEN_BURN_ADDRESS = address(bytes20(bytes32(keccak256("NO_TOKEN_BURN_ADDRESS"))));
    uint256 public constant FEE_DENOMINATOR = 10_000;

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

    /// @param _ctf        - ConditionalTokens address
    /// @param _collateral - collateral address
    constructor(address _ctf, address _collateral, address _vault) {
        ctf = IConditionalTokens(_ctf);
        col = ERC20(_collateral);
        vault = _vault;

        wcol = new WrappedCollateral(_collateral, col.decimals());
        // approve the ctf to transfer wcol on our behalf
        wcol.approve(_ctf, type(uint256).max);
        // approve wcol to transfer collateral on our behalf
        col.approve(address(wcol), type(uint256).max);
    }

    /*//////////////////////////////////////////////////////////////
                                  IDS
    //////////////////////////////////////////////////////////////*/

    /// @notice Returns the conditionId for a given questionId
    /// @param _questionId  - the questionId
    /// @return conditionId - the corresponding conditionId
    function getConditionId(bytes32 _questionId) public view returns (bytes32) {
        return CTHelpers.getConditionId(
            address(this), // oracle
            _questionId,
            2 // outcomeCount
        );
    }

    /// @notice Returns the positionId for a given questionId and outcome
    /// @param _questionId  - the questionId
    /// @param _outcome     - the boolean outcome
    /// @return positionId  - the corresponding positionId
    function getPositionId(bytes32 _questionId, bool _outcome) public view returns (uint256) {
        bytes32 collectionId = CTHelpers.getCollectionId(
            bytes32(0),
            getConditionId(_questionId),
            _outcome ? 1 : 2 // 1 (0b01) is yes, 2 (0b10) is no
        );

        uint256 positionId = CTHelpers.getPositionId(address(wcol), collectionId);
        return positionId;
    }

    /*//////////////////////////////////////////////////////////////
                             SPLIT POSITION
    //////////////////////////////////////////////////////////////*/

    /// @notice Splits collateral to a complete set of conditional tokens for a single question
    /// @notice This function signature is the same as the CTF's splitPosition
    /// @param _collateralToken - the collateral token, must be the same as the adapter's collateral token
    /// @param _conditionId - the conditionId for the question
    /// @param _amount - the amount of collateral to split
    function splitPosition(address _collateralToken, bytes32, bytes32 _conditionId, uint256[] calldata, uint256 _amount)
        external
    {
        if (_collateralToken != address(col)) revert UnexpectedCollateralToken();
        splitPosition(_conditionId, _amount);
    }

    /// @notice Splits collateral to a complete set of conditional tokens for a single question
    /// @param _conditionId - the conditionId for the question
    /// @param _amount      - the amount of collateral to split
    function splitPosition(bytes32 _conditionId, uint256 _amount) public {
        col.safeTransferFrom(msg.sender, address(this), _amount);
        wcol.wrap(address(this), _amount);
        ctf.splitPosition(address(wcol), bytes32(0), _conditionId, Helpers.partition(), _amount);
        ctf.safeBatchTransferFrom(
            address(this), msg.sender, Helpers.positionIds(address(wcol), _conditionId), Helpers.values(2, _amount), ""
        );

        emit PositionSplit(msg.sender, _conditionId, _amount);
    }

    /*//////////////////////////////////////////////////////////////
                            MERGE POSITIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Merges a complete set of conditional tokens for a single question to collateral
    /// @notice This function signature is the same as the CTF's mergePositions
    /// @param _collateralToken - the collateral token, must be the same as the adapter's collateral token
    /// @param _conditionId     - the conditionId for the question
    /// @param _amount          - the amount of collateral to merge
    function mergePositions(
        address _collateralToken,
        bytes32,
        bytes32 _conditionId,
        uint256[] calldata,
        uint256 _amount
    ) external {
        if (_collateralToken != address(col)) revert UnexpectedCollateralToken();
        mergePositions(_conditionId, _amount);
    }

    /// @notice Merges a complete set of conditional tokens for a single question to collateral
    /// @param _conditionId - the conditionId for the question
    /// @param _amount      - the amount of collateral to merge
    function mergePositions(bytes32 _conditionId, uint256 _amount) public {
        uint256[] memory positionIds = Helpers.positionIds(address(wcol), _conditionId);

        // get conditional tokens from sender
        ctf.safeBatchTransferFrom(msg.sender, address(this), positionIds, Helpers.values(2, _amount), "");
        ctf.mergePositions(address(wcol), bytes32(0), _conditionId, Helpers.partition(), _amount);
        wcol.unwrap(msg.sender, _amount);

        emit PositionsMerge(msg.sender, _conditionId, _amount);
    }

    /*//////////////////////////////////////////////////////////////
                           ERC1155 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Proxies ERC1155 balanceOf to the CTF
    /// @param _owner   - the owner of the tokens
    /// @param _id      - the positionId
    /// @return balance - the owner's balance
    function balanceOf(address _owner, uint256 _id) external view returns (uint256) {
        return ctf.balanceOf(_owner, _id);
    }

    /// @notice Proxies ERC1155 balanceOfBatch to the CTF
    /// @param _owners   - the owners of the tokens
    /// @param _ids      - the positionIds
    /// @return balances - the owners' balances
    function balanceOfBatch(address[] memory _owners, uint256[] memory _ids) external view returns (uint256[] memory) {
        return ctf.balanceOfBatch(_owners, _ids);
    }

    /// @notice Proxies ERC1155 safeTransferFrom to the CTF
    /// @notice Can only be called by an admin
    /// @notice Requires this contract to be approved for all
    /// @notice Requires the sender to be approved for all
    /// @param _from  - the owner of the tokens
    /// @param _to    - the recipient of the tokens
    /// @param _id    - the positionId
    /// @param _value - the amount of tokens to transfer
    /// @param _data  - the data to pass to the recipient
    function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data)
        external
        onlyAdmin
    {
        if (!ctf.isApprovedForAll(_from, msg.sender)) {
            revert NotApprovedForAll();
        }

        return ctf.safeTransferFrom(_from, _to, _id, _value, _data);
    }

    /*//////////////////////////////////////////////////////////////
                            REDEEM POSITION
    //////////////////////////////////////////////////////////////*/

    /// @notice Redeem a set of conditional tokens for collateral
    /// @param _conditionId - conditionId of the conditional tokens to redeem
    /// @param _amounts     - amounts of conditional tokens to redeem
    /// _amounts should always have length 2, with the first element being the amount of yes tokens to redeem and the
    /// second element being the amount of no tokens to redeem
    function redeemPositions(bytes32 _conditionId, uint256[] calldata _amounts) public {
        uint256[] memory positionIds = Helpers.positionIds(address(wcol), _conditionId);

        // get conditional tokens from sender
        ctf.safeBatchTransferFrom(msg.sender, address(this), positionIds, _amounts, "");
        ctf.redeemPositions(address(wcol), bytes32(0), _conditionId, Helpers.partition());

        uint256 payout = wcol.balanceOf(address(this));
        if (payout > 0) {
            wcol.unwrap(msg.sender, payout);
        }

        emit PayoutRedemption(msg.sender, _conditionId, _amounts, payout);
    }

    /*//////////////////////////////////////////////////////////////
                            CONVERT POSITIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Convert a set of no positions to the complementary set of yes positions plus collateral proportional to
    /// (# of no positions - 1)
    /// @notice If the market has a fee, the fee is taken from both collateral and the yes positions
    /// @param _marketId - the marketId
    /// @param _indexSet - the set of positions to convert, expressed as an index set where the least significant bit is
    /// the first question (index zero)
    /// @param _amount   - the amount of tokens to convert
    function convertPositions(bytes32 _marketId, uint256 _indexSet, uint256 _amount) external {
        MarketData md = getMarketData(_marketId);
        uint256 questionCount = md.questionCount();

        if (md.oracle() == address(0)) revert MarketNotPrepared();
        if (questionCount <= 1) revert NoConvertiblePositions();
        if (_indexSet == 0) revert InvalidIndexSet();
        if ((_indexSet >> questionCount) > 0) revert InvalidIndexSet();

        // if _amount is 0, return early
        if (_amount == 0) {
            return;
        }

        uint256 index = 0;
        uint256 noPositionCount;

        // count number of no positions
        while (index < questionCount) {
            unchecked {
                if ((_indexSet & (1 << index)) > 0) {
                    ++noPositionCount;
                }
                ++index;
            }
        }

        uint256 yesPositionCount = questionCount - noPositionCount;
        uint256[] memory noPositionIds = new uint256[](noPositionCount);
        uint256[] memory yesPositionIds = new uint256[](yesPositionCount);
        uint256[] memory accumulatedNoPositionIds = new uint256[](yesPositionCount);

        // mint the amount of wcol required
        wcol.mint(yesPositionCount * _amount);

        // populate noPositionIds and yesPositionIds
        // split yes positions
        {
            uint256 noIndex;
            uint256 yesIndex;
            index = 0;

            while (index < questionCount) {
                bytes32 questionId = NegRiskIdLib.getQuestionId(_marketId, uint8(index));

                if ((_indexSet & (1 << index)) > 0) {
                    // NO
                    noPositionIds[noIndex] = getPositionId(questionId, false);

                    unchecked {
                        ++noIndex;
                    }
                } else {
                    // YES
                    yesPositionIds[yesIndex] = getPositionId(questionId, true);
                    accumulatedNoPositionIds[yesIndex] = getPositionId(questionId, false);

                    // split position to get yes and no tokens
                    // the no tokens will be discarded
                    _splitPosition(getConditionId(questionId), _amount);

                    unchecked {
                        ++yesIndex;
                    }
                }
                unchecked {
                    ++index;
                }
            }
        }

        // transfer the caller's no tokens _and_ accumulated no tokens to the burn address
        // these must never be redeemed
        {
            ctf.safeBatchTransferFrom(
                msg.sender, NO_TOKEN_BURN_ADDRESS, noPositionIds, Helpers.values(noPositionIds.length, _amount), ""
            );
            ctf.safeBatchTransferFrom(
                address(this),
                NO_TOKEN_BURN_ADDRESS,
                accumulatedNoPositionIds,
                Helpers.values(yesPositionCount, _amount),
                ""
            );
        }

        uint256 feeAmount = (_amount * md.feeBips()) / FEE_DENOMINATOR;
        uint256 amountOut = _amount - feeAmount;

        if (noPositionIds.length > 1) {
            // collateral out is always proportional to the number of no positions minus 1
            uint256 multiplier = noPositionIds.length - 1;
            // transfer collateral fees to vault
            if (feeAmount > 0) {
                wcol.release(vault, multiplier * feeAmount);
            }
            // transfer collateral to sender
            wcol.release(msg.sender, multiplier * amountOut);
        }

        if (yesPositionIds.length > 0) {
            if (feeAmount > 0) {
                // transfer yes token fees to vault
                ctf.safeBatchTransferFrom(
                    address(this), vault, yesPositionIds, Helpers.values(yesPositionIds.length, feeAmount), ""
                );
            }

            // transfer yes tokens to sender
            ctf.safeBatchTransferFrom(
                address(this), msg.sender, yesPositionIds, Helpers.values(yesPositionIds.length, amountOut), ""
            );
        }

        emit PositionsConverted(msg.sender, _marketId, _indexSet, _amount);
    }

    /*//////////////////////////////////////////////////////////////
                             PREPARE MARKET
    //////////////////////////////////////////////////////////////*/

    /// @notice Prepare a multi-outcome market
    /// @param _feeBips  - the fee for the market, out of 10_000
    /// @param _metadata     - metadata for the market
    /// @return marketId - the marketId
    function prepareMarket(uint256 _feeBips, bytes calldata _metadata) external returns (bytes32) {
        bytes32 marketId = _prepareMarket(_feeBips, _metadata);

        emit MarketPrepared(marketId, msg.sender, _feeBips, _metadata);

        return marketId;
    }

    /*//////////////////////////////////////////////////////////////
                            PREPARE QUESTION
    //////////////////////////////////////////////////////////////*/

    /// @notice Prepare a question for a given market
    /// @param _marketId   - the id of the market for which to prepare the question
    /// @param _metadata   - the question metadata
    /// @return questionId - the id of the resulting question
    function prepareQuestion(bytes32 _marketId, bytes calldata _metadata) external returns (bytes32) {
        (bytes32 questionId, uint256 questionIndex) = _prepareQuestion(_marketId);
        bytes32 conditionId = getConditionId(questionId);

        // check to see if the condition has already been prepared on the ctf
        if (ctf.getOutcomeSlotCount(conditionId) == 0) {
            ctf.prepareCondition(address(this), questionId, 2);
        }

        emit QuestionPrepared(_marketId, questionId, questionIndex, _metadata);

        return questionId;
    }

    /*//////////////////////////////////////////////////////////////
                             REPORT OUTCOME
    //////////////////////////////////////////////////////////////*/

    /// @notice Report the outcome of a question
    /// @param _questionId - the questionId to report
    /// @param _outcome    - the outcome of the question
    function reportOutcome(bytes32 _questionId, bool _outcome) external {
        _reportOutcome(_questionId, _outcome);

        ctf.reportPayouts(_questionId, Helpers.payouts(_outcome));

        emit OutcomeReported(NegRiskIdLib.getMarketId(_questionId), _questionId, _outcome);
    }

    /*//////////////////////////////////////////////////////////////
                                INTERNAL
    //////////////////////////////////////////////////////////////*/

    /// @dev internal function to avoid stack too deep in convertPositions
    function _splitPosition(bytes32 _conditionId, uint256 _amount) internal {
        ctf.splitPosition(address(wcol), bytes32(0), _conditionId, Helpers.partition(), _amount);
    }
}

File 2 of 13 : ERC1155.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 amount
    );

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] amounts
    );

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    event URI(string value, uint256 indexed id);

    /*//////////////////////////////////////////////////////////////
                             ERC1155 STORAGE
    //////////////////////////////////////////////////////////////*/

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

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                             METADATA LOGIC
    //////////////////////////////////////////////////////////////*/

    function uri(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                              ERC1155 LOGIC
    //////////////////////////////////////////////////////////////*/

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) public virtual {
        require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

        balanceOf[from][id] -= amount;
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, from, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
                    ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) public virtual {
        require(ids.length == amounts.length, "LENGTH_MISMATCH");

        require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

        // Storing these outside the loop saves ~15 gas per iteration.
        uint256 id;
        uint256 amount;

        for (uint256 i = 0; i < ids.length; ) {
            id = ids[i];
            amount = amounts[i];

            balanceOf[from][id] -= amount;
            balanceOf[to][id] += amount;

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
                    ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
        public
        view
        virtual
        returns (uint256[] memory balances)
    {
        require(owners.length == ids.length, "LENGTH_MISMATCH");

        balances = new uint256[](owners.length);

        // Unchecked because the only math done is incrementing
        // the array index counter which cannot possibly overflow.
        unchecked {
            for (uint256 i = 0; i < owners.length; ++i) {
                balances[i] = balanceOf[owners[i]][ids[i]];
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
            interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
    }

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

    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, address(0), to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
                    ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchMint(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[to][ids[i]] += amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, address(0), to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
                    ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchBurn(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[from][ids[i]] -= amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, address(0), ids, amounts);
    }

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

        emit TransferSingle(msg.sender, from, address(0), id, amount);
    }
}

/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155TokenReceiver {
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
    }
}

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

File 4 of 13 : SafeTransferLib.sol
// 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;

        /// @solidity memory-safe-assembly
        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;

        /// @solidity memory-safe-assembly
        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), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            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;

        /// @solidity memory-safe-assembly
        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), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            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;

        /// @solidity memory-safe-assembly
        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), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            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");
    }
}

File 5 of 13 : WrappedCollateral.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

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

/// @title IWrappedCollateralEE
/// @notice WrappedCollateral Errors and Events
interface IWrappedCollateralEE {
    error OnlyOwner();
}

string constant NAME = "Wrapped Collateral";
string constant SYMBOL = "WCOL";

/// @title WrappedCollateral
/// @author Mike Shrieve ([email protected])
/// @notice Wraps an ERC20 token to be used as collateral in the CTF
contract WrappedCollateral is IWrappedCollateralEE, ERC20 {
    using SafeTransferLib for ERC20;

    /*//////////////////////////////////////////////////////////////
                                 STATE
    //////////////////////////////////////////////////////////////*/

    address public immutable owner;
    address public immutable underlying;

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    modifier onlyOwner() {
        if (msg.sender != owner) revert OnlyOwner();
        _;
    }

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

    /// @param _underlying The address of the underlying ERC20 token
    /// @param _decimals The number of decimals of the underlying ERC20 token
    constructor(address _underlying, uint8 _decimals) ERC20(NAME, SYMBOL, _decimals) {
        owner = msg.sender;
        underlying = _underlying;
    }

    /*//////////////////////////////////////////////////////////////
                                 UNWRAP
    //////////////////////////////////////////////////////////////*/

    /// @notice Unwraps the specified amount of tokens
    /// @param _to The address to send the unwrapped tokens to
    /// @param _amount The amount of tokens to unwrap
    function unwrap(address _to, uint256 _amount) external {
        _burn(msg.sender, _amount);
        ERC20(underlying).safeTransfer(_to, _amount);
    }

    /*//////////////////////////////////////////////////////////////
                                 ADMIN
    //////////////////////////////////////////////////////////////*/

    /// @notice Wraps the specified amount of tokens
    /// @notice Can only be called by the owner
    /// @param _to     - the address to send the wrapped tokens to
    /// @param _amount - the amount of tokens to wrap
    function wrap(address _to, uint256 _amount) external onlyOwner {
        ERC20(underlying).safeTransferFrom(msg.sender, address(this), _amount);
        _mint(_to, _amount);
    }

    /// @notice Burns the specified amount of tokens
    /// @notice Can only be called by the owner
    /// @param _amount - the amount of tokens to burn
    function burn(uint256 _amount) external onlyOwner {
        _burn(msg.sender, _amount);
    }

    /// @notice Mints the specified amount of tokens
    /// @notice Can only be called by the owner
    /// @param _amount - the amount of tokens to mint
    function mint(uint256 _amount) external onlyOwner {
        _mint(msg.sender, _amount);
    }

    /// @notice Releases the specified amount of the underlying token
    /// @notice Can only be called by the owner
    /// @param _to     - the address to send the released tokens to
    /// @param _amount - the amount of tokens to release
    function release(address _to, uint256 _amount) external onlyOwner {
        ERC20(underlying).safeTransfer(_to, _amount);
    }
}

File 6 of 13 : MarketDataManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {MarketData, MarketDataLib} from "src/types/MarketData.sol";
import {NegRiskIdLib} from "src/libraries/NegRiskIdLib.sol";

interface IMarketStateManagerEE {
    error IndexOutOfBounds();
    error OnlyOracle();
    error MarketNotPrepared();
    error MarketAlreadyPrepared();
    error MarketAlreadyDetermined();
    error FeeBipsOutOfBounds();
}

/// @title MarketStateManager
/// @notice Manages market state on behalf of the NegRiskAdapter
/// @author Mike Shrieve([email protected])
abstract contract MarketStateManager is IMarketStateManagerEE {
    mapping(bytes32 _marketId => MarketData) internal marketData;

    /*//////////////////////////////////////////////////////////////
                                GETTERS
    //////////////////////////////////////////////////////////////*/

    function getMarketData(bytes32 _marketId) public view returns (MarketData) {
        return marketData[_marketId];
    }

    function getOracle(bytes32 _marketId) external view returns (address) {
        return marketData[_marketId].oracle();
    }

    function getQuestionCount(bytes32 _marketId) external view returns (uint256) {
        return marketData[_marketId].questionCount();
    }

    function getDetermined(bytes32 _marketId) external view returns (bool) {
        return marketData[_marketId].determined();
    }

    function getResult(bytes32 _marketId) external view returns (uint256) {
        return marketData[_marketId].result();
    }

    function getFeeBips(bytes32 _marketId) external view returns (uint256) {
        return marketData[_marketId].feeBips();
    }

    /*//////////////////////////////////////////////////////////////
                                INTERNAL
    //////////////////////////////////////////////////////////////*/

    /// @notice Prepares market data
    /// @notice The market id depends on the oracle address, feeBips, and market metadata
    /// @param _feeBips  - feeBips out of 10_000
    /// @param _metadata - market metadata
    /// @return marketId - the market id
    function _prepareMarket(uint256 _feeBips, bytes memory _metadata) internal returns (bytes32 marketId) {
        address oracle = msg.sender;
        marketId = NegRiskIdLib.getMarketId(oracle, _feeBips, _metadata);
        MarketData md = marketData[marketId];

        if (md.oracle() != address(0)) revert MarketAlreadyPrepared();
        if (_feeBips > 10_000) revert FeeBipsOutOfBounds();

        marketData[marketId] = MarketDataLib.initialize(oracle, _feeBips);
    }

    /// @notice Prepares a new question for the given market
    /// @param _marketId   - the market for which to prepare a new question
    /// @return questionId - the resulting question id
    /// @return index      - the resulting question index
    function _prepareQuestion(bytes32 _marketId) internal returns (bytes32 questionId, uint256 index) {
        MarketData md = marketData[_marketId];
        address oracle = marketData[_marketId].oracle();

        if (oracle == address(0)) revert MarketNotPrepared();
        if (oracle != msg.sender) revert OnlyOracle();

        index = md.questionCount();
        questionId = NegRiskIdLib.getQuestionId(_marketId, uint8(index));
        marketData[_marketId] = md.incrementQuestionCount();
    }

    /// @notice Reports the outcome of a question
    /// @notice State is only modified if the outcome is true
    /// @notice Reverts if the market is not prepared
    /// @notice Reverts if msg.sender is not the market's oracle
    /// @notice Reverts if the question index is out of bounds
    /// @notice Reverts if the outcome is true, and the market has already been determined
    function _reportOutcome(bytes32 _questionId, bool _outcome) internal {
        bytes32 marketId = NegRiskIdLib.getMarketId(_questionId);
        uint256 questionIndex = NegRiskIdLib.getQuestionIndex(_questionId);

        MarketData data = marketData[marketId];
        address oracle = data.oracle();

        if (oracle == address(0)) revert MarketNotPrepared();
        if (oracle != msg.sender) revert OnlyOracle();
        if (questionIndex >= data.questionCount()) revert IndexOutOfBounds();

        if (_outcome == true) {
            if (data.determined()) revert MarketAlreadyDetermined();
            marketData[marketId] = data.determine(questionIndex);
        }
    }
}

File 7 of 13 : CTHelpers.sol
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.5.1;

// forked from Gnosis Condtional Tokens
library CTHelpers {
    /// @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)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(oracle, questionId, outcomeSlotCount));
    }

    uint256 constant P =
        21888242871839275222246405745257275088696311157297823662689037894645226208583;
    uint256 constant B = 3;

    function sqrt(uint256 x) private pure returns (uint256 y) {
        uint256 p = P;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            // add chain generated via https://crypto.stackexchange.com/q/27179/71252
            // and transformed to the following program:

            // x=1; y=x+x; z=y+y; z=z+z; y=y+z; x=x+y; y=y+x; z=y+y; t=z+z; t=z+t; t=t+t;
            // t=t+t; z=z+t; x=x+z; z=x+x; z=z+z; y=y+z; z=y+y; z=z+z; z=z+z; z=y+z; x=x+z;
            // z=x+x; z=z+z; z=z+z; z=x+z; y=y+z; x=x+y; z=x+x; z=z+z; y=y+z; z=y+y; t=z+z;
            // t=t+t; t=t+t; z=z+t; x=x+z; y=y+x; z=y+y; z=z+z; z=z+z; x=x+z; z=x+x; z=z+z;
            // z=x+z; z=z+z; z=z+z; z=x+z; y=y+z; z=y+y; t=z+z; t=t+t; t=z+t; t=y+t; t=t+t;
            // t=t+t; t=t+t; t=t+t; z=z+t; x=x+z; z=x+x; z=x+z; y=y+z; z=y+y; z=y+z; z=z+z;
            // t=z+z; t=z+t; w=t+t; w=w+w; w=w+w; w=w+w; w=w+w; t=t+w; z=z+t; x=x+z; y=y+x;
            // z=y+y; x=x+z; y=y+x; x=x+y; y=y+x; x=x+y; z=x+x; z=x+z; z=z+z; y=y+z; z=y+y;
            // z=z+z; x=x+z; y=y+x; z=y+y; z=y+z; x=x+z; y=y+x; x=x+y; y=y+x; z=y+y; z=z+z;
            // z=y+z; x=x+z; z=x+x; z=x+z; y=y+z; x=x+y; y=y+x; x=x+y; y=y+x; z=y+y; z=y+z;
            // z=z+z; x=x+z; y=y+x; z=y+y; z=y+z; z=z+z; x=x+z; z=x+x; t=z+z; t=t+t; t=z+t;
            // t=x+t; t=t+t; t=t+t; t=t+t; t=t+t; z=z+t; y=y+z; x=x+y; y=y+x; x=x+y; z=x+x;
            // z=x+z; z=z+z; z=z+z; z=z+z; z=x+z; y=y+z; z=y+y; z=y+z; z=z+z; x=x+z; z=x+x;
            // z=x+z; y=y+z; x=x+y; z=x+x; z=z+z; y=y+z; x=x+y; z=x+x; y=y+z; x=x+y; y=y+x;
            // z=y+y; z=y+z; x=x+z; y=y+x; z=y+y; z=y+z; z=z+z; z=z+z; x=x+z; z=x+x; z=z+z;
            // z=z+z; z=x+z; y=y+z; x=x+y; z=x+x; t=x+z; t=t+t; t=t+t; z=z+t; y=y+z; z=y+y;
            // x=x+z; y=y+x; x=x+y; y=y+x; x=x+y; y=y+x; z=y+y; t=y+z; z=y+t; z=z+z; z=z+z;
            // z=t+z; x=x+z; y=y+x; x=x+y; y=y+x; x=x+y; z=x+x; z=x+z; y=y+z; x=x+y; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
            // x=x+x; x=x+x; x=x+x; x=x+x; res=y+x
            // res == (P + 1) // 4

            y := mulmod(x, x, p)
            {
                let z := mulmod(y, y, p)
                z := mulmod(z, z, p)
                y := mulmod(y, z, p)
                x := mulmod(x, y, p)
                y := mulmod(y, x, p)
                z := mulmod(y, y, p)
                {
                    let t := mulmod(z, z, p)
                    t := mulmod(z, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    z := mulmod(z, t, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(z, z, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(y, z, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    z := mulmod(x, x, p)
                    z := mulmod(z, z, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    t := mulmod(z, z, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    z := mulmod(z, t, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(z, z, p)
                    z := mulmod(x, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    t := mulmod(z, z, p)
                    t := mulmod(t, t, p)
                    t := mulmod(z, t, p)
                    t := mulmod(y, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    z := mulmod(z, t, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    z := mulmod(z, z, p)
                    t := mulmod(z, z, p)
                    t := mulmod(z, t, p)
                    {
                        let w := mulmod(t, t, p)
                        w := mulmod(w, w, p)
                        w := mulmod(w, w, p)
                        w := mulmod(w, w, p)
                        w := mulmod(w, w, p)
                        t := mulmod(t, w, p)
                    }
                    z := mulmod(z, t, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    z := mulmod(x, x, p)
                    z := mulmod(x, z, p)
                    z := mulmod(z, z, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    z := mulmod(z, z, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(z, z, p)
                    z := mulmod(y, z, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    z := mulmod(z, z, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    z := mulmod(z, z, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    t := mulmod(z, z, p)
                    t := mulmod(t, t, p)
                    t := mulmod(z, t, p)
                    t := mulmod(x, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    z := mulmod(z, t, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    z := mulmod(x, x, p)
                    z := mulmod(x, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    z := mulmod(z, z, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    z := mulmod(x, x, p)
                    z := mulmod(z, z, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    z := mulmod(x, x, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    z := mulmod(y, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    x := mulmod(x, z, p)
                    z := mulmod(x, x, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(x, z, p)
                    y := mulmod(y, z, p)
                    x := mulmod(x, y, p)
                    z := mulmod(x, x, p)
                    t := mulmod(x, z, p)
                    t := mulmod(t, t, p)
                    t := mulmod(t, t, p)
                    z := mulmod(z, t, p)
                    y := mulmod(y, z, p)
                    z := mulmod(y, y, p)
                    x := mulmod(x, z, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    x := mulmod(x, y, p)
                    y := mulmod(y, x, p)
                    z := mulmod(y, y, p)
                    t := mulmod(y, z, p)
                    z := mulmod(y, t, p)
                    z := mulmod(z, z, p)
                    z := mulmod(z, z, p)
                    z := mulmod(t, z, p)
                }
                x := mulmod(x, z, p)
                y := mulmod(y, x, p)
                x := mulmod(x, y, p)
                y := mulmod(y, x, p)
                x := mulmod(x, y, p)
                z := mulmod(x, x, p)
                z := mulmod(x, z, p)
                y := mulmod(y, z, p)
            }
            x := mulmod(x, y, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            x := mulmod(x, x, p)
            y := mulmod(y, x, p)
        }
    }

    /// @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)
        internal
        view
        returns (bytes32)
    {
        uint256 x1 = uint256(keccak256(abi.encodePacked(conditionId, indexSet)));
        bool odd = x1 >> 255 != 0;
        uint256 y1;
        uint256 yy;
        do {
            x1 = addmod(x1, 1, P);
            yy = addmod(mulmod(x1, mulmod(x1, x1, P), P), B, P);
            y1 = sqrt(yy);
        } while (mulmod(y1, y1, P) != yy);
        if ((odd && y1 % 2 == 0) || (!odd && y1 % 2 == 1)) y1 = P - y1;

        uint256 x2 = uint256(parentCollectionId);
        if (x2 != 0) {
            odd = x2 >> 254 != 0;
            x2 = (x2 << 2) >> 2;
            yy = addmod(mulmod(x2, mulmod(x2, x2, P), P), B, P);
            uint256 y2 = sqrt(yy);
            if ((odd && y2 % 2 == 0) || (!odd && y2 % 2 == 1)) y2 = P - y2;
            require(mulmod(y2, y2, P) == yy, "invalid parent collection ID");

            (bool success, bytes memory ret) = address(6).staticcall(abi.encode(x1, y1, x2, y2));
            require(success, "ecadd failed");
            (x1, y1) = abi.decode(ret, (uint256, uint256));
        }

        if (y1 % 2 == 1) x1 ^= 1 << 254;

        return bytes32(x1);
    }

    /// @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(address collateralToken, bytes32 collectionId)
        internal
        pure
        returns (uint256)
    {
        return uint256(keccak256(abi.encodePacked(collateralToken, collectionId)));
    }
}

File 8 of 13 : Helpers.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {CTHelpers} from "./CTHelpers.sol";

/// @title Helpers
/// @notice Helper functions for the NegRiskAdapter
/// @author Mike Shrieve ([email protected])
library Helpers {
    /// @notice Returns the positionIds corresponding to _conditionId
    /// @param _collateral  - the collateral address
    /// @param _conditionId - the conditionId
    /// @return positionIds - length 2 array of position ids
    function positionIds(address _collateral, bytes32 _conditionId) internal view returns (uint256[] memory) {
        uint256[] memory positionIds_ = new uint256[](2);

        // YES
        positionIds_[0] = CTHelpers.getPositionId(_collateral, CTHelpers.getCollectionId(bytes32(0), _conditionId, 1));
        // NO
        positionIds_[1] = CTHelpers.getPositionId(_collateral, CTHelpers.getCollectionId(bytes32(0), _conditionId, 2));

        return positionIds_;
    }

    /// @notice Returns an array with each element set to the same value
    /// @param _length  - the length of the array
    /// @param _value   - the value of each element
    /// @return values_ - the array of values
    function values(uint256 _length, uint256 _value) internal pure returns (uint256[] memory) {
        uint256[] memory values_ = new uint256[](_length);
        uint256 i;

        while (i < _length) {
            values_[i] = _value;
            unchecked {
                ++i;
            }
        }
        return values_;
    }

    /// @notice returns the partition for a binary conditional token
    /// @return partition - the partition [1,2] = [0b01, 0b10]
    function partition() internal pure returns (uint256[] memory) {
        uint256[] memory partition_ = new uint256[](2);
        // YES
        partition_[0] = 1;
        // NO
        partition_[1] = 2;
        return partition_;
    }

    /// @notice returns the payouts for a binary conditional token
    /// @notice payouts are [1,0] if _outcome is true and [0,1] otherwise
    /// @param _outcome - the boolean outcome
    /// @return payouts - the payouts
    function payouts(bool _outcome) internal pure returns (uint256[] memory) {
        uint256[] memory payouts_ = new uint256[](2);
        // YES
        payouts_[0] = _outcome ? 1 : 0;
        // NO
        payouts_[1] = _outcome ? 0 : 1;
        return payouts_;
    }
}

File 9 of 13 : NegRiskIdLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @title NegRiskIdLib
/// @notice Functions for the NegRiskAdapter Market and QuestionIds
/// @notice MarketIds are the keccak256 hash of the oracle, feeBips, and metadata, with the final 8 bits set to 0
/// @notice QuestionIds share the first 31 bytes with their corresponding MarketId, and the final byte consists of the
/// questionIndex
/// @author Mike Shrieve ([email protected])
library NegRiskIdLib {
    bytes32 private constant MASK = bytes32(type(uint256).max) << 8;

    /// @notice Returns the MarketId for a given oracle, feeBips, and metadata
    /// @param _oracle   - the oracle address
    /// @param _feeBips  - the feeBips, out of 10_000
    /// @param _metadata - the market metadata
    /// @return marketId - the marketId
    function getMarketId(address _oracle, uint256 _feeBips, bytes memory _metadata) internal pure returns (bytes32) {
        return keccak256(abi.encode(_oracle, _feeBips, _metadata)) & MASK;
    }

    /// @notice Returns the MarketId for a given QuestionId
    /// @param _questionId - the questionId
    /// @return marketId   - the marketId
    function getMarketId(bytes32 _questionId) internal pure returns (bytes32) {
        return _questionId & MASK;
    }

    /// @notice Returns the QuestionId for a given MarketId and questionIndex
    /// @param _marketId      - the marketId
    /// @param _questionIndex - the questionIndex
    /// @return questionId    - the questionId
    function getQuestionId(bytes32 _marketId, uint8 _questionIndex) internal pure returns (bytes32) {
        unchecked {
            return bytes32(uint256(_marketId) + _questionIndex);
        }
    }

    /// @notice Returns the questionIndex for a given QuestionId
    /// @param _questionId - the questionId
    /// @return questionIndex - the questionIndex
    function getQuestionIndex(bytes32 _questionId) internal pure returns (uint8) {
        return uint8(uint256(_questionId));
    }
}

File 10 of 13 : IConditionalTokens.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @notice references to IERC20 are replaced by address

/// @notice Interface for Gnosis Conditional Tokens
interface IERC1155 {
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    event TransferBatch(
        address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values
    );

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    event URI(string value, uint256 indexed id);

    function balanceOf(address owner, uint256 id) external view returns (uint256);

    function balanceOfBatch(address[] memory owners, uint256[] memory ids) external view returns (uint256[] memory);

    function setApprovalForAll(address operator, bool approved) external;

    function isApprovedForAll(address owner, address operator) external view returns (bool);

    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

interface IConditionalTokensEE {
    event ConditionPreparation(
        bytes32 indexed conditionId, address indexed oracle, bytes32 indexed questionId, uint256 outcomeSlotCount
    );

    event ConditionResolution(
        bytes32 indexed conditionId,
        address indexed oracle,
        bytes32 indexed questionId,
        uint256 outcomeSlotCount,
        uint256[] payoutNumerators
    );

    /// @dev Emitted when a position is successfully split.
    event PositionSplit(
        address indexed stakeholder,
        address collateralToken,
        bytes32 indexed parentCollectionId,
        bytes32 indexed conditionId,
        uint256[] partition,
        uint256 amount
    );
    /// @dev Emitted when positions are successfully merged.
    event PositionsMerge(
        address indexed stakeholder,
        address collateralToken,
        bytes32 indexed parentCollectionId,
        bytes32 indexed conditionId,
        uint256[] partition,
        uint256 amount
    );
    event PayoutRedemption(
        address indexed redeemer,
        address indexed collateralToken,
        bytes32 indexed parentCollectionId,
        bytes32 conditionId,
        uint256[] indexSets,
        uint256 payout
    );
}

interface IConditionalTokens is IConditionalTokensEE, IERC1155 {
    function payoutNumerators(bytes32 conditionId, uint256 index) external view returns (uint256);

    function payoutDenominator(bytes32 conditionId) external view 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(
        address collateralToken,
        bytes32 parentCollectionId,
        bytes32 conditionId,
        uint256[] calldata partition,
        uint256 amount
    ) external;

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

    function redeemPositions(
        address 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(address collateralToken, bytes32 collectionId) external pure returns (uint256);
}

File 11 of 13 : Auth.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

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

/// @title Auth
/// @author Jon Amenechi ([email protected])
/// @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;
    }
}

File 12 of 13 : IAuth.sol
// 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;
}

File 13 of 13 : MarketData.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @notice the MarketData user-defined type, a zero-cost abstraction over bytes32
type MarketData is bytes32;

// md[0] = questionCount
// md[1] = determined
// md[2] = result
// md[3:4] = feeBips
// md[12:32] = oracle

using MarketDataLib for MarketData global;

/// @title MarketDataLib
/// @notice Library for dealing with the MarketData user-defined bytes32 type
/// @author Mike Shrieve ([email protected])
library MarketDataLib {
    error DeterminedFlagAlreadySet();

    /// @notice used to increment the questionCount
    uint256 constant INCREMENT = uint256(bytes32(bytes1(0x01)));

    /// @notice extracts the oracle address from MarketData
    /// @return oracle - the address of the oracle
    function oracle(MarketData _data) internal pure returns (address) {
        return address(uint160(uint256(MarketData.unwrap(_data))));
    }

    /// @notice extracts the questionCount from MarketData
    /// @return questionCount - the number of questions in the market
    function questionCount(MarketData _data) internal pure returns (uint256) {
        return uint256(uint8(MarketData.unwrap(_data)[0]));
    }

    /// @notice increments the questionCount
    /// @notice does _not_ check to see if the questionCount is already at the maximum value
    /// @return marketData - the modified MarketData
    function incrementQuestionCount(MarketData _data) internal pure returns (MarketData) {
        bytes32 data = MarketData.unwrap(_data);
        data = bytes32(uint256(data) + INCREMENT);
        return MarketData.wrap(data);
    }

    /// @notice extracts the determined flag from MarketData
    /// @return determined - true if the market has been determined, i.e. if one of the questions was resolved true
    function determined(MarketData _data) internal pure returns (bool) {
        return MarketData.unwrap(_data)[1] == 0x00 ? false : true;
    }

    /// @notice marks the market as determined
    /// @param _result - the result of the market, i.e., the index of the question that was resolved true
    /// @return marketData - the modified MarketData
    function determine(MarketData _data, uint256 _result) internal pure returns (MarketData) {
        bytes32 data = MarketData.unwrap(_data);

        if (data[1] != 0x00) revert DeterminedFlagAlreadySet();
        data |= bytes32(bytes1(0x01)) >> 8;
        data |= bytes32(bytes1(uint8(_result))) >> 16;

        return MarketData.wrap(data);
    }

    /// @notice initializes the MarketData type
    /// @param _oracle - the address of the oracle
    /// @param _feeBips - the feeBips, out of 10_000
    /// @return marketData - the initialized MarketData
    function initialize(address _oracle, uint256 _feeBips) internal pure returns (MarketData) {
        bytes32 data;
        data |= bytes32(bytes2(uint16(_feeBips))) >> 24;
        data |= bytes32(uint256(uint160(_oracle)));
        return MarketData.wrap(data);
    }

    /// @notice extracts the result from MarketData, i.e., the index of the question that was resolved true
    /// @notice if the market has not been determined, returns zero
    /// @return result - the index of the question that was resolved true, or zero
    function result(MarketData _data) internal pure returns (uint256) {
        return uint256(uint8(MarketData.unwrap(_data)[2]));
    }

    /// @notice extracts the feeBips from MarketData, out of 10_000
    /// @return feeBips - the feeBips
    function feeBips(MarketData _data) internal pure returns (uint256) {
        return uint256(uint16(bytes2(MarketData.unwrap(_data) << 24)));
    }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
    "openzeppelin-contracts/=lib/ctf-exchange/lib/openzeppelin-contracts/contracts/",
    "common/=lib/ctf-exchange/src/common/",
    "creator/=lib/ctf-exchange/src/creator/",
    "ctf-exchange/=lib/ctf-exchange/src/",
    "dev/=lib/ctf-exchange/src/dev/",
    "exchange-fee-module/=lib/exchange-fee-module/src/",
    "exchange/=lib/ctf-exchange/src/exchange/",
    "openzeppelin/=lib/ctf-exchange/lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_ctf","type":"address"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeterminedFlagAlreadySet","type":"error"},{"inputs":[],"name":"FeeBipsOutOfBounds","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidIndexSet","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MarketAlreadyDetermined","type":"error"},{"inputs":[],"name":"MarketAlreadyPrepared","type":"error"},{"inputs":[],"name":"MarketNotPrepared","type":"error"},{"inputs":[],"name":"NoConvertiblePositions","type":"error"},{"inputs":[],"name":"NotAdmin","type":"error"},{"inputs":[],"name":"NotApprovedForAll","type":"error"},{"inputs":[],"name":"OnlyOracle","type":"error"},{"inputs":[],"name":"UnexpectedCollateralToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeBips","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"MarketPrepared","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":"marketId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"questionId","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"outcome","type":"bool"}],"name":"OutcomeReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"conditionId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"}],"name":"PayoutRedemption","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"conditionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PositionSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"indexSet","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PositionsConverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"conditionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PositionsMerge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"questionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"QuestionPrepared","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":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_TOKEN_BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_owners","type":"address[]"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"col","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"},{"internalType":"uint256","name":"_indexSet","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"convertPositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ctf","outputs":[{"internalType":"contract IConditionalTokens","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_questionId","type":"bytes32"}],"name":"getConditionId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getDetermined","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getFeeBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getMarketData","outputs":[{"internalType":"MarketData","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_questionId","type":"bytes32"},{"internalType":"bool","name":"_outcome","type":"bool"}],"name":"getPositionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getQuestionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getResult","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mergePositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mergePositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeBips","type":"uint256"},{"internalType":"bytes","name":"_metadata","type":"bytes"}],"name":"prepareMarket","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"},{"internalType":"bytes","name":"_metadata","type":"bytes"}],"name":"prepareQuestion","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"redeemPositions","outputs":[],"stateMutability":"nonpayable","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"},{"internalType":"bool","name":"_outcome","type":"bool"}],"name":"reportOutcome","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"splitPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"splitPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wcol","outputs":[{"internalType":"contract WrappedCollateral","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6101006040523480156200001257600080fd5b5060405162005ed038038062005ed083398101604081905262000035916200023b565b33600090815260016020818152604092839020919091556001600160a01b0385811660805284811660a081905290841660e052825163313ce56760e01b815292518593919263313ce56792600480820193918290030181865afa158015620000a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000c7919062000285565b604051620000d59062000210565b6001600160a01b03909216825260ff166020820152604001604051809103906000f0801580156200010a573d6000803e3d6000fd5b506001600160a01b0390811660c081905260405163095ea7b360e01b8152918516600483015260001960248301529063095ea7b3906044016020604051808303816000875af115801562000162573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001889190620002b1565b5060a05160c05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af1158015620001e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002069190620002b1565b50505050620002d5565b61174d806200478383390190565b80516001600160a01b03811681146200023657600080fd5b919050565b6000806000606084860312156200025157600080fd5b6200025c846200021e565b92506200026c602085016200021e565b91506200027c604085016200021e565b90509250925092565b6000602082840312156200029857600080fd5b815160ff81168114620002aa57600080fd5b9392505050565b600060208284031215620002c457600080fd5b81518015158114620002aa57600080fd5b60805160a05160c05160e05161436a62000419600039600081816105ba015281816118e90152611aae0152600081816103e501528181610bc301528181610e8201528181610f3101528181610ff3015281816110cf015281816111cf015281816112810152818161158d015281816118c2015281816119ad01528181611c4301528181611d5501528181611e0201528181611ec00152612c2d01526000818161044d01528181610b0101528181610d7e0152610e250152600081816102750152818161062a015281816107ee015281816108b1015281816109c601528181610ef501528181610fb2015281816110f801528181611193015281816116dc0152818161179a01528181611a7101528181611b2d01528181611ca801528181611d1901528181611f980152818161211c015281816121fa0152612c06015261436a6000f3fe608060405234801561001057600080fd5b506004361061020a5760003560e01c80638a0db6151161012a578063bc197c81116100bd578063dbeccb231161008c578063f23a6e6111610071578063f23a6e6114610569578063f242432a146105a2578063fbfa77cf146105b557600080fd5b8063dbeccb2314610543578063e200affd1461055657600080fd5b8063bc197c81146104a8578063c64748c414610514578063d73792a914610527578063dafaf94a1461053057600080fd5b8063a78695b0116100f9578063a78695b014610448578063add4c7841461046f578063b10c5c1714610482578063b7f75d2c1461049557600080fd5b80638a0db615146104075780638bad0c0a1461041a5780639e7212ad14610422578063a3d7da1d1461043557600080fd5b8063429b62e5116101a2578063752b5ba511610171578063752b5ba51461039f5780637ad7fe36146103b25780637ae2e67b146103cd5780637e3b74c3146103e057600080fd5b8063429b62e5146103395780634e1273f414610359578063704802751461037957806372ce42751461038c57600080fd5b806322a9339f116101de57806322a9339f1461027057806324d7806c146102bc5780632582cb5e1461030657806330f4f4bb1461031957600080fd5b8062fdd58e1461020f57806304329c03146102355780631785f53c146102485780631d69b48d1461025d575b600080fd5b61022261021d3660046137d2565b6105dc565b6040519081526020015b60405180910390f35b6102226102433660046137fc565b61069f565b61025b610256366004613815565b610703565b005b61022261026b366004613879565b61079f565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161022c565b6102f66102ca366004613815565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160208190526040909120541490565b604051901515815260200161022c565b6102226103143660046137fc565b61096b565b6102226103273660046137fc565b60009081526020819052604090205490565b610222610347366004613815565b60016020526000908152604090205481565b61036c6103673660046139d2565b610986565b60405161022c9190613acd565b61025b610387366004613815565b610a60565b61025b61039a366004613b25565b610aff565b6102226103ad366004613ba6565b610b96565b61029773a5ef39c3d3e10d0b270233af41cac69796b1296681565b6102f66103db3660046137fc565b610c3f565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b610222610415366004613879565b610c57565b61025b610cf7565b61025b610430366004613b25565b610d7c565b61025b610443366004613bd6565b610e0b565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b61022261047d3660046137fc565b6110b0565b61025b610490366004613bd6565b6110c8565b6102226104a33660046137fc565b611330565b6104e36104b6366004613bf8565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161022c565b61025b610522366004613cb3565b611348565b61022261271081565b61029761053e3660046137fc565b611c28565b61025b610551366004613cdf565b611c3c565b61025b610564366004613ba6565b611f8c565b6104e3610577366004613d1e565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61025b6105b0366004613d1e565b612087565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390526000917f00000000000000000000000000000000000000000000000000000000000000009091169062fdd58e90604401602060405180830381865afa158015610672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106969190613d96565b90505b92915050565b604080513060601b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166020808301919091526034820184905260026054808401919091528351808403909101815260749092019092528051910120600090610699565b336000908152600160208190526040909120541461074d576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160205260408082208290555133917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a350565b60008060006107ad86612273565b9150915060006107bc8361069f565b6040517fd42dc0c2000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d42dc0c290602401602060405180830381865afa15801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086e9190613d96565b600003610923576040517fd96ee75400000000000000000000000000000000000000000000000000000000815230600482015260248101849052600260448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d96ee75490606401600060405180830381600087803b15801561090a57600080fd5b505af115801561091e573d6000803e3d6000fd5b505050505b82877faac410f87d423a922a7b226ac68f0c2eaf5bf6d15e644ac0758c7f96e2c253f784898960405161095893929190613df8565b60405180910390a3509095945050505050565b60008181526020819052604081205460d81c61ffff16610699565b6040517f4e1273f400000000000000000000000000000000000000000000000000000000815260609073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634e1273f4906109fd9086908690600401613e12565b600060405180830381865afa158015610a1a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106969190810190613e7f565b3360009081526001602081905260409091205414610aaa576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160208190526040808320919091555133917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a350565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610b84576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e8482610e0b565b505050505050565b600080610bbd81610ba68661069f565b85610bb2576002610bb5565b60015b60ff16612358565b604080517f000000000000000000000000000000000000000000000000000000000000000060601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602080830191909152603480830185905283518084039091018152605490920190925280519101209091506000905b95945050505050565b600081815260208190526040812054610699906127ba565b600080610c9a8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127f992505050565b90503373ffffffffffffffffffffffffffffffffffffffff16817ff059ab16d1ca60e123eab60e3c02b68faf060347c701a5d14885a8e1def7b3a8878787604051610ce793929190613df8565b60405180910390a3949350505050565b3360009081526001602081905260409091205414610d41576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600160205260408082208290555182917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a3565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610e01576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e84826110c8565b610e4d73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846128f7565b6040517fbf376c7a000000000000000000000000000000000000000000000000000000008152306004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063bf376c7a90604401600060405180830381600087803b158015610edb57600080fd5b505af1158015610eef573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166372ce42757f00000000000000000000000000000000000000000000000000000000000000006000801b85610f5d6129e9565b866040518663ffffffff1660e01b8152600401610f7e959493929190613f10565b600060405180830381600087803b158015610f9857600080fd5b505af1158015610fac573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d630336110187f000000000000000000000000000000000000000000000000000000000000000087612a54565b611023600287612b57565b6040518563ffffffff1660e01b81526004016110429493929190613f5d565b600060405180830381600087803b15801561105c57600080fd5b505af1158015611070573d6000803e3d6000fd5b50506040518381528492503391507fbbed930dbfb7907ae2d60ddf78345610214f26419a0128df39b6cc3d9e5df9b0906020015b60405180910390a35050565b60008181526020819052604081205461069990612bd9565b60006110f47f000000000000000000000000000000000000000000000000000000000000000084612a54565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6333084611140600288612b57565b6040518563ffffffff1660e01b815260040161115f9493929190613f5d565b600060405180830381600087803b15801561117957600080fd5b505af115801561118d573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639e7212ad7f00000000000000000000000000000000000000000000000000000000000000006000801b866111fb6129e9565b876040518663ffffffff1660e01b815260040161121c959493929190613f10565b600060405180830381600087803b15801561123657600080fd5b505af115801561124a573d6000803e3d6000fd5b50506040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1692506339f476939150604401600060405180830381600087803b1580156112dc57600080fd5b505af11580156112f0573d6000803e3d6000fd5b50506040518481528592503391507fba33ac50d8894676597e6e35dc09cff59854708b642cd069d21eb9c7ca072a049060200160405180910390a3505050565b60008181526020819052604081205461069990612be6565b6000838152602081905260408120549061136182612be6565b905073ffffffffffffffffffffffffffffffffffffffff82166113b0576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181116113ea576040517f24f2dfe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611424576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83811c1561145e576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361146d575050505050565b6000805b82821015611493576001821b861615611488576001015b816001019150611471565b600061149f8285613ff4565b905060008267ffffffffffffffff8111156114bc576114bc6138c5565b6040519080825280602002602001820160405280156114e5578160200160208202803683370190505b50905060008267ffffffffffffffff811115611503576115036138c5565b60405190808252806020026020018201604052801561152c578160200160208202803683370190505b50905060008367ffffffffffffffff81111561154a5761154a6138c5565b604051908082528060200260200182016040528015611573578160200160208202803683370190505b50905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663a0712d686115bc8b87614007565b6040518263ffffffff1660e01b81526004016115da91815260200190565b600060405180830381600087803b1580156115f457600080fd5b505af1158015611608573d6000803e3d6000fd5b50505050600080600097505b888810156116d85760ff88168d016001891b8d161561166157611638816000610b96565b86848151811061164a5761164a61401e565b6020026020010181815250508260010192506116cc565b61166c816001610b96565b85838151811061167e5761167e61401e565b602002602001018181525050611695816000610b96565b8483815181106116a7576116a761401e565b6020026020010181815250506116c56116bf8261069f565b8d612bef565b8160010191505b88600101985050611614565b50507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6337fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c8661174788518f612b57565b6040518563ffffffff1660e01b81526004016117669493929190613f5d565b600060405180830381600087803b15801561178057600080fd5b505af1158015611794573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c84611804898f612b57565b6040518563ffffffff1660e01b81526004016118239493929190613f5d565b600060405180830381600087803b15801561183d57600080fd5b505af1158015611851573d6000803e3d6000fd5b506000925061271091505060d88a901c61ffff1661186f908c614007565b611879919061407c565b90506000611887828c613ff4565b9050600185511115611a62576000600186516118a39190613ff4565b905082156119965773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016630357371d7f00000000000000000000000000000000000000000000000000000000000000006119128685614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b15801561197d57600080fd5b505af1158015611991573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016630357371d336119dd8585614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b158015611a4857600080fd5b505af1158015611a5c573d6000803e3d6000fd5b50505050505b835115611bc7578115611b2b577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307f000000000000000000000000000000000000000000000000000000000000000087611ad9895188612b57565b6040518563ffffffff1660e01b8152600401611af89493929190613f5d565b600060405180830381600087803b158015611b1257600080fd5b505af1158015611b26573d6000803e3d6000fd5b505050505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6303387611b75895187612b57565b6040518563ffffffff1660e01b8152600401611b949493929190613f5d565b600060405180830381600087803b158015611bae57600080fd5b505af1158015611bc2573d6000803e3d6000fd5b505050505b8b8d3373ffffffffffffffffffffffffffffffffffffffff167fb03d19dddbc72a87e735ff0ea3b57bef133ebe44e1894284916a84044deb367e8e604051611c1191815260200190565b60405180910390a450505050505050505050505050565b600081815260208190526040812054610699565b6000611c687f000000000000000000000000000000000000000000000000000000000000000085612a54565b6040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632eb2c2d690611ce590339030908690899089906004016140db565b600060405180830381600087803b158015611cff57600080fd5b505af1158015611d13573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166301b7037c7f00000000000000000000000000000000000000000000000000000000000000006000801b87611d816129e9565b6040518563ffffffff1660e01b8152600401611da09493929190614145565b600060405180830381600087803b158015611dba57600080fd5b505af1158015611dce573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600092507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1691506370a0823190602401602060405180830381865afa158015611e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e839190613d96565b90508015611f32576040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906339f4769390604401600060405180830381600087803b158015611f1957600080fd5b505af1158015611f2d573d6000803e3d6000fd5b505050505b843373ffffffffffffffffffffffffffffffffffffffff167f9140a6a270ef945260c03894b3c6b3b2695e9d5101feef0ff24fec960cfd3224868685604051611f7d93929190614180565b60405180910390a35050505050565b611f968282612ca6565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c49298ac83611fdc84612e26565b6040518363ffffffff1660e01b8152600401611ff99291906141a4565b600060405180830381600087803b15801561201357600080fd5b505af1158015612027573d6000803e3d6000fd5b5050505081612055837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690565b60405183151581527f9e9fa7fd355160bd4cd3f22d4333519354beff1f5689bde87f2c5e63d8d484b2906020016110a4565b33600090815260016020819052604090912054146120d1576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301523360248301527f0000000000000000000000000000000000000000000000000000000000000000169063e985e9c590604401602060405180830381865afa158015612163573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218791906141c5565b6121bd576040517fcd7769ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f242432a90612239908990899089908990899089906004016141e2565b600060405180830381600087803b15801561225357600080fd5b505af1158015612267573d6000803e3d6000fd5b50505050505050505050565b60008181526020819052604081205481908073ffffffffffffffffffffffffffffffffffffffff81166122d2576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612321576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61232a82612be6565b925060ff83168501935061233d82612eb2565b60009586526020869052604090952094909455509092909150565b6000808383604051602001612377929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120905060ff81901c15156000805b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476001850893507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780878809870908905061243781612ee6565b9150807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47838409036123ba578280156124785750612476600283614234565b155b806124965750821580156124965750612492600283614234565b6001145b156124c8576124c5827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b91505b8780156127755760fe81901c151593507f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808485098409089150600061255283612ee6565b90508480156125695750612567600282614234565b155b806125875750841580156125875750612583600282614234565b6001145b156125b9576125b6817f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b90505b827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478283091461264a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420706172656e7420636f6c6c656374696f6e2049440000000060448201526064015b60405180910390fd5b60408051602081018890529081018590526060810183905260808101829052600090819060069060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526126ac9161426c565b600060405180830381855afa9150503d80600081146126e7576040519150601f19603f3d011682016040523d82523d6000602084013e6126ec565b606091505b509150915081612758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f6563616464206661696c656400000000000000000000000000000000000000006044820152606401612641565b8080602001905181019061276c9190614288565b90985095505050505b612780600284614234565b6001036127ad577f4000000000000000000000000000000000000000000000000000000000000000851894505b5092979650505050505050565b60008160011a60f81b7fff0000000000000000000000000000000000000000000000000000000000000016156127f1576001610699565b600092915050565b60003361280781858561369d565b6000818152602081905260408120549193508173ffffffffffffffffffffffffffffffffffffffff1614612867576040517fd2b4c0c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127108511156128a3576040517ffc520af500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82167cffff00000000000000000000000000000000000000000000000000000060d887901b161760008481526020819052604090205550909392505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806129e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401612641565b5050505050565b60408051600280825260608083018452926000929190602083019080368337019050509050600181600081518110612a2357612a2361401e565b602002602001018181525050600281600181518110612a4457612a4461401e565b6020908102919091010152919050565b60408051600280825260608083018452926000929190602083019080368337019050509050612b0384612a8a6000866001612358565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b16602082015260348101829052600090605401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b81600081518110612b1657612b1661401e565b6020908102919091010152612b3284612a8a6000866002612358565b81600181518110612b4557612b4561401e565b60209081029190910101529392505050565b606060008367ffffffffffffffff811115612b7457612b746138c5565b604051908082528060200260200182016040528015612b9d578160200160208202803683370190505b50905060005b84811015612bd15783828281518110612bbe57612bbe61401e565b6020908102919091010152600101612ba3565b509392505050565b60008160025b1a92915050565b60008181612bdf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166372ce42757f0000000000000000000000000000000000000000000000000000000000000000600085612c576129e9565b866040518663ffffffff1660e01b8152600401612c78959493929190613f10565b600060405180830381600087803b158015612c9257600080fd5b505af1158015610b8e573d6000803e3d6000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00821660008181526020819052604090205460ff8416908073ffffffffffffffffffffffffffffffffffffffff8116612d2b576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612d7a576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d8382612be6565b8310612dbb576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841515600103610b8e57612dce826127ba565b15612e05576040517fe3b0238900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e0f82846136f7565b600085815260208190526040902055505050505050565b6040805160028082526060808301845292600092919060208301908036833701905050905082612e57576000612e5a565b60015b60ff1681600081518110612e7057612e7061401e565b60200260200101818152505082612e88576001612e8b565b60005b60ff1681600181518110612ea157612ea161401e565b602090810291909101015292915050565b600081612edf7f0100000000000000000000000000000000000000000000000000000000000000826142ac565b9392505050565b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808380099150808283098181820990508181840992508183850993508184840992508183840990508181820982818309905082818209905082818209905082818309915082828609945082858609915082828309915082828509935082848509915082828309915082828309915082828509915082828609945082858609915082828309915082828309915082828609915082828509935082848609945082858609915082828309915082828509935082848509915082828309905082818209905082818209905082818309915082828609945082858509935082848509915082828309915082828309915082828609945082858609915082828309915082828609915082828309915082828309915082828609915082828509935082848509915082828309905082818209905082818309905082818509905082818209905082818209905082818209905082818209905082818309915082828609945082858609915082828609915082828509935082848509915082828509915082828309915082828309905082818309905082818209838182099050838182099050838182099050838182099050838183099150508281830991508282860994508285850993508284850991508282860994508285850993508284860994508285850993508284860994508285860991508282860991508282830991508282850993508284850991508282830991508282860994508285850993508284850991508282850991508282860994508285850993508284860994508285850993508284850991508282830991508282850991508282860994508285860991508282860991508282850993508284860994508285850993508284860994508285850993508284850991508282850991508282830991508282860994508285850993508284850991508282850991508282830991508282860994508285860991508282830990508281820990508281830990508281860990508281820990508281820990508281820990508281820990508281830991508282850993508284860994508285850993508284860994508285860991508282860991508282830991508282830991508282830991508282860991508282850993508284850991508282850991508282830991508282860994508285860991508282860991508282850993508284860994508285860991508282830991508282850993508284860994508285860991508282850993508284860994508285850993508284850991508282850991508282860994508285850993508284850991508282850991508282830991508282830991508282860994508285860991508282830991508282830991508282860991508282850993508284860994508285860991508282860990508281820990508281820990508281830991508282850993508284850991508282860994508285850993508284860994508285850993508284860994508285850993508284850991508282850990508281850991508282830991508282830991508282820991505081818509935081848409925081838509935081848409925081838509935081848509905081818509905081818409925050808284099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808383099392505050565b6040516000907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00906136d7908690869086906020016142bf565b604051602081830303815290604052805190602001201690509392505050565b6000828060011a60f81b7fff00000000000000000000000000000000000000000000000000000000000000161561375a576040517fb36eb03600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7dff000000000000000000000000000000000000000000000000000000000060e884901b16177e0100000000000000000000000000000000000000000000000000000000000017905092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146137cd57600080fd5b919050565b600080604083850312156137e557600080fd5b6137ee836137a9565b946020939093013593505050565b60006020828403121561380e57600080fd5b5035919050565b60006020828403121561382757600080fd5b610696826137a9565b60008083601f84011261384257600080fd5b50813567ffffffffffffffff81111561385a57600080fd5b60208301915083602082850101111561387257600080fd5b9250929050565b60008060006040848603121561388e57600080fd5b83359250602084013567ffffffffffffffff8111156138ac57600080fd5b6138b886828701613830565b9497909650939450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561393b5761393b6138c5565b604052919050565b600067ffffffffffffffff82111561395d5761395d6138c5565b5060051b60200190565b600082601f83011261397857600080fd5b8135602061398d61398883613943565b6138f4565b82815260059290921b840181019181810190868411156139ac57600080fd5b8286015b848110156139c757803583529183019183016139b0565b509695505050505050565b600080604083850312156139e557600080fd5b823567ffffffffffffffff808211156139fd57600080fd5b818501915085601f830112613a1157600080fd5b81356020613a2161398883613943565b82815260059290921b84018101918181019089841115613a4057600080fd5b948201945b83861015613a6557613a56866137a9565b82529482019490820190613a45565b96505086013592505080821115613a7b57600080fd5b50613a8885828601613967565b9150509250929050565b600081518084526020808501945080840160005b83811015613ac257815187529582019590820190600101613aa6565b509495945050505050565b6020815260006106966020830184613a92565b60008083601f840112613af257600080fd5b50813567ffffffffffffffff811115613b0a57600080fd5b6020830191508360208260051b850101111561387257600080fd5b60008060008060008060a08789031215613b3e57600080fd5b613b47876137a9565b95506020870135945060408701359350606087013567ffffffffffffffff811115613b7157600080fd5b613b7d89828a01613ae0565b979a9699509497949695608090950135949350505050565b8015158114613ba357600080fd5b50565b60008060408385031215613bb957600080fd5b823591506020830135613bcb81613b95565b809150509250929050565b60008060408385031215613be957600080fd5b50508035926020909101359150565b60008060008060008060008060a0898b031215613c1457600080fd5b613c1d896137a9565b9750613c2b60208a016137a9565b9650604089013567ffffffffffffffff80821115613c4857600080fd5b613c548c838d01613ae0565b909850965060608b0135915080821115613c6d57600080fd5b613c798c838d01613ae0565b909650945060808b0135915080821115613c9257600080fd5b50613c9f8b828c01613830565b999c989b5096995094979396929594505050565b600080600060608486031215613cc857600080fd5b505081359360208301359350604090920135919050565b600080600060408486031215613cf457600080fd5b83359250602084013567ffffffffffffffff811115613d1257600080fd5b6138b886828701613ae0565b60008060008060008060a08789031215613d3757600080fd5b613d40876137a9565b9550613d4e602088016137a9565b94506040870135935060608701359250608087013567ffffffffffffffff811115613d7857600080fd5b613d8489828a01613830565b979a9699509497509295939492505050565b600060208284031215613da857600080fd5b5051919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b838152604060208201526000610c36604083018486613daf565b604080825283519082018190526000906020906060840190828701845b82811015613e6157815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101613e2f565b50505083810382850152613e758186613a92565b9695505050505050565b60006020808385031215613e9257600080fd5b825167ffffffffffffffff811115613ea957600080fd5b8301601f81018513613eba57600080fd5b8051613ec861398882613943565b81815260059190911b82018301908381019087831115613ee757600080fd5b928401925b82841015613f0557835182529284019290840190613eec565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015260a060608201526000613f4b60a0830185613a92565b90508260808301529695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525060a06040830152613f9660a0830185613a92565b8281036060840152613fa88185613a92565b838103608090940193909352505060008152602001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561069957610699613fc5565b808202811582820484141761069957610699613fc5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261408b5761408b61404d565b500490565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156140c257600080fd5b8260051b80836020870137939093016020019392505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a0604083015261411460a0830186613a92565b8281036060840152614127818587614090565b83810360809094019390935250506000815260200195945050505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613e756080830184613a92565b604081526000614194604083018587614090565b9050826020830152949350505050565b8281526040602082015260006141bd6040830184613a92565b949350505050565b6000602082840312156141d757600080fd5b8151612edf81613b95565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a0608083015261422860a083018486613daf565b98975050505050505050565b6000826142435761424361404d565b500690565b60005b8381101561426357818101518382015260200161424b565b50506000910152565b6000825161427e818460208701614248565b9190910192915050565b6000806040838503121561429b57600080fd5b505080516020909101519092909150565b8082018082111561069957610699613fc5565b73ffffffffffffffffffffffffffffffffffffffff841681528260208201526060604082015260008251806060840152614300816080850160208701614248565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160800194935050505056fea2646970667358221220cb002f701e1383f3770988bb92900d67a44a83a2d126941d16180c38af3bdf6664736f6c634300081300336101206040523480156200001257600080fd5b506040516200174d3803806200174d83398101604081905262000035916200016e565b6040518060400160405280601281526020017115dc985c1c19590810dbdb1b185d195c985b60721b8152506040518060400160405280600481526020016315d0d3d360e21b8152508282600090816200008f919062000262565b5060016200009e838262000262565b5060ff81166080524660a052620000b4620000d2565b60c05250503360e05250506001600160a01b031661010052620003ac565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516200010691906200032e565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080604083850312156200018257600080fd5b82516001600160a01b03811681146200019a57600080fd5b602084015190925060ff81168114620001b257600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001e857607f821691505b6020821081036200020957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200025d57600081815260208120601f850160051c81016020861015620002385750805b601f850160051c820191505b81811015620002595782815560010162000244565b5050505b505050565b81516001600160401b038111156200027e576200027e620001bd565b62000296816200028f8454620001d3565b846200020f565b602080601f831160018114620002ce5760008415620002b55750858301515b600019600386901b1c1916600185901b17855562000259565b600085815260208120601f198616915b82811015620002ff57888601518255948401946001909101908401620002de565b50858210156200031e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200033e81620001d3565b600182811680156200035957600181146200036f57620003a0565b60ff1984168752821515830287019450620003a0565b8760005260208060002060005b85811015620003975781548a8201529084019082016200037c565b50505082870194505b50929695505050505050565b60805160a05160c05160e051610100516113326200041b60003960008181610242015281816103f801526108e40152600081816102ce01528181610387015281816106ec015281816107750152610873015260006106a801526000610673015260006101db01526113326000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c80636f307dc3116100cd578063a0712d6811610081578063bf376c7a11610066578063bf376c7a1461031e578063d505accf14610331578063dd62ed3e1461034457600080fd5b8063a0712d68146102f8578063a9059cbb1461030b57600080fd5b80637ecebe00116100b25780637ecebe00146102a95780638da5cb5b146102c957806395d89b41146102f057600080fd5b80636f307dc31461023d57806370a082311461028957600080fd5b806323b872dd116101245780633644e515116101095780633644e5151461020f57806339f476931461021757806342966c681461022a57600080fd5b806323b872dd146101c3578063313ce567146101d657600080fd5b80630357371d1461015657806306fdde031461016b578063095ea7b31461018957806318160ddd146101ac575b600080fd5b610169610164366004610fcb565b61036f565b005b610173610423565b6040516101809190610ff5565b60405180910390f35b61019c610197366004610fcb565b6104b1565b6040519015158152602001610180565b6101b560025481565b604051908152602001610180565b61019c6101d1366004611061565b61052b565b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610180565b6101b561066f565b610169610225366004610fcb565b6106ca565b61016961023836600461109d565b6106d4565b6102647f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610180565b6101b56102973660046110b6565b60036020526000908152604090205481565b6101b56102b73660046110b6565b60056020526000908152604090205481565b6102647f000000000000000000000000000000000000000000000000000000000000000081565b610173610750565b61016961030636600461109d565b61075d565b61019c610319366004610fcb565b6107d6565b61016961032c366004610fcb565b61085b565b61016961033f3660046110d8565b610916565b6101b561035236600461114b565b600460209081526000928352604080842090915290825290205481565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103de576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61041f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383610c3a565b5050565b600080546104309061117e565b80601f016020809104026020016040519081016040528092919081815260200182805461045c9061117e565b80156104a95780601f1061047e576101008083540402835291602001916104a9565b820191906000526020600020905b81548152906001019060200180831161048c57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906105199086815260200190565b60405180910390a35060015b92915050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146105bf5761058d8382611200565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040812080548592906105f4908490611200565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061065c9087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146106a5576106a0610d0f565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6103de3382610da9565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610743576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61074d3382610da9565b50565b600180546104309061117e565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146107cc576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61074d3382610e3f565b336000908152600360205260408120805483919083906107f7908490611200565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906105199086815260200190565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146108ca576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61090c73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084610eb0565b61041f8282610e3f565b42841015610985576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161099161066f565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610ae3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610b5e57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e4552000000000000000000000000000000000000604482015260640161097c565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610d09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c45440000000000000000000000000000000000604482015260640161097c565b50505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051610d419190611213565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604081208054839290610dde908490611200565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b8060026000828254610e5191906112e9565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610e33565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610f9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640161097c565b5050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fc657600080fd5b919050565b60008060408385031215610fde57600080fd5b610fe783610fa2565b946020939093013593505050565b600060208083528351808285015260005b8181101561102257858101830151858201604001528201611006565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008060006060848603121561107657600080fd5b61107f84610fa2565b925061108d60208501610fa2565b9150604084013590509250925092565b6000602082840312156110af57600080fd5b5035919050565b6000602082840312156110c857600080fd5b6110d182610fa2565b9392505050565b600080600080600080600060e0888a0312156110f357600080fd5b6110fc88610fa2565b965061110a60208901610fa2565b95506040880135945060608801359350608088013560ff8116811461112e57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561115e57600080fd5b61116783610fa2565b915061117560208401610fa2565b90509250929050565b600181811c9082168061119257607f821691505b6020821081036111cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610525576105256111d1565b600080835481600182811c91508083168061122f57607f831692505b60208084108203611267577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b81801561127b57600181146112ae576112db565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528415158502890196506112db565b60008a81526020902060005b868110156112d35781548b8201529085019083016112ba565b505084890196505b509498975050505050505050565b80820180821115610525576105256111d156fea2646970667358221220ad3d29a4463d14a148a3849050be8e5252fd8bc37be24d48ae47ffef67fa5b4664736f6c634300081300330000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760450000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061020a5760003560e01c80638a0db6151161012a578063bc197c81116100bd578063dbeccb231161008c578063f23a6e6111610071578063f23a6e6114610569578063f242432a146105a2578063fbfa77cf146105b557600080fd5b8063dbeccb2314610543578063e200affd1461055657600080fd5b8063bc197c81146104a8578063c64748c414610514578063d73792a914610527578063dafaf94a1461053057600080fd5b8063a78695b0116100f9578063a78695b014610448578063add4c7841461046f578063b10c5c1714610482578063b7f75d2c1461049557600080fd5b80638a0db615146104075780638bad0c0a1461041a5780639e7212ad14610422578063a3d7da1d1461043557600080fd5b8063429b62e5116101a2578063752b5ba511610171578063752b5ba51461039f5780637ad7fe36146103b25780637ae2e67b146103cd5780637e3b74c3146103e057600080fd5b8063429b62e5146103395780634e1273f414610359578063704802751461037957806372ce42751461038c57600080fd5b806322a9339f116101de57806322a9339f1461027057806324d7806c146102bc5780632582cb5e1461030657806330f4f4bb1461031957600080fd5b8062fdd58e1461020f57806304329c03146102355780631785f53c146102485780631d69b48d1461025d575b600080fd5b61022261021d3660046137d2565b6105dc565b6040519081526020015b60405180910390f35b6102226102433660046137fc565b61069f565b61025b610256366004613815565b610703565b005b61022261026b366004613879565b61079f565b6102977f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604581565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161022c565b6102f66102ca366004613815565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160208190526040909120541490565b604051901515815260200161022c565b6102226103143660046137fc565b61096b565b6102226103273660046137fc565b60009081526020819052604090205490565b610222610347366004613815565b60016020526000908152604090205481565b61036c6103673660046139d2565b610986565b60405161022c9190613acd565b61025b610387366004613815565b610a60565b61025b61039a366004613b25565b610aff565b6102226103ad366004613ba6565b610b96565b61029773a5ef39c3d3e10d0b270233af41cac69796b1296681565b6102f66103db3660046137fc565b610c3f565b6102977f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e281565b610222610415366004613879565b610c57565b61025b610cf7565b61025b610430366004613b25565b610d7c565b61025b610443366004613bd6565b610e0b565b6102977f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417481565b61022261047d3660046137fc565b6110b0565b61025b610490366004613bd6565b6110c8565b6102226104a33660046137fc565b611330565b6104e36104b6366004613bf8565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161022c565b61025b610522366004613cb3565b611348565b61022261271081565b61029761053e3660046137fc565b611c28565b61025b610551366004613cdf565b611c3c565b61025b610564366004613ba6565b611f8c565b6104e3610577366004613d1e565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61025b6105b0366004613d1e565b612087565b6102977f0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d81565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390526000917f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760459091169062fdd58e90604401602060405180830381865afa158015610672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106969190613d96565b90505b92915050565b604080513060601b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166020808301919091526034820184905260026054808401919091528351808403909101815260749092019092528051910120600090610699565b336000908152600160208190526040909120541461074d576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160205260408082208290555133917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a350565b60008060006107ad86612273565b9150915060006107bc8361069f565b6040517fd42dc0c2000000000000000000000000000000000000000000000000000000008152600481018290529091507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff169063d42dc0c290602401602060405180830381865afa15801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086e9190613d96565b600003610923576040517fd96ee75400000000000000000000000000000000000000000000000000000000815230600482015260248101849052600260448201527f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff169063d96ee75490606401600060405180830381600087803b15801561090a57600080fd5b505af115801561091e573d6000803e3d6000fd5b505050505b82877faac410f87d423a922a7b226ac68f0c2eaf5bf6d15e644ac0758c7f96e2c253f784898960405161095893929190613df8565b60405180910390a3509095945050505050565b60008181526020819052604081205460d81c61ffff16610699565b6040517f4e1273f400000000000000000000000000000000000000000000000000000000815260609073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760451690634e1273f4906109fd9086908690600401613e12565b600060405180830381865afa158015610a1a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106969190810190613e7f565b3360009081526001602081905260409091205414610aaa576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160208190526040808320919091555133917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a350565b7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610b84576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e8482610e0b565b505050505050565b600080610bbd81610ba68661069f565b85610bb2576002610bb5565b60015b60ff16612358565b604080517f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602080830191909152603480830185905283518084039091018152605490920190925280519101209091506000905b95945050505050565b600081815260208190526040812054610699906127ba565b600080610c9a8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127f992505050565b90503373ffffffffffffffffffffffffffffffffffffffff16817ff059ab16d1ca60e123eab60e3c02b68faf060347c701a5d14885a8e1def7b3a8878787604051610ce793929190613df8565b60405180910390a3949350505050565b3360009081526001602081905260409091205414610d41576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600160205260408082208290555182917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a3565b7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610e01576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e84826110c8565b610e4d73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174163330846128f7565b6040517fbf376c7a000000000000000000000000000000000000000000000000000000008152306004820152602481018290527f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff169063bf376c7a90604401600060405180830381600087803b158015610edb57600080fd5b505af1158015610eef573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff166372ce42757f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e26000801b85610f5d6129e9565b866040518663ffffffff1660e01b8152600401610f7e959493929190613f10565b600060405180830381600087803b158015610f9857600080fd5b505af1158015610fac573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d630336110187f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e287612a54565b611023600287612b57565b6040518563ffffffff1660e01b81526004016110429493929190613f5d565b600060405180830381600087803b15801561105c57600080fd5b505af1158015611070573d6000803e3d6000fd5b50506040518381528492503391507fbbed930dbfb7907ae2d60ddf78345610214f26419a0128df39b6cc3d9e5df9b0906020015b60405180910390a35050565b60008181526020819052604081205461069990612bd9565b60006110f47f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e284612a54565b90507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6333084611140600288612b57565b6040518563ffffffff1660e01b815260040161115f9493929190613f5d565b600060405180830381600087803b15801561117957600080fd5b505af115801561118d573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16639e7212ad7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e26000801b866111fb6129e9565b876040518663ffffffff1660e01b815260040161121c959493929190613f10565b600060405180830381600087803b15801561123657600080fd5b505af115801561124a573d6000803e3d6000fd5b50506040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff1692506339f476939150604401600060405180830381600087803b1580156112dc57600080fd5b505af11580156112f0573d6000803e3d6000fd5b50506040518481528592503391507fba33ac50d8894676597e6e35dc09cff59854708b642cd069d21eb9c7ca072a049060200160405180910390a3505050565b60008181526020819052604081205461069990612be6565b6000838152602081905260408120549061136182612be6565b905073ffffffffffffffffffffffffffffffffffffffff82166113b0576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181116113ea576040517f24f2dfe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611424576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83811c1561145e576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361146d575050505050565b6000805b82821015611493576001821b861615611488576001015b816001019150611471565b600061149f8285613ff4565b905060008267ffffffffffffffff8111156114bc576114bc6138c5565b6040519080825280602002602001820160405280156114e5578160200160208202803683370190505b50905060008267ffffffffffffffff811115611503576115036138c5565b60405190808252806020026020018201604052801561152c578160200160208202803683370190505b50905060008367ffffffffffffffff81111561154a5761154a6138c5565b604051908082528060200260200182016040528015611573578160200160208202803683370190505b50905073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e21663a0712d686115bc8b87614007565b6040518263ffffffff1660e01b81526004016115da91815260200190565b600060405180830381600087803b1580156115f457600080fd5b505af1158015611608573d6000803e3d6000fd5b50505050600080600097505b888810156116d85760ff88168d016001891b8d161561166157611638816000610b96565b86848151811061164a5761164a61401e565b6020026020010181815250508260010192506116cc565b61166c816001610b96565b85838151811061167e5761167e61401e565b602002602001018181525050611695816000610b96565b8483815181106116a7576116a761401e565b6020026020010181815250506116c56116bf8261069f565b8d612bef565b8160010191505b88600101985050611614565b50507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6337fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c8661174788518f612b57565b6040518563ffffffff1660e01b81526004016117669493929190613f5d565b600060405180830381600087803b15801561178057600080fd5b505af1158015611794573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c84611804898f612b57565b6040518563ffffffff1660e01b81526004016118239493929190613f5d565b600060405180830381600087803b15801561183d57600080fd5b505af1158015611851573d6000803e3d6000fd5b506000925061271091505060d88a901c61ffff1661186f908c614007565b611879919061407c565b90506000611887828c613ff4565b9050600185511115611a62576000600186516118a39190613ff4565b905082156119965773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e216630357371d7f0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d6119128685614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b15801561197d57600080fd5b505af1158015611991573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e216630357371d336119dd8585614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b158015611a4857600080fd5b505af1158015611a5c573d6000803e3d6000fd5b50505050505b835115611bc7578115611b2b577f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307f0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d87611ad9895188612b57565b6040518563ffffffff1660e01b8152600401611af89493929190613f5d565b600060405180830381600087803b158015611b1257600080fd5b505af1158015611b26573d6000803e3d6000fd5b505050505b7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6303387611b75895187612b57565b6040518563ffffffff1660e01b8152600401611b949493929190613f5d565b600060405180830381600087803b158015611bae57600080fd5b505af1158015611bc2573d6000803e3d6000fd5b505050505b8b8d3373ffffffffffffffffffffffffffffffffffffffff167fb03d19dddbc72a87e735ff0ea3b57bef133ebe44e1894284916a84044deb367e8e604051611c1191815260200190565b60405180910390a450505050505050505050505050565b600081815260208190526040812054610699565b6000611c687f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e285612a54565b6040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760451690632eb2c2d690611ce590339030908690899089906004016140db565b600060405180830381600087803b158015611cff57600080fd5b505af1158015611d13573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff166301b7037c7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e26000801b87611d816129e9565b6040518563ffffffff1660e01b8152600401611da09493929190614145565b600060405180830381600087803b158015611dba57600080fd5b505af1158015611dce573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600092507f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff1691506370a0823190602401602060405180830381865afa158015611e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e839190613d96565b90508015611f32576040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff16906339f4769390604401600060405180830381600087803b158015611f1957600080fd5b505af1158015611f2d573d6000803e3d6000fd5b505050505b843373ffffffffffffffffffffffffffffffffffffffff167f9140a6a270ef945260c03894b3c6b3b2695e9d5101feef0ff24fec960cfd3224868685604051611f7d93929190614180565b60405180910390a35050505050565b611f968282612ca6565b7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff1663c49298ac83611fdc84612e26565b6040518363ffffffff1660e01b8152600401611ff99291906141a4565b600060405180830381600087803b15801561201357600080fd5b505af1158015612027573d6000803e3d6000fd5b5050505081612055837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690565b60405183151581527f9e9fa7fd355160bd4cd3f22d4333519354beff1f5689bde87f2c5e63d8d484b2906020016110a4565b33600090815260016020819052604090912054146120d1576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301523360248301527f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045169063e985e9c590604401602060405180830381865afa158015612163573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218791906141c5565b6121bd576040517fcd7769ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045169063f242432a90612239908990899089908990899089906004016141e2565b600060405180830381600087803b15801561225357600080fd5b505af1158015612267573d6000803e3d6000fd5b50505050505050505050565b60008181526020819052604081205481908073ffffffffffffffffffffffffffffffffffffffff81166122d2576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612321576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61232a82612be6565b925060ff83168501935061233d82612eb2565b60009586526020869052604090952094909455509092909150565b6000808383604051602001612377929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120905060ff81901c15156000805b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476001850893507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780878809870908905061243781612ee6565b9150807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47838409036123ba578280156124785750612476600283614234565b155b806124965750821580156124965750612492600283614234565b6001145b156124c8576124c5827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b91505b8780156127755760fe81901c151593507f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808485098409089150600061255283612ee6565b90508480156125695750612567600282614234565b155b806125875750841580156125875750612583600282614234565b6001145b156125b9576125b6817f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b90505b827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478283091461264a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420706172656e7420636f6c6c656374696f6e2049440000000060448201526064015b60405180910390fd5b60408051602081018890529081018590526060810183905260808101829052600090819060069060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526126ac9161426c565b600060405180830381855afa9150503d80600081146126e7576040519150601f19603f3d011682016040523d82523d6000602084013e6126ec565b606091505b509150915081612758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f6563616464206661696c656400000000000000000000000000000000000000006044820152606401612641565b8080602001905181019061276c9190614288565b90985095505050505b612780600284614234565b6001036127ad577f4000000000000000000000000000000000000000000000000000000000000000851894505b5092979650505050505050565b60008160011a60f81b7fff0000000000000000000000000000000000000000000000000000000000000016156127f1576001610699565b600092915050565b60003361280781858561369d565b6000818152602081905260408120549193508173ffffffffffffffffffffffffffffffffffffffff1614612867576040517fd2b4c0c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127108511156128a3576040517ffc520af500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82167cffff00000000000000000000000000000000000000000000000000000060d887901b161760008481526020819052604090205550909392505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806129e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401612641565b5050505050565b60408051600280825260608083018452926000929190602083019080368337019050509050600181600081518110612a2357612a2361401e565b602002602001018181525050600281600181518110612a4457612a4461401e565b6020908102919091010152919050565b60408051600280825260608083018452926000929190602083019080368337019050509050612b0384612a8a6000866001612358565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b16602082015260348101829052600090605401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b81600081518110612b1657612b1661401e565b6020908102919091010152612b3284612a8a6000866002612358565b81600181518110612b4557612b4561401e565b60209081029190910101529392505050565b606060008367ffffffffffffffff811115612b7457612b746138c5565b604051908082528060200260200182016040528015612b9d578160200160208202803683370190505b50905060005b84811015612bd15783828281518110612bbe57612bbe61401e565b6020908102919091010152600101612ba3565b509392505050565b60008160025b1a92915050565b60008181612bdf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045166372ce42757f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e2600085612c576129e9565b866040518663ffffffff1660e01b8152600401612c78959493929190613f10565b600060405180830381600087803b158015612c9257600080fd5b505af1158015610b8e573d6000803e3d6000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00821660008181526020819052604090205460ff8416908073ffffffffffffffffffffffffffffffffffffffff8116612d2b576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612d7a576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d8382612be6565b8310612dbb576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841515600103610b8e57612dce826127ba565b15612e05576040517fe3b0238900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e0f82846136f7565b600085815260208190526040902055505050505050565b6040805160028082526060808301845292600092919060208301908036833701905050905082612e57576000612e5a565b60015b60ff1681600081518110612e7057612e7061401e565b60200260200101818152505082612e88576001612e8b565b60005b60ff1681600181518110612ea157612ea161401e565b602090810291909101015292915050565b600081612edf7f0100000000000000000000000000000000000000000000000000000000000000826142ac565b9392505050565b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808380099150808283098181820990508181840992508183850993508184840992508183840990508181820982818309905082818209905082818209905082818309915082828609945082858609915082828309915082828509935082848509915082828309915082828309915082828509915082828609945082858609915082828309915082828309915082828609915082828509935082848609945082858609915082828309915082828509935082848509915082828309905082818209905082818209905082818309915082828609945082858509935082848509915082828309915082828309915082828609945082858609915082828309915082828609915082828309915082828309915082828609915082828509935082848509915082828309905082818209905082818309905082818509905082818209905082818209905082818209905082818209905082818309915082828609945082858609915082828609915082828509935082848509915082828509915082828309915082828309905082818309905082818209838182099050838182099050838182099050838182099050838183099150508281830991508282860994508285850993508284850991508282860994508285850993508284860994508285850993508284860994508285860991508282860991508282830991508282850993508284850991508282830991508282860994508285850993508284850991508282850991508282860994508285850993508284860994508285850993508284850991508282830991508282850991508282860994508285860991508282860991508282850993508284860994508285850993508284860994508285850993508284850991508282850991508282830991508282860994508285850993508284850991508282850991508282830991508282860994508285860991508282830990508281820990508281830990508281860990508281820990508281820990508281820990508281820990508281830991508282850993508284860994508285850993508284860994508285860991508282860991508282830991508282830991508282830991508282860991508282850993508284850991508282850991508282830991508282860994508285860991508282860991508282850993508284860994508285860991508282830991508282850993508284860994508285860991508282850993508284860994508285850993508284850991508282850991508282860994508285850993508284850991508282850991508282830991508282830991508282860994508285860991508282830991508282830991508282860991508282850993508284860994508285860991508282860990508281820990508281820990508281830991508282850993508284850991508282860994508285850993508284860994508285850993508284860994508285850993508284850991508282850990508281850991508282830991508282830991508282820991505081818509935081848409925081838509935081848409925081838509935081848509905081818509905081818409925050808284099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808383099392505050565b6040516000907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00906136d7908690869086906020016142bf565b604051602081830303815290604052805190602001201690509392505050565b6000828060011a60f81b7fff00000000000000000000000000000000000000000000000000000000000000161561375a576040517fb36eb03600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7dff000000000000000000000000000000000000000000000000000000000060e884901b16177e0100000000000000000000000000000000000000000000000000000000000017905092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146137cd57600080fd5b919050565b600080604083850312156137e557600080fd5b6137ee836137a9565b946020939093013593505050565b60006020828403121561380e57600080fd5b5035919050565b60006020828403121561382757600080fd5b610696826137a9565b60008083601f84011261384257600080fd5b50813567ffffffffffffffff81111561385a57600080fd5b60208301915083602082850101111561387257600080fd5b9250929050565b60008060006040848603121561388e57600080fd5b83359250602084013567ffffffffffffffff8111156138ac57600080fd5b6138b886828701613830565b9497909650939450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561393b5761393b6138c5565b604052919050565b600067ffffffffffffffff82111561395d5761395d6138c5565b5060051b60200190565b600082601f83011261397857600080fd5b8135602061398d61398883613943565b6138f4565b82815260059290921b840181019181810190868411156139ac57600080fd5b8286015b848110156139c757803583529183019183016139b0565b509695505050505050565b600080604083850312156139e557600080fd5b823567ffffffffffffffff808211156139fd57600080fd5b818501915085601f830112613a1157600080fd5b81356020613a2161398883613943565b82815260059290921b84018101918181019089841115613a4057600080fd5b948201945b83861015613a6557613a56866137a9565b82529482019490820190613a45565b96505086013592505080821115613a7b57600080fd5b50613a8885828601613967565b9150509250929050565b600081518084526020808501945080840160005b83811015613ac257815187529582019590820190600101613aa6565b509495945050505050565b6020815260006106966020830184613a92565b60008083601f840112613af257600080fd5b50813567ffffffffffffffff811115613b0a57600080fd5b6020830191508360208260051b850101111561387257600080fd5b60008060008060008060a08789031215613b3e57600080fd5b613b47876137a9565b95506020870135945060408701359350606087013567ffffffffffffffff811115613b7157600080fd5b613b7d89828a01613ae0565b979a9699509497949695608090950135949350505050565b8015158114613ba357600080fd5b50565b60008060408385031215613bb957600080fd5b823591506020830135613bcb81613b95565b809150509250929050565b60008060408385031215613be957600080fd5b50508035926020909101359150565b60008060008060008060008060a0898b031215613c1457600080fd5b613c1d896137a9565b9750613c2b60208a016137a9565b9650604089013567ffffffffffffffff80821115613c4857600080fd5b613c548c838d01613ae0565b909850965060608b0135915080821115613c6d57600080fd5b613c798c838d01613ae0565b909650945060808b0135915080821115613c9257600080fd5b50613c9f8b828c01613830565b999c989b5096995094979396929594505050565b600080600060608486031215613cc857600080fd5b505081359360208301359350604090920135919050565b600080600060408486031215613cf457600080fd5b83359250602084013567ffffffffffffffff811115613d1257600080fd5b6138b886828701613ae0565b60008060008060008060a08789031215613d3757600080fd5b613d40876137a9565b9550613d4e602088016137a9565b94506040870135935060608701359250608087013567ffffffffffffffff811115613d7857600080fd5b613d8489828a01613830565b979a9699509497509295939492505050565b600060208284031215613da857600080fd5b5051919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b838152604060208201526000610c36604083018486613daf565b604080825283519082018190526000906020906060840190828701845b82811015613e6157815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101613e2f565b50505083810382850152613e758186613a92565b9695505050505050565b60006020808385031215613e9257600080fd5b825167ffffffffffffffff811115613ea957600080fd5b8301601f81018513613eba57600080fd5b8051613ec861398882613943565b81815260059190911b82018301908381019087831115613ee757600080fd5b928401925b82841015613f0557835182529284019290840190613eec565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015260a060608201526000613f4b60a0830185613a92565b90508260808301529695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525060a06040830152613f9660a0830185613a92565b8281036060840152613fa88185613a92565b838103608090940193909352505060008152602001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561069957610699613fc5565b808202811582820484141761069957610699613fc5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261408b5761408b61404d565b500490565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156140c257600080fd5b8260051b80836020870137939093016020019392505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a0604083015261411460a0830186613a92565b8281036060840152614127818587614090565b83810360809094019390935250506000815260200195945050505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613e756080830184613a92565b604081526000614194604083018587614090565b9050826020830152949350505050565b8281526040602082015260006141bd6040830184613a92565b949350505050565b6000602082840312156141d757600080fd5b8151612edf81613b95565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a0608083015261422860a083018486613daf565b98975050505050505050565b6000826142435761424361404d565b500690565b60005b8381101561426357818101518382015260200161424b565b50506000910152565b6000825161427e818460208701614248565b9190910192915050565b6000806040838503121561429b57600080fd5b505080516020909101519092909150565b8082018082111561069957610699613fc5565b73ffffffffffffffffffffffffffffffffffffffff841681528260208201526060604082015260008251806060840152614300816080850160208701614248565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160800194935050505056fea2646970667358221220cb002f701e1383f3770988bb92900d67a44a83a2d126941d16180c38af3bdf6664736f6c63430008130033

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

0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760450000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d

-----Decoded View---------------
Arg [0] : _ctf (address): 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
Arg [1] : _collateral (address): 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
Arg [2] : _vault (address): 0x7f67327E88c258932D7d8f72950bE0d46975E11D

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045
Arg [1] : 0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174
Arg [2] : 0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d


Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ 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.