Contract 0xdcbe79f74c98368141798ea0b7b979b9ba54b026 2

Contract Overview

Balance:
404.483169855806212637 MOVR

MOVR Value:
$3,391.19 (@ $8.38/MOVR)

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x70baa3dc81d7f9f2953bbf072a6bdb2860b648ab2ae95cd97777b662e9b6684dRemove Liquidity39489552023-04-02 5:35:426 hrs 33 mins ago0x891da613d26ef051eca35ea337428c514d271c98 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033046475
0x4bd7c2cbdf0dad64e1b1d8268ef4945e27836224eb29c4d72a3fc349a5756ffbAdd Liquidity39489342023-04-02 5:31:246 hrs 37 mins ago0x891da613d26ef051eca35ea337428c514d271c98 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0261.2 MOVR0.0002786135
0xd0a4df10faf14edd74dc8abf76987dea7e9ea9ab5f7e0a68322f6f4413f6638aBuy39368262023-03-31 11:57:362 days 11 mins ago0x7d0a5d9596337ffceff4ae3d68d51c8cf91f0123 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0262 MOVR0.0004715925
0x52b837302a076d7c752966c14b08be05f6dbbd95bfbff0ebb21b9c79c551574dAdd Liquidity39367412023-03-31 11:40:062 days 28 mins ago0x7d0a5d9596337ffceff4ae3d68d51c8cf91f0123 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0262 MOVR0.00032127
0xa8187d972b23f697a16f0d9b3b163d9ffdf8f56985ce238b048b9923d2db799bCreate Market39367362023-03-31 11:39:062 days 29 mins ago0x7d0a5d9596337ffceff4ae3d68d51c8cf91f0123 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0263 MOVR0.0020690775
0xaff58852e7894f5fac226d5091bfb732246a923f3a9074bd93ea6543e0bba00fBuy39365022023-03-31 10:51:062 days 1 hr ago0x7d0a5d9596337ffceff4ae3d68d51c8cf91f0123 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0262 MOVR0.0003433875
0x3f4540b4302124d3b4e0921e73af7564ffb57f4739eeeff4e83e38e8ba50c981Claim Liquidity39341772023-03-31 2:52:062 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x7dd1b8485580e935179af11b46fcdc074b0077055292402b711c367acd38f0aaClaim Liquidity39341222023-03-31 2:40:182 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x8c2aa4bfc05318f255920ad9ff7b08e5d35a0aade0acf4b41f216363e6e5a342Claim Liquidity39341212023-03-31 2:40:002 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x4d52ccc771160db2ebf6f2ab0a142b1b812cc2c33e9c3e0c47e350774d65975aResolve Market O...39341072023-03-31 2:37:122 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00031561875
0x3fd74bcf8ae1ac14597be727612479837520bc8e39f9f2c4ea22adf59708ee6cResolve Market O...39341062023-03-31 2:37:002 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x7d46a3bd542aaeaa200ceba5e3304ae51ef77d665e7dc90c475b2ca056ce477bClaim Liquidity39341032023-03-31 2:36:242 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x89efbcb5c7729264e2341a69a29ffe3bd40088b2a8acdb22f8aca7cfbfbbbf92Claim Liquidity39341032023-03-31 2:36:242 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x57509315e2df5ea607e3d138bc954819ae77a6914ae354cf19b7276ab2cf6898Claim Liquidity39341022023-03-31 2:36:122 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0xecb9f6e58f79dd7aff779373960a7b942cebad4afc1f04d0d21a7e83787bba38Claim Liquidity39341022023-03-31 2:36:122 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x4f334afff07dcb544e316e44effc91684165c3e8045ed44dfefb5343b4db6920Claim Liquidity39341012023-03-31 2:36:002 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00029024625
0x098d5fa30e861517e13d4e8ac81431505f9c89ef7bf2033330823c19c3c6d3ccResolve Market O...39340952023-03-31 2:34:482 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x6c897ccc1733cb1d882f7761b21b0dfcad6ed4e7e522b6248444b67b4ead35e3Resolve Market O...39340942023-03-31 2:34:302 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x9b09b1965bd667f29ded7e64f31f0c05d8d757a8197ff44ed305425e5496248fResolve Market O...39340932023-03-31 2:34:182 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00031561875
0x2ef6d13d24a81936d20bb11e982d9884116bc23bb90f47218aac6dd264776417Resolve Market O...39340922023-03-31 2:34:062 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x1f45b66834ec69bb8ff228f6e739e8e58f3bf3a88a81812bfa3d70863111f4fcResolve Market O...39340902023-03-31 2:33:422 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00031561875
0x6615417d09794061f41ffb591ed706045ae729599229d8a82f1f0d60a50889cdResolve Market O...39340862023-03-31 2:32:542 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x8109205507e991fdbcf009b8b3328d16822e828046d2cd04eeece858bf74fc16Resolve Market O...39340852023-03-31 2:32:422 days 9 hrs ago0x200f28a82317d84cd2932e4b6e7a9aa0376053d6 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x1bc348e31ade8226b56bd81198dcc8cd1c299d0e40850d3baed5d2fe781815bdResolve Market O...39333382023-03-30 23:58:542 days 12 hrs ago0xb415fa3fce264ddb928fcbb0d0041cb248f979d1 IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260 MOVR0.00033361875
0x1d1aea81af46c4caa2fef08d5e8b0be9b8577034f6080f465e74a0470473cfebCreate Market39332252023-03-30 23:35:242 days 12 hrs ago0x61c55c82bb98afafe51ceff9c8e2d5bbd390f56a IN  0xdcbe79f74c98368141798ea0b7b979b9ba54b0260.01 MOVR0.001926568
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x70baa3dc81d7f9f2953bbf072a6bdb2860b648ab2ae95cd97777b662e9b6684d39489552023-04-02 5:35:426 hrs 33 mins ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x891da613d26ef051eca35ea337428c514d271c980.36288723695596002 MOVR
0x70baa3dc81d7f9f2953bbf072a6bdb2860b648ab2ae95cd97777b662e9b6684d39489552023-04-02 5:35:426 hrs 33 mins ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x891da613d26ef051eca35ea337428c514d271c980.000000029243438074 MOVR
0x3f4540b4302124d3b4e0921e73af7564ffb57f4739eeeff4e83e38e8ba50c98139341772023-03-31 2:52:062 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.02 MOVR
0x7dd1b8485580e935179af11b46fcdc074b0077055292402b711c367acd38f0aa39341222023-03-31 2:40:182 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.02 MOVR
0x8c2aa4bfc05318f255920ad9ff7b08e5d35a0aade0acf4b41f216363e6e5a34239341212023-03-31 2:40:002 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.01 MOVR
0x7d46a3bd542aaeaa200ceba5e3304ae51ef77d665e7dc90c475b2ca056ce477b39341032023-03-31 2:36:242 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.02 MOVR
0x89efbcb5c7729264e2341a69a29ffe3bd40088b2a8acdb22f8aca7cfbfbbbf9239341032023-03-31 2:36:242 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.02 MOVR
0x57509315e2df5ea607e3d138bc954819ae77a6914ae354cf19b7276ab2cf689839341022023-03-31 2:36:122 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.02 MOVR
0xecb9f6e58f79dd7aff779373960a7b942cebad4afc1f04d0d21a7e83787bba3839341022023-03-31 2:36:122 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.01 MOVR
0x4f334afff07dcb544e316e44effc91684165c3e8045ed44dfefb5343b4db692039341012023-03-31 2:36:002 days 9 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x200f28a82317d84cd2932e4b6e7a9aa0376053d60.01 MOVR
0x8e4b7d6ea9f0ee4cd5cd9b51d8fe7d948d9e7851b2730f249c394c6071838e6039259442023-03-29 22:30:423 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260xc4d5552b2c441f38e45045c0cd6fe0ef47317cef3.254828017139830312 MOVR
0xad28c5acca0be41e31497dcb212b5e74b29981ee21812132710433e90cf907f339259422023-03-29 22:30:183 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df52215810.7782600004220777 MOVR
0xe316fd178ba4b18edc0d1587dfcc7e3fa87d5f046916f400e4db944001ac957339259402023-03-29 22:29:543 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x422acdb845a7dccde31d5773e1fcb443d71994990.025529257711415374 MOVR
0x1fbbe8719092e37f1296b4fc4fb4871c012e52a89afbb89e95679018fb73d51d39259382023-03-29 22:29:303 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df52215810.48443945208551065 MOVR
0x6da83d2dca73799b61da8ab014df2cf89985c6e69ed721e5bb86c9cf44e02bf839259362023-03-29 22:29:063 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df522158150.4868619352664 MOVR
0x1b8963fc2bd35a05b3204f33ba21892807e083ee1e9d47a163a41c86b1babf1239259362023-03-29 22:29:063 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x422acdb845a7dccde31d5773e1fcb443d71994990.3914924667715696 MOVR
0xdf113be54a4380f2f9f00ff70989f733378a1545f5620b8af1af6e15094e254639259362023-03-29 22:29:063 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df522158117.648396772586953969 MOVR
0xdf113be54a4380f2f9f00ff70989f733378a1545f5620b8af1af6e15094e254639259362023-03-29 22:29:063 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df52215810.711924194328713071 MOVR
0x3507495a5a1a9a4774c2f01717b9601bf6391daaba0a93c9771b3ad8b4bf061839259322023-03-29 22:28:183 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df52215810.7918537938642753 MOVR
0x2f4f8d0c596d7ed81908d8bc8e0b68b6ae61d3182eb78c71f99be0d4bc0e75bc39259302023-03-29 22:27:553 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x422acdb845a7dccde31d5773e1fcb443d71994990.026344413348142133 MOVR
0xd8e15c504caffb61ea55c54b591ba3d4d24a862bae0a04e9c0c0f9d2c9d5897c39259282023-03-29 22:27:243 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df52215810.4914271540730101 MOVR
0xfdcd5e45b20c479fdd4773fc2e94f8aeb8145f63af27453d5192865e5dd7b7ae39259262023-03-29 22:27:003 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df522158151.25934732124194 MOVR
0xa8dc6dd1c14fa8df242fea33bf9ae26276451b02238f80d6f81a4e4644f9685739259262023-03-29 22:27:003 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x422acdb845a7dccde31d5773e1fcb443d71994990.3915198802125439 MOVR
0xf482fae672c9f679e74daa8174c989875b9e776dbab5a4fd66839d41fb7008b539259262023-03-29 22:27:003 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df522158117.916019301548137116 MOVR
0xf482fae672c9f679e74daa8174c989875b9e776dbab5a4fd66839d41fb7008b539259262023-03-29 22:27:003 days 13 hrs ago 0xdcbe79f74c98368141798ea0b7b979b9ba54b0260x4f53b60d21e8a8e4c418fd308ab5d00df52215810.722810056786460597 MOVR
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PredictionMarket

Compiler Version
v0.6.2+commit.bacdbe57

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at moonriver.moonscan.io on 2021-11-03
*/

// File: contracts/RealitioERC20.sol

/**
 *Submitted for verification at Etherscan.io on 2021-06-09
*/

pragma solidity >0.4.24;

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

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

    event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity >0.4.24;

/**
 * @title ReailtioSafeMath256
 * @dev Math operations with safety checks that throw on error
 */
library RealitioSafeMath256 {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}
pragma solidity >0.4.24;

/**
 * @title RealitioSafeMath32
 * @dev Math operations with safety checks that throw on error
 * @dev Copy of SafeMath but for uint32 instead of uint256
 * @dev Deleted functions we don't use
 */
library RealitioSafeMath32 {
  function add(uint32 a, uint32 b) internal pure returns (uint32) {
    uint32 c = a + b;
    assert(c >= a);
    return c;
  }
}
pragma solidity >0.4.18;


contract BalanceHolder {

    IERC20 public token;

    mapping(address => uint256) public balanceOf;

    event LogWithdraw(
        address indexed user,
        uint256 amount
    );

    function withdraw()
    public {
        uint256 bal = balanceOf[msg.sender];
        balanceOf[msg.sender] = 0;
        require(token.transfer(msg.sender, bal));
        emit LogWithdraw(msg.sender, bal);
    }

}
pragma solidity >0.4.24;


contract RealitioERC20 is BalanceHolder {

    using RealitioSafeMath256 for uint256;
    using RealitioSafeMath32 for uint32;

    address constant NULL_ADDRESS = address(0);

    // History hash when no history is created, or history has been cleared
    bytes32 constant NULL_HASH = bytes32(0);

    // An unitinalized finalize_ts for a question will indicate an unanswered question.
    uint32 constant UNANSWERED = 0;

    // An unanswered reveal_ts for a commitment will indicate that it does not exist.
    uint256 constant COMMITMENT_NON_EXISTENT = 0;

    // Commit->reveal timeout is 1/8 of the question timeout (rounded down).
    uint32 constant COMMITMENT_TIMEOUT_RATIO = 8;

    event LogSetQuestionFee(
        address arbitrator,
        uint256 amount
    );

    event LogNewTemplate(
        uint256 indexed template_id,
        address indexed user,
        string question_text
    );

    event LogNewQuestion(
        bytes32 indexed question_id,
        address indexed user,
        uint256 template_id,
        string question,
        bytes32 indexed content_hash,
        address arbitrator,
        uint32 timeout,
        uint32 opening_ts,
        uint256 nonce,
        uint256 created
    );

    event LogFundAnswerBounty(
        bytes32 indexed question_id,
        uint256 bounty_added,
        uint256 bounty,
        address indexed user
    );

    event LogNewAnswer(
        bytes32 answer,
        bytes32 indexed question_id,
        bytes32 history_hash,
        address indexed user,
        uint256 bond,
        uint256 ts,
        bool is_commitment
    );

    event LogAnswerReveal(
        bytes32 indexed question_id,
        address indexed user,
        bytes32 indexed answer_hash,
        bytes32 answer,
        uint256 nonce,
        uint256 bond
    );

    event LogNotifyOfArbitrationRequest(
        bytes32 indexed question_id,
        address indexed user
    );

    event LogFinalize(
        bytes32 indexed question_id,
        bytes32 indexed answer
    );

    event LogClaim(
        bytes32 indexed question_id,
        address indexed user,
        uint256 amount
    );

    struct Question {
        bytes32 content_hash;
        address arbitrator;
        uint32 opening_ts;
        uint32 timeout;
        uint32 finalize_ts;
        bool is_pending_arbitration;
        uint256 bounty;
        bytes32 best_answer;
        bytes32 history_hash;
        uint256 bond;
    }

    // Stored in a mapping indexed by commitment_id, a hash of commitment hash, question, bond.
    struct Commitment {
        uint32 reveal_ts;
        bool is_revealed;
        bytes32 revealed_answer;
    }

    // Only used when claiming more bonds than fits into a transaction
    // Stored in a mapping indexed by question_id.
    struct Claim {
        address payee;
        uint256 last_bond;
        uint256 queued_funds;
    }

    uint256 nextTemplateID = 0;
    mapping(uint256 => uint256) public templates;
    mapping(uint256 => bytes32) public template_hashes;
    mapping(bytes32 => Question) public questions;
    mapping(bytes32 => Claim) public question_claims;
    mapping(bytes32 => Commitment) public commitments;
    mapping(address => uint256) public arbitrator_question_fees;

    modifier onlyArbitrator(bytes32 question_id) {
        require(msg.sender == questions[question_id].arbitrator, "msg.sender must be arbitrator");
        _;
    }

    modifier stateAny() {
        _;
    }

    modifier stateNotCreated(bytes32 question_id) {
        require(questions[question_id].timeout == 0, "question must not exist");
        _;
    }

    modifier stateOpen(bytes32 question_id) {
        require(questions[question_id].timeout > 0, "question must exist");
        require(!questions[question_id].is_pending_arbitration, "question must not be pending arbitration");
        uint32 finalize_ts = questions[question_id].finalize_ts;
        require(finalize_ts == UNANSWERED || finalize_ts > uint32(now), "finalization deadline must not have passed");
        uint32 opening_ts = questions[question_id].opening_ts;
        require(opening_ts == 0 || opening_ts <= uint32(now), "opening date must have passed");
        _;
    }

    modifier statePendingArbitration(bytes32 question_id) {
        require(questions[question_id].is_pending_arbitration, "question must be pending arbitration");
        _;
    }

    modifier stateOpenOrPendingArbitration(bytes32 question_id) {
        require(questions[question_id].timeout > 0, "question must exist");
        uint32 finalize_ts = questions[question_id].finalize_ts;
        require(finalize_ts == UNANSWERED || finalize_ts > uint32(now), "finalization dealine must not have passed");
        uint32 opening_ts = questions[question_id].opening_ts;
        require(opening_ts == 0 || opening_ts <= uint32(now), "opening date must have passed");
        _;
    }

    modifier stateFinalized(bytes32 question_id) {
        require(isFinalized(question_id), "question must be finalized");
        _;
    }

    modifier bondMustDouble(bytes32 question_id, uint256 tokens) {
        require(tokens > 0, "bond must be positive");
        require(tokens >= (questions[question_id].bond.mul(2)), "bond must be double at least previous bond");
        _;
    }

    modifier previousBondMustNotBeatMaxPrevious(bytes32 question_id, uint256 max_previous) {
        if (max_previous > 0) {
            require(questions[question_id].bond <= max_previous, "bond must exceed max_previous");
        }
        _;
    }

    function setToken(IERC20 _token)
    public
    {
        require(token == IERC20(0x0), "Token can only be initialized once");
        token = _token;
    }

    /// @notice Constructor, sets up some initial templates
    /// @dev Creates some generalized templates for different question types used in the DApp.
    constructor()
    public {
        createTemplate('{"title": "%s", "type": "bool", "category": "%s", "lang": "%s"}');
        createTemplate('{"title": "%s", "type": "uint", "decimals": 18, "category": "%s", "lang": "%s"}');
        createTemplate('{"title": "%s", "type": "single-select", "outcomes": [%s], "category": "%s", "lang": "%s"}');
        createTemplate('{"title": "%s", "type": "multiple-select", "outcomes": [%s], "category": "%s", "lang": "%s"}');
        createTemplate('{"title": "%s", "type": "datetime", "category": "%s", "lang": "%s"}');
    }

    /// @notice Function for arbitrator to set an optional per-question fee.
    /// @dev The per-question fee, charged when a question is asked, is intended as an anti-spam measure.
    /// @param fee The fee to be charged by the arbitrator when a question is asked
    function setQuestionFee(uint256 fee)
        stateAny()
    external {
        arbitrator_question_fees[msg.sender] = fee;
        emit LogSetQuestionFee(msg.sender, fee);
    }

    /// @notice Create a reusable template, which should be a JSON document.
    /// Placeholders should use gettext() syntax, eg %s.
    /// @dev Template data is only stored in the event logs, but its block number is kept in contract storage.
    /// @param content The template content
    /// @return The ID of the newly-created template, which is created sequentially.
    function createTemplate(string memory content)
        stateAny()
    public returns (uint256) {
        uint256 id = nextTemplateID;
        templates[id] = block.number;
        template_hashes[id] = keccak256(abi.encodePacked(content));
        emit LogNewTemplate(id, msg.sender, content);
        nextTemplateID = id.add(1);
        return id;
    }

    /// @notice Create a new reusable template and use it to ask a question
    /// @dev Template data is only stored in the event logs, but its block number is kept in contract storage.
    /// @param content The template content
    /// @param question A string containing the parameters that will be passed into the template to make the question
    /// @param arbitrator The arbitration contract that will have the final word on the answer if there is a dispute
    /// @param timeout How long the contract should wait after the answer is changed before finalizing on that answer
    /// @param opening_ts If set, the earliest time it should be possible to answer the question.
    /// @param nonce A user-specified nonce used in the question ID. Change it to repeat a question.
    /// @return The ID of the newly-created template, which is created sequentially.
    function createTemplateAndAskQuestion(
        string memory content,
        string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce
    )
        // stateNotCreated is enforced by the internal _askQuestion
    public returns (bytes32) {
        uint256 template_id = createTemplate(content);
        return askQuestion(template_id, question, arbitrator, timeout, opening_ts, nonce);
    }

    /// @notice Ask a new question without a bounty and return the ID
    /// @dev Template data is only stored in the event logs, but its block number is kept in contract storage.
    /// @dev Calling without the token param will only work if there is no arbitrator-set question fee.
    /// @dev This has the same function signature as askQuestion() in the non-ERC20 version, which is optionally payable.
    /// @param template_id The ID number of the template the question will use
    /// @param question A string containing the parameters that will be passed into the template to make the question
    /// @param arbitrator The arbitration contract that will have the final word on the answer if there is a dispute
    /// @param timeout How long the contract should wait after the answer is changed before finalizing on that answer
    /// @param opening_ts If set, the earliest time it should be possible to answer the question.
    /// @param nonce A user-specified nonce used in the question ID. Change it to repeat a question.
    /// @return The ID of the newly-created question, created deterministically.
    function askQuestion(uint256 template_id, string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce)
        // stateNotCreated is enforced by the internal _askQuestion
    public returns (bytes32) {

        require(templates[template_id] > 0, "template must exist");

        bytes32 content_hash = keccak256(abi.encodePacked(template_id, opening_ts, question));
        bytes32 question_id = keccak256(abi.encodePacked(content_hash, arbitrator, timeout, msg.sender, nonce));

        _askQuestion(question_id, content_hash, arbitrator, timeout, opening_ts, 0);
        emit LogNewQuestion(question_id, msg.sender, template_id, question, content_hash, arbitrator, timeout, opening_ts, nonce, now);

        return question_id;
    }

    /// @notice Ask a new question with a bounty and return the ID
    /// @dev Template data is only stored in the event logs, but its block number is kept in contract storage.
    /// @param template_id The ID number of the template the question will use
    /// @param question A string containing the parameters that will be passed into the template to make the question
    /// @param arbitrator The arbitration contract that will have the final word on the answer if there is a dispute
    /// @param timeout How long the contract should wait after the answer is changed before finalizing on that answer
    /// @param opening_ts If set, the earliest time it should be possible to answer the question.
    /// @param nonce A user-specified nonce used in the question ID. Change it to repeat a question.
    /// @param tokens The combined initial question bounty and question fee
    /// @return The ID of the newly-created question, created deterministically.
    function askQuestionERC20(uint256 template_id, string memory question, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 nonce, uint256 tokens)
        // stateNotCreated is enforced by the internal _askQuestion
    public returns (bytes32) {

        _deductTokensOrRevert(tokens);

        require(templates[template_id] > 0, "template must exist");

        bytes32 content_hash = keccak256(abi.encodePacked(template_id, opening_ts, question));
        bytes32 question_id = keccak256(abi.encodePacked(content_hash, arbitrator, timeout, msg.sender, nonce));

        _askQuestion(question_id, content_hash, arbitrator, timeout, opening_ts, tokens);
        emit LogNewQuestion(question_id, msg.sender, template_id, question, content_hash, arbitrator, timeout, opening_ts, nonce, now);

        return question_id;
    }

    function _deductTokensOrRevert(uint256 tokens)
    internal {

        if (tokens == 0) {
            return;
        }

        uint256 bal = balanceOf[msg.sender];

        // Deduct any tokens you have in your internal balance first
        if (bal > 0) {
            if (bal >= tokens) {
                balanceOf[msg.sender] = bal.sub(tokens);
                return;
            } else {
                tokens = tokens.sub(bal);
                balanceOf[msg.sender] = 0;
            }
        }
        // Now we need to charge the rest from
        require(token.transferFrom(msg.sender, address(this), tokens), "Transfer of tokens failed, insufficient approved balance?");
        return;

    }

    function _askQuestion(bytes32 question_id, bytes32 content_hash, address arbitrator, uint32 timeout, uint32 opening_ts, uint256 tokens)
        stateNotCreated(question_id)
    internal {

        uint256 bounty = tokens;

        // A timeout of 0 makes no sense, and we will use this to check existence
        require(timeout > 0, "timeout must be positive");
        require(timeout < 365 days, "timeout must be less than 365 days");
        require(arbitrator != NULL_ADDRESS, "arbitrator must be set");

        // The arbitrator can set a fee for asking a question.
        // This is intended as an anti-spam defence.
        // The fee is waived if the arbitrator is asking the question.
        // This allows them to set an impossibly high fee and make users proxy the question through them.
        // This would allow more sophisticated pricing, question whitelisting etc.
        if (msg.sender != arbitrator) {
            uint256 question_fee = arbitrator_question_fees[arbitrator];
            require(bounty >= question_fee, "Tokens provided must cover question fee");
            bounty = bounty.sub(question_fee);
            balanceOf[arbitrator] = balanceOf[arbitrator].add(question_fee);
        }

        questions[question_id].content_hash = content_hash;
        questions[question_id].arbitrator = arbitrator;
        questions[question_id].opening_ts = opening_ts;
        questions[question_id].timeout = timeout;
        questions[question_id].bounty = bounty;

    }

    /// @notice Add funds to the bounty for a question
    /// @dev Add bounty funds after the initial question creation. Can be done any time until the question is finalized.
    /// @param question_id The ID of the question you wish to fund
    /// @param tokens The number of tokens to fund
    function fundAnswerBountyERC20(bytes32 question_id, uint256 tokens)
        stateOpen(question_id)
    external {
        _deductTokensOrRevert(tokens);
        questions[question_id].bounty = questions[question_id].bounty.add(tokens);
        emit LogFundAnswerBounty(question_id, tokens, questions[question_id].bounty, msg.sender);
    }

    /// @notice Submit an answer for a question.
    /// @dev Adds the answer to the history and updates the current "best" answer.
    /// May be subject to front-running attacks; Substitute submitAnswerCommitment()->submitAnswerReveal() to prevent them.
    /// @param question_id The ID of the question
    /// @param answer The answer, encoded into bytes32
    /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
    /// @param tokens The amount of tokens to submit
    function submitAnswerERC20(bytes32 question_id, bytes32 answer, uint256 max_previous, uint256 tokens)
        stateOpen(question_id)
        bondMustDouble(question_id, tokens)
        previousBondMustNotBeatMaxPrevious(question_id, max_previous)
    external {
        _deductTokensOrRevert(tokens);
        _addAnswerToHistory(question_id, answer, msg.sender, tokens, false);
        _updateCurrentAnswer(question_id, answer, questions[question_id].timeout);
    }

    // @notice Verify and store a commitment, including an appropriate timeout
    // @param question_id The ID of the question to store
    // @param commitment The ID of the commitment
    function _storeCommitment(bytes32 question_id, bytes32 commitment_id)
    internal
    {
        require(commitments[commitment_id].reveal_ts == COMMITMENT_NON_EXISTENT, "commitment must not already exist");

        uint32 commitment_timeout = questions[question_id].timeout / COMMITMENT_TIMEOUT_RATIO;
        commitments[commitment_id].reveal_ts = uint32(now).add(commitment_timeout);
    }

    /// @notice Submit the hash of an answer, laying your claim to that answer if you reveal it in a subsequent transaction.
    /// @dev Creates a hash, commitment_id, uniquely identifying this answer, to this question, with this bond.
    /// The commitment_id is stored in the answer history where the answer would normally go.
    /// Does not update the current best answer - this is left to the later submitAnswerReveal() transaction.
    /// @param question_id The ID of the question
    /// @param answer_hash The hash of your answer, plus a nonce that you will later reveal
    /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
    /// @param _answerer If specified, the address to be given as the question answerer. Defaults to the sender.
    /// @param tokens Number of tokens sent
    /// @dev Specifying the answerer is useful if you want to delegate the commit-and-reveal to a third-party.
    function submitAnswerCommitmentERC20(bytes32 question_id, bytes32 answer_hash, uint256 max_previous, address _answerer, uint256 tokens)
        stateOpen(question_id)
        bondMustDouble(question_id, tokens)
        previousBondMustNotBeatMaxPrevious(question_id, max_previous)
    external {

        _deductTokensOrRevert(tokens);

        bytes32 commitment_id = keccak256(abi.encodePacked(question_id, answer_hash, tokens));
        address answerer = (_answerer == NULL_ADDRESS) ? msg.sender : _answerer;

        _storeCommitment(question_id, commitment_id);
        _addAnswerToHistory(question_id, commitment_id, answerer, tokens, true);

    }

    /// @notice Submit the answer whose hash you sent in a previous submitAnswerCommitment() transaction
    /// @dev Checks the parameters supplied recreate an existing commitment, and stores the revealed answer
    /// Updates the current answer unless someone has since supplied a new answer with a higher bond
    /// msg.sender is intentionally not restricted to the user who originally sent the commitment;
    /// For example, the user may want to provide the answer+nonce to a third-party service and let them send the tx
    /// NB If we are pending arbitration, it will be up to the arbitrator to wait and see any outstanding reveal is sent
    /// @param question_id The ID of the question
    /// @param answer The answer, encoded as bytes32
    /// @param nonce The nonce that, combined with the answer, recreates the answer_hash you gave in submitAnswerCommitment()
    /// @param bond The bond that you paid in your submitAnswerCommitment() transaction
    function submitAnswerReveal(bytes32 question_id, bytes32 answer, uint256 nonce, uint256 bond)
        stateOpenOrPendingArbitration(question_id)
    external {

        bytes32 answer_hash = keccak256(abi.encodePacked(answer, nonce));
        bytes32 commitment_id = keccak256(abi.encodePacked(question_id, answer_hash, bond));

        require(!commitments[commitment_id].is_revealed, "commitment must not have been revealed yet");
        require(commitments[commitment_id].reveal_ts > uint32(now), "reveal deadline must not have passed");

        commitments[commitment_id].revealed_answer = answer;
        commitments[commitment_id].is_revealed = true;

        if (bond == questions[question_id].bond) {
            _updateCurrentAnswer(question_id, answer, questions[question_id].timeout);
        }

        emit LogAnswerReveal(question_id, msg.sender, answer_hash, answer, nonce, bond);

    }

    function _addAnswerToHistory(bytes32 question_id, bytes32 answer_or_commitment_id, address answerer, uint256 bond, bool is_commitment)
    internal
    {
        bytes32 new_history_hash = keccak256(abi.encodePacked(questions[question_id].history_hash, answer_or_commitment_id, bond, answerer, is_commitment));

        // Update the current bond level, if there's a bond (ie anything except arbitration)
        if (bond > 0) {
            questions[question_id].bond = bond;
        }
        questions[question_id].history_hash = new_history_hash;

        emit LogNewAnswer(answer_or_commitment_id, question_id, new_history_hash, answerer, bond, now, is_commitment);
    }

    function _updateCurrentAnswer(bytes32 question_id, bytes32 answer, uint32 timeout_secs)
    internal {
        questions[question_id].best_answer = answer;
        questions[question_id].finalize_ts = uint32(now).add(timeout_secs);
    }

    /// @notice Notify the contract that the arbitrator has been paid for a question, freezing it pending their decision.
    /// @dev The arbitrator contract is trusted to only call this if they've been paid, and tell us who paid them.
    /// @param question_id The ID of the question
    /// @param requester The account that requested arbitration
    /// @param max_previous If specified, reverts if a bond higher than this was submitted after you sent your transaction.
    function notifyOfArbitrationRequest(bytes32 question_id, address requester, uint256 max_previous)
        onlyArbitrator(question_id)
        stateOpen(question_id)
        previousBondMustNotBeatMaxPrevious(question_id, max_previous)
    external {
        require(questions[question_id].bond > 0, "Question must already have an answer when arbitration is requested");
        questions[question_id].is_pending_arbitration = true;
        emit LogNotifyOfArbitrationRequest(question_id, requester);
    }

    /// @notice Submit the answer for a question, for use by the arbitrator.
    /// @dev Doesn't require (or allow) a bond.
    /// If the current final answer is correct, the account should be whoever submitted it.
    /// If the current final answer is wrong, the account should be whoever paid for arbitration.
    /// However, the answerer stipulations are not enforced by the contract.
    /// @param question_id The ID of the question
    /// @param answer The answer, encoded into bytes32
    /// @param answerer The account credited with this answer for the purpose of bond claims
    function submitAnswerByArbitrator(bytes32 question_id, bytes32 answer, address answerer)
        onlyArbitrator(question_id)
        statePendingArbitration(question_id)
    external {

        require(answerer != NULL_ADDRESS, "answerer must be provided");
        emit LogFinalize(question_id, answer);

        questions[question_id].is_pending_arbitration = false;
        _addAnswerToHistory(question_id, answer, answerer, 0, false);
        _updateCurrentAnswer(question_id, answer, 0);

    }

    /// @notice Report whether the answer to the specified question is finalized
    /// @param question_id The ID of the question
    /// @return Return true if finalized
    function isFinalized(bytes32 question_id)
    view public returns (bool) {
        uint32 finalize_ts = questions[question_id].finalize_ts;
        return ( !questions[question_id].is_pending_arbitration && (finalize_ts > UNANSWERED) && (finalize_ts <= uint32(now)) );
    }

    /// @notice (Deprecated) Return the final answer to the specified question, or revert if there isn't one
    /// @param question_id The ID of the question
    /// @return The answer formatted as a bytes32
    function getFinalAnswer(bytes32 question_id)
        stateFinalized(question_id)
    external view returns (bytes32) {
        return questions[question_id].best_answer;
    }

    /// @notice Return the final answer to the specified question, or revert if there isn't one
    /// @param question_id The ID of the question
    /// @return The answer formatted as a bytes32
    function resultFor(bytes32 question_id)
        stateFinalized(question_id)
    external view returns (bytes32) {
        return questions[question_id].best_answer;
    }


    /// @notice Return the final answer to the specified question, provided it matches the specified criteria.
    /// @dev Reverts if the question is not finalized, or if it does not match the specified criteria.
    /// @param question_id The ID of the question
    /// @param content_hash The hash of the question content (template ID + opening time + question parameter string)
    /// @param arbitrator The arbitrator chosen for the question (regardless of whether they are asked to arbitrate)
    /// @param min_timeout The timeout set in the initial question settings must be this high or higher
    /// @param min_bond The bond sent with the final answer must be this high or higher
    /// @return The answer formatted as a bytes32
    function getFinalAnswerIfMatches(
        bytes32 question_id,
        bytes32 content_hash, address arbitrator, uint32 min_timeout, uint256 min_bond
    )
        stateFinalized(question_id)
    external view returns (bytes32) {
        require(content_hash == questions[question_id].content_hash, "content hash must match");
        require(arbitrator == questions[question_id].arbitrator, "arbitrator must match");
        require(min_timeout <= questions[question_id].timeout, "timeout must be long enough");
        require(min_bond <= questions[question_id].bond, "bond must be high enough");
        return questions[question_id].best_answer;
    }

    /// @notice Assigns the winnings (bounty and bonds) to everyone who gave the accepted answer
    /// Caller must provide the answer history, in reverse order
    /// @dev Works up the chain and assign bonds to the person who gave the right answer
    /// If someone gave the winning answer earlier, they must get paid from the higher bond
    /// That means we can't pay out the bond added at n until we have looked at n-1
    /// The first answer is authenticated by checking against the stored history_hash.
    /// One of the inputs to history_hash is the history_hash before it, so we use that to authenticate the next entry, etc
    /// Once we get to a null hash we'll know we're done and there are no more answers.
    /// Usually you would call the whole thing in a single transaction, but if not then the data is persisted to pick up later.
    /// @param question_id The ID of the question
    /// @param history_hashes Second-last-to-first, the hash of each history entry. (Final one should be empty).
    /// @param addrs Last-to-first, the address of each answerer or commitment sender
    /// @param bonds Last-to-first, the bond supplied with each answer or commitment
    /// @param answers Last-to-first, each answer supplied, or commitment ID if the answer was supplied with commit->reveal
    function claimWinnings(
        bytes32 question_id,
        bytes32[] memory history_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers
    )
        stateFinalized(question_id)
    public {

        require(history_hashes.length > 0, "at least one history hash entry must be provided");

        // These are only set if we split our claim over multiple transactions.
        address payee = question_claims[question_id].payee;
        uint256 last_bond = question_claims[question_id].last_bond;
        uint256 queued_funds = question_claims[question_id].queued_funds;

        // Starts as the hash of the final answer submitted. It'll be cleared when we're done.
        // If we're splitting the claim over multiple transactions, it'll be the hash where we left off last time
        bytes32 last_history_hash = questions[question_id].history_hash;

        bytes32 best_answer = questions[question_id].best_answer;

        uint256 i;
        for (i = 0; i < history_hashes.length; i++) {

            // Check input against the history hash, and see which of 2 possible values of is_commitment fits.
            bool is_commitment = _verifyHistoryInputOrRevert(last_history_hash, history_hashes[i], answers[i], bonds[i], addrs[i]);

            queued_funds = queued_funds.add(last_bond);
            (queued_funds, payee) = _processHistoryItem(
                question_id, best_answer, queued_funds, payee,
                addrs[i], bonds[i], answers[i], is_commitment);

            // Line the bond up for next time, when it will be added to somebody's queued_funds
            last_bond = bonds[i];
            last_history_hash = history_hashes[i];

        }

        if (last_history_hash != NULL_HASH) {
            // We haven't yet got to the null hash (1st answer), ie the caller didn't supply the full answer chain.
            // Persist the details so we can pick up later where we left off later.

            // If we know who to pay we can go ahead and pay them out, only keeping back last_bond
            // (We always know who to pay unless all we saw were unrevealed commits)
            if (payee != NULL_ADDRESS) {
                _payPayee(question_id, payee, queued_funds);
                queued_funds = 0;
            }

            question_claims[question_id].payee = payee;
            question_claims[question_id].last_bond = last_bond;
            question_claims[question_id].queued_funds = queued_funds;
        } else {
            // There is nothing left below us so the payee can keep what remains
            _payPayee(question_id, payee, queued_funds.add(last_bond));
            delete question_claims[question_id];
        }

        questions[question_id].history_hash = last_history_hash;

    }

    function _payPayee(bytes32 question_id, address payee, uint256 value)
    internal {
        balanceOf[payee] = balanceOf[payee].add(value);
        emit LogClaim(question_id, payee, value);
    }

    function _verifyHistoryInputOrRevert(
        bytes32 last_history_hash,
        bytes32 history_hash, bytes32 answer, uint256 bond, address addr
    )
    internal pure returns (bool) {
        if (last_history_hash == keccak256(abi.encodePacked(history_hash, answer, bond, addr, true)) ) {
            return true;
        }
        if (last_history_hash == keccak256(abi.encodePacked(history_hash, answer, bond, addr, false)) ) {
            return false;
        }
        revert("History input provided did not match the expected hash");
    }

    function _processHistoryItem(
        bytes32 question_id, bytes32 best_answer,
        uint256 queued_funds, address payee,
        address addr, uint256 bond, bytes32 answer, bool is_commitment
    )
    internal returns (uint256, address) {

        // For commit-and-reveal, the answer history holds the commitment ID instead of the answer.
        // We look at the referenced commitment ID and switch in the actual answer.
        if (is_commitment) {
            bytes32 commitment_id = answer;
            // If it's a commit but it hasn't been revealed, it will always be considered wrong.
            if (!commitments[commitment_id].is_revealed) {
                delete commitments[commitment_id];
                return (queued_funds, payee);
            } else {
                answer = commitments[commitment_id].revealed_answer;
                delete commitments[commitment_id];
            }
        }

        if (answer == best_answer) {

            if (payee == NULL_ADDRESS) {

                // The entry is for the first payee we come to, ie the winner.
                // They get the question bounty.
                payee = addr;
                queued_funds = queued_funds.add(questions[question_id].bounty);
                questions[question_id].bounty = 0;

            } else if (addr != payee) {

                // Answerer has changed, ie we found someone lower down who needs to be paid

                // The lower answerer will take over receiving bonds from higher answerer.
                // They should also be paid the takeover fee, which is set at a rate equivalent to their bond.
                // (This is our arbitrary rule, to give consistent right-answerers a defence against high-rollers.)

                // There should be enough for the fee, but if not, take what we have.
                // There's an edge case involving weird arbitrator behaviour where we may be short.
                uint256 answer_takeover_fee = (queued_funds >= bond) ? bond : queued_funds;

                // Settle up with the old (higher-bonded) payee
                _payPayee(question_id, payee, queued_funds.sub(answer_takeover_fee));

                // Now start queued_funds again for the new (lower-bonded) payee
                payee = addr;
                queued_funds = answer_takeover_fee;

            }

        }

        return (queued_funds, payee);

    }

    /// @notice Convenience function to assign bounties/bonds for multiple questions in one go, then withdraw all your funds.
    /// Caller must provide the answer history for each question, in reverse order
    /// @dev Can be called by anyone to assign bonds/bounties, but funds are only withdrawn for the user making the call.
    /// @param question_ids The IDs of the questions you want to claim for
    /// @param lengths The number of history entries you will supply for each question ID
    /// @param hist_hashes In a single list for all supplied questions, the hash of each history entry.
    /// @param addrs In a single list for all supplied questions, the address of each answerer or commitment sender
    /// @param bonds In a single list for all supplied questions, the bond supplied with each answer or commitment
    /// @param answers In a single list for all supplied questions, each answer supplied, or commitment ID
    function claimMultipleAndWithdrawBalance(
        bytes32[] memory question_ids, uint256[] memory lengths,
        bytes32[] memory hist_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers
    )
        stateAny() // The finalization checks are done in the claimWinnings function
    public {

        uint256 qi;
        uint256 i;
        for (qi = 0; qi < question_ids.length; qi++) {
            bytes32 qid = question_ids[qi];
            uint256 ln = lengths[qi];
            bytes32[] memory hh = new bytes32[](ln);
            address[] memory ad = new address[](ln);
            uint256[] memory bo = new uint256[](ln);
            bytes32[] memory an = new bytes32[](ln);
            uint256 j;
            for (j = 0; j < ln; j++) {
                hh[j] = hist_hashes[i];
                ad[j] = addrs[i];
                bo[j] = bonds[i];
                an[j] = answers[i];
                i++;
            }
            claimWinnings(qid, hh, ad, bo, an);
        }
        withdraw();
    }

    /// @notice Returns the questions's content hash, identifying the question content
    /// @param question_id The ID of the question
    function getContentHash(bytes32 question_id)
    public view returns(bytes32) {
        return questions[question_id].content_hash;
    }

    /// @notice Returns the arbitrator address for the question
    /// @param question_id The ID of the question
    function getArbitrator(bytes32 question_id)
    public view returns(address) {
        return questions[question_id].arbitrator;
    }

    /// @notice Returns the timestamp when the question can first be answered
    /// @param question_id The ID of the question
    function getOpeningTS(bytes32 question_id)
    public view returns(uint32) {
        return questions[question_id].opening_ts;
    }

    /// @notice Returns the timeout in seconds used after each answer
    /// @param question_id The ID of the question
    function getTimeout(bytes32 question_id)
    public view returns(uint32) {
        return questions[question_id].timeout;
    }

    /// @notice Returns the timestamp at which the question will be/was finalized
    /// @param question_id The ID of the question
    function getFinalizeTS(bytes32 question_id)
    public view returns(uint32) {
        return questions[question_id].finalize_ts;
    }

    /// @notice Returns whether the question is pending arbitration
    /// @param question_id The ID of the question
    function isPendingArbitration(bytes32 question_id)
    public view returns(bool) {
        return questions[question_id].is_pending_arbitration;
    }

    /// @notice Returns the current total unclaimed bounty
    /// @dev Set back to zero once the bounty has been claimed
    /// @param question_id The ID of the question
    function getBounty(bytes32 question_id)
    public view returns(uint256) {
        return questions[question_id].bounty;
    }

    /// @notice Returns the current best answer
    /// @param question_id The ID of the question
    function getBestAnswer(bytes32 question_id)
    public view returns(bytes32) {
        return questions[question_id].best_answer;
    }

    /// @notice Returns the history hash of the question
    /// @param question_id The ID of the question
    /// @dev Updated on each answer, then rewound as each is claimed
    function getHistoryHash(bytes32 question_id)
    public view returns(bytes32) {
        return questions[question_id].history_hash;
    }

    /// @notice Returns the highest bond posted so far for a question
    /// @param question_id The ID of the question
    function getBond(bytes32 question_id)
    public view returns(uint256) {
        return questions[question_id].bond;
    }

}

// File: @openzeppelin/contracts/math/SafeMath.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

// File: contracts/PredictionMarket.sol

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;


// openzeppelin imports


library CeilDiv {
  // calculates ceil(x/y)
  function ceildiv(uint256 x, uint256 y) internal pure returns (uint256) {
    if (x > 0) return ((x - 1) / y) + 1;
    return x / y;
  }
}

/// @title Market Contract Factory
contract PredictionMarket {
  using SafeMath for uint256;
  using CeilDiv for uint256;

  // ------ Events ------

  event MarketCreated(address indexed user, uint256 indexed marketId, uint256 outcomes, string question, string image);

  event MarketActionTx(
    address indexed user,
    MarketAction indexed action,
    uint256 indexed marketId,
    uint256 outcomeId,
    uint256 shares,
    uint256 value,
    uint256 timestamp
  );

  event MarketOutcomePrice(uint256 indexed marketId, uint256 indexed outcomeId, uint256 value, uint256 timestamp);

  event MarketLiquidity(
    uint256 indexed marketId,
    uint256 value, // total liquidity
    uint256 price, // value of one liquidity share; max: 1 (50-50 situation)
    uint256 timestamp
  );

  event MarketResolved(address indexed user, uint256 indexed marketId, uint256 outcomeId, uint256 timestamp);

  // ------ Events End ------

  uint256 public constant MAX_UINT_256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;

  uint256 public constant ONE = 10**18;

  enum MarketState {
    open,
    closed,
    resolved
  }
  enum MarketAction {
    buy,
    sell,
    addLiquidity,
    removeLiquidity,
    claimWinnings,
    claimLiquidity,
    claimFees,
    claimVoided
  }

  struct Market {
    // market details
    uint256 closesAtTimestamp;
    uint256 balance; // total stake
    uint256 liquidity; // stake held
    uint256 sharesAvailable; // shares held (all outcomes)
    mapping(address => uint256) liquidityShares;
    mapping(address => bool) liquidityClaims; // wether user has claimed liquidity earnings
    MarketState state; // resolution variables
    MarketResolution resolution; // fees
    MarketFees fees;
    // market outcomes
    uint256[] outcomeIds;
    mapping(uint256 => MarketOutcome) outcomes;
  }

  struct MarketFees {
    uint256 value; // fee % taken from every transaction
    uint256 poolWeight; // internal var used to ensure pro-rate fee distribution
    mapping(address => uint256) claimed;
  }

  struct MarketResolution {
    bool resolved;
    uint256 outcomeId;
    bytes32 questionId; // realitio questionId
  }

  struct MarketOutcome {
    uint256 marketId;
    uint256 id;
    Shares shares;
  }

  struct Shares {
    uint256 total; // number of shares
    uint256 available; // available shares
    mapping(address => uint256) holders;
    mapping(address => bool) claims; // wether user has claimed winnings
    mapping(address => bool) voidedClaims; // wether user has claimed voided market shares
  }

  uint256[] marketIds;
  mapping(uint256 => Market) markets;
  uint256 public marketIndex;

  // governance
  uint256 public fee; // fee % taken from every transaction, can be updated by contract owner
  // realitio configs
  address public realitioAddress;
  uint256 public realitioTimeout;
  // market creation
  IERC20 public token; // token used for rewards / market creation
  uint256 public requiredBalance; // required balance for market creation

  // ------ Modifiers ------

  modifier isMarket(uint256 marketId) {
    require(marketId < marketIndex);
    _;
  }

  modifier timeTransitions(uint256 marketId) {
    if (now > markets[marketId].closesAtTimestamp && markets[marketId].state == MarketState.open) {
      nextState(marketId);
    }
    _;
  }

  modifier atState(uint256 marketId, MarketState state) {
    require(markets[marketId].state == state);
    _;
  }

  modifier notAtState(uint256 marketId, MarketState state) {
    require(markets[marketId].state != state);
    _;
  }

  modifier transitionNext(uint256 marketId) {
    _;
    nextState(marketId);
  }

  modifier mustHoldRequiredBalance() {
    require(token.balanceOf(msg.sender) >= requiredBalance, "msg.sender must hold minimum erc20 balance");
    _;
  }

  // ------ Modifiers End ------

  /// @dev protocol is immutable and has no ownership
  constructor(
    uint256 _fee,
    IERC20 _token,
    uint256 _requiredBalance,
    address _realitioAddress,
    uint256 _realitioTimeout
  ) public {
    fee = _fee;
    token = _token;
    requiredBalance = _requiredBalance;
    realitioAddress = _realitioAddress;
    realitioTimeout = _realitioTimeout;
  }

  // ------ Core Functions ------

  /// @dev Creates a market, initializes the outcome shares pool and submits a question in Realitio
  function createMarket(
    string memory question,
    string memory image,
    uint256 closesAt,
    address arbitrator,
    uint256 outcomes
  ) public payable mustHoldRequiredBalance() returns (uint256) {
    uint256 marketId = marketIndex;
    marketIds.push(marketId);

    Market storage market = markets[marketId];

    require(msg.value > 0, "stake needs to be > 0");
    require(closesAt >= now, "market must resolve after the current date");
    require(arbitrator == address(arbitrator), "invalid arbitrator address");
    // v1 - only binary markets
    require(outcomes == 2, "number of outcomes has to be 2");

    market.closesAtTimestamp = closesAt;
    market.state = MarketState.open;
    market.fees.value = fee;
    // setting intial value to an integer that does not map to any outcomeId
    market.resolution.outcomeId = MAX_UINT_256;

    // creating market outcomes
    for (uint256 i = 0; i < outcomes; i++) {
      market.outcomeIds.push(i);
      MarketOutcome storage outcome = market.outcomes[i];

      outcome.marketId = marketId;
      outcome.id = i;
    }

    // creating question in realitio
    RealitioERC20 realitio = RealitioERC20(realitioAddress);

    market.resolution.questionId = realitio.askQuestionERC20(
      2,
      question,
      arbitrator,
      uint32(realitioTimeout),
      uint32(closesAt),
      0,
      0
    );

    addLiquidity(marketId, msg.value);

    // emiting initial price events
    emitMarketOutcomePriceEvents(marketId);
    emit MarketCreated(msg.sender, marketId, outcomes, question, image);

    // incrementing market array index
    marketIndex = marketIndex + 1;

    return marketId;
  }

  /// @dev Calculates the number of shares bought with "amount" balance
  function calcBuyAmount(
    uint256 amount,
    uint256 marketId,
    uint256 outcomeId
  ) public view returns (uint256) {
    Market storage market = markets[marketId];

    uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
    uint256 amountMinusFees = amount.sub(amount.mul(market.fees.value) / ONE);
    uint256 buyTokenPoolBalance = outcomesShares[outcomeId];
    uint256 endingOutcomeBalance = buyTokenPoolBalance.mul(ONE);
    for (uint256 i = 0; i < outcomesShares.length; i++) {
      if (i != outcomeId) {
        uint256 outcomeShares = outcomesShares[i];
        endingOutcomeBalance = endingOutcomeBalance.mul(outcomeShares).ceildiv(outcomeShares.add(amountMinusFees));
      }
    }
    require(endingOutcomeBalance > 0, "must have non-zero balances");

    return buyTokenPoolBalance.add(amountMinusFees).sub(endingOutcomeBalance.ceildiv(ONE));
  }

  /// @dev Calculates the number of shares needed to be sold in order to receive "amount" in balance
  function calcSellAmount(
    uint256 amount,
    uint256 marketId,
    uint256 outcomeId
  ) public view returns (uint256 outcomeTokenSellAmount) {
    Market storage market = markets[marketId];

    uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
    uint256 amountPlusFees = amount.mul(ONE) / ONE.sub(market.fees.value);
    uint256 sellTokenPoolBalance = outcomesShares[outcomeId];
    uint256 endingOutcomeBalance = sellTokenPoolBalance.mul(ONE);
    for (uint256 i = 0; i < outcomesShares.length; i++) {
      if (i != outcomeId) {
        uint256 outcomeShares = outcomesShares[i];
        endingOutcomeBalance = endingOutcomeBalance.mul(outcomeShares).ceildiv(outcomeShares.sub(amountPlusFees));
      }
    }
    require(endingOutcomeBalance > 0, "must have non-zero balances");

    return amountPlusFees.add(endingOutcomeBalance.ceildiv(ONE)).sub(sellTokenPoolBalance);
  }

  /// @dev Buy shares of a market outcome
  function buy(
    uint256 marketId,
    uint256 outcomeId,
    uint256 minOutcomeSharesToBuy
  ) external payable timeTransitions(marketId) atState(marketId, MarketState.open) {
    Market storage market = markets[marketId];

    uint256 value = msg.value;
    uint256 shares = calcBuyAmount(value, marketId, outcomeId);
    require(shares >= minOutcomeSharesToBuy, "minimum buy amount not reached");

    // subtracting fee from transaction value
    uint256 feeAmount = value.mul(market.fees.value) / ONE;
    market.fees.poolWeight = market.fees.poolWeight.add(feeAmount);
    uint256 valueMinusFees = value.sub(feeAmount);

    MarketOutcome storage outcome = market.outcomes[outcomeId];

    // Funding market shares with received funds
    addSharesToMarket(marketId, valueMinusFees);

    require(outcome.shares.available >= shares, "outcome shares pool balance is too low");

    transferOutcomeSharesfromPool(msg.sender, marketId, outcomeId, shares);

    emit MarketActionTx(msg.sender, MarketAction.buy, marketId, outcomeId, shares, value, now);
    emitMarketOutcomePriceEvents(marketId);
  }

  /// @dev Sell shares of a market outcome
  function sell(
    uint256 marketId,
    uint256 outcomeId,
    uint256 value,
    uint256 maxOutcomeSharesToSell
  ) external payable timeTransitions(marketId) atState(marketId, MarketState.open) {
    Market storage market = markets[marketId];
    MarketOutcome storage outcome = market.outcomes[outcomeId];

    uint256 shares = calcSellAmount(value, marketId, outcomeId);

    require(shares <= maxOutcomeSharesToSell, "maximum sell amount exceeded");
    require(outcome.shares.holders[msg.sender] >= shares, "user does not have enough balance");

    transferOutcomeSharesToPool(msg.sender, marketId, outcomeId, shares);

    // adding fee to transaction value
    uint256 feeAmount = value.mul(market.fees.value) / (ONE.sub(fee));
    market.fees.poolWeight = market.fees.poolWeight.add(feeAmount);
    uint256 valuePlusFees = value.add(feeAmount);

    require(market.balance >= valuePlusFees, "market does not have enough balance");

    // Rebalancing market shares
    removeSharesFromMarket(marketId, valuePlusFees);

    // Transferring funds to user
    msg.sender.transfer(value);

    emit MarketActionTx(msg.sender, MarketAction.sell, marketId, outcomeId, shares, value, now);
    emitMarketOutcomePriceEvents(marketId);
  }

  /// @dev Adds liquidity to a market - external
  function addLiquidity(uint256 marketId)
    external
    payable
    timeTransitions(marketId)
    atState(marketId, MarketState.open)
  {
    addLiquidity(marketId, msg.value);
  }

  /// @dev Private function, used by addLiquidity and CreateMarket
  function addLiquidity(uint256 marketId, uint256 value)
    private
    timeTransitions(marketId)
    atState(marketId, MarketState.open)
  {
    Market storage market = markets[marketId];

    require(value > 0, "stake has to be greater than 0.");

    uint256 liquidityAmount;

    uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
    uint256[] memory sendBackAmounts = new uint256[](outcomesShares.length);
    uint256 poolWeight = 0;

    if (market.liquidity > 0) {
      // part of the liquidity is exchanged for outcome shares if market is not balanced
      for (uint256 i = 0; i < outcomesShares.length; i++) {
        uint256 outcomeShares = outcomesShares[i];
        if (poolWeight < outcomeShares) poolWeight = outcomeShares;
      }

      for (uint256 i = 0; i < outcomesShares.length; i++) {
        uint256 remaining = value.mul(outcomesShares[i]) / poolWeight;
        sendBackAmounts[i] = value.sub(remaining);
      }

      liquidityAmount = value.mul(market.liquidity) / poolWeight;

      // re-balancing fees pool
      rebalanceFeesPool(marketId, liquidityAmount, MarketAction.addLiquidity);
    } else {
      // funding market with no liquidity
      liquidityAmount = value;
    }

    // funding market
    market.liquidity = market.liquidity.add(liquidityAmount);
    market.liquidityShares[msg.sender] = market.liquidityShares[msg.sender].add(liquidityAmount);

    addSharesToMarket(marketId, value);

    // transform sendBackAmounts to array of amounts added
    for (uint256 i = 0; i < sendBackAmounts.length; i++) {
      if (sendBackAmounts[i] > 0) {
        uint256 marketShares = market.sharesAvailable;
        uint256 outcomeShares = market.outcomes[i].shares.available;
        transferOutcomeSharesfromPool(msg.sender, marketId, i, sendBackAmounts[i]);
        emit MarketActionTx(
          msg.sender,
          MarketAction.buy,
          marketId,
          i,
          sendBackAmounts[i],
          (marketShares.sub(outcomeShares)).mul(sendBackAmounts[i]).div(market.sharesAvailable), // price * shares
          now
        );
      }
    }

    uint256 liquidityPrice = getMarketLiquidityPrice(marketId);
    uint256 liquidityValue = liquidityPrice.mul(liquidityAmount) / ONE;
    emit MarketActionTx(msg.sender, MarketAction.addLiquidity, marketId, 0, liquidityAmount, liquidityValue, now);
    emit MarketLiquidity(marketId, market.liquidity, liquidityPrice, now);
  }

  /// @dev Removes liquidity to a market - external
  function removeLiquidity(uint256 marketId, uint256 shares)
    external
    payable
    timeTransitions(marketId)
    atState(marketId, MarketState.open)
  {
    Market storage market = markets[marketId];

    require(market.liquidityShares[msg.sender] >= shares, "user does not have enough balance");
    // claiming any pending fees
    claimFees(marketId);

    // re-balancing fees pool
    rebalanceFeesPool(marketId, shares, MarketAction.removeLiquidity);

    uint256[] memory outcomesShares = getMarketOutcomesShares(marketId);
    uint256[] memory sendAmounts = new uint256[](outcomesShares.length);
    uint256 poolWeight = MAX_UINT_256;

    // part of the liquidity is exchanged for outcome shares if market is not balanced
    for (uint256 i = 0; i < outcomesShares.length; i++) {
      uint256 outcomeShares = outcomesShares[i];
      if (poolWeight > outcomeShares) poolWeight = outcomeShares;
    }

    uint256 liquidityAmount = shares.mul(poolWeight).div(market.liquidity);

    for (uint256 i = 0; i < outcomesShares.length; i++) {
      sendAmounts[i] = outcomesShares[i].mul(shares) / market.liquidity;
      sendAmounts[i] = sendAmounts[i].sub(liquidityAmount);
    }

    // removing liquidity from market
    removeSharesFromMarket(marketId, liquidityAmount);
    market.liquidity = market.liquidity.sub(shares);
    // removing liquidity tokens from market creator
    market.liquidityShares[msg.sender] = market.liquidityShares[msg.sender].sub(shares);

    for (uint256 i = 0; i < outcomesShares.length; i++) {
      if (sendAmounts[i] > 0) {
        uint256 marketShares = market.sharesAvailable;
        uint256 outcomeShares = market.outcomes[i].shares.available;

        transferOutcomeSharesfromPool(msg.sender, marketId, i, sendAmounts[i]);
        emit MarketActionTx(
          msg.sender,
          MarketAction.buy,
          marketId,
          i,
          sendAmounts[i],
          (marketShares.sub(outcomeShares)).mul(sendAmounts[i]).div(market.sharesAvailable), // price * shares
          now
        );
      }
    }

    // transferring user funds from liquidity removed
    msg.sender.transfer(liquidityAmount);

    emit MarketActionTx(msg.sender, MarketAction.removeLiquidity, marketId, 0, shares, liquidityAmount, now);
    emit MarketLiquidity(marketId, market.liquidity, getMarketLiquidityPrice(marketId), now);
  }

  /// @dev Fetches winning outcome from Realitio and resolves the market
  function resolveMarketOutcome(uint256 marketId)
    public
    timeTransitions(marketId)
    atState(marketId, MarketState.closed)
    transitionNext(marketId)
    returns (uint256)
  {
    Market storage market = markets[marketId];

    RealitioERC20 realitio = RealitioERC20(realitioAddress);
    // will fail if question is not finalized
    uint256 outcomeId = uint256(realitio.resultFor(market.resolution.questionId));

    market.resolution.outcomeId = outcomeId;

    emit MarketResolved(msg.sender, marketId, outcomeId, now);
    emitMarketOutcomePriceEvents(marketId);

    return market.resolution.outcomeId;
  }

  /// @dev Allows holders of resolved outcome shares to claim earnings.
  function claimWinnings(uint256 marketId) public atState(marketId, MarketState.resolved) {
    Market storage market = markets[marketId];
    MarketOutcome storage resolvedOutcome = market.outcomes[market.resolution.outcomeId];

    require(resolvedOutcome.shares.holders[msg.sender] > 0, "user does not hold resolved outcome shares");
    require(resolvedOutcome.shares.claims[msg.sender] == false, "user already claimed resolved outcome winnings");

    // 1 share => price = 1
    uint256 value = resolvedOutcome.shares.holders[msg.sender];

    // assuring market has enough funds
    require(market.balance >= value, "Market does not have enough balance");

    market.balance = market.balance.sub(value);
    resolvedOutcome.shares.claims[msg.sender] = true;

    emit MarketActionTx(
      msg.sender,
      MarketAction.claimWinnings,
      marketId,
      market.resolution.outcomeId,
      resolvedOutcome.shares.holders[msg.sender],
      value,
      now
    );

    msg.sender.transfer(value);
  }

  /// @dev Allows holders of voided outcome shares to claim balance back.
  function claimVoidedOutcomeShares(uint256 marketId, uint256 outcomeId)
    public
    atState(marketId, MarketState.resolved)
  {
    Market storage market = markets[marketId];
    MarketOutcome storage outcome = market.outcomes[outcomeId];

    require(outcome.shares.holders[msg.sender] > 0, "user does not hold outcome shares");
    require(outcome.shares.voidedClaims[msg.sender] == false, "user already claimed outcome shares");

    // voided market - shares are valued at last market price
    uint256 price = getMarketOutcomePrice(marketId, outcomeId);
    uint256 value = price.mul(outcome.shares.holders[msg.sender]).div(ONE);

    // assuring market has enough funds
    require(market.balance >= value, "Market does not have enough balance");

    market.balance = market.balance.sub(value);
    outcome.shares.voidedClaims[msg.sender] = true;

    emit MarketActionTx(
      msg.sender,
      MarketAction.claimVoided,
      marketId,
      outcomeId,
      outcome.shares.holders[msg.sender],
      value,
      now
    );

    msg.sender.transfer(value);
  }

  /// @dev Allows liquidity providers to claim earnings from liquidity providing.
  function claimLiquidity(uint256 marketId) public atState(marketId, MarketState.resolved) {
    Market storage market = markets[marketId];

    // claiming any pending fees
    claimFees(marketId);

    require(market.liquidityShares[msg.sender] > 0, "user does not hold liquidity shares");
    require(market.liquidityClaims[msg.sender] == false, "user already claimed liquidity winnings");

    // value = total resolved outcome pool shares * pool share (%)
    uint256 liquidityPrice = getMarketLiquidityPrice(marketId);
    uint256 value = liquidityPrice.mul(market.liquidityShares[msg.sender]) / ONE;

    // assuring market has enough funds
    require(market.balance >= value, "Market does not have enough balance");

    market.balance = market.balance.sub(value);
    market.liquidityClaims[msg.sender] = true;

    emit MarketActionTx(
      msg.sender,
      MarketAction.claimLiquidity,
      marketId,
      0,
      market.liquidityShares[msg.sender],
      value,
      now
    );

    msg.sender.transfer(value);
  }

  /// @dev Allows liquidity providers to claim their fees share from fees pool
  function claimFees(uint256 marketId) public payable {
    Market storage market = markets[marketId];

    uint256 claimableFees = getUserClaimableFees(marketId, msg.sender);

    if (claimableFees > 0) {
      market.fees.claimed[msg.sender] = market.fees.claimed[msg.sender].add(claimableFees);
      msg.sender.transfer(claimableFees);
    }

    emit MarketActionTx(
      msg.sender,
      MarketAction.claimFees,
      marketId,
      0,
      market.liquidityShares[msg.sender],
      claimableFees,
      now
    );
  }

  /// @dev Rebalances the fees pool. Needed in every AddLiquidity / RemoveLiquidity call
  function rebalanceFeesPool(
    uint256 marketId,
    uint256 liquidityShares,
    MarketAction action
  ) private returns (uint256) {
    Market storage market = markets[marketId];

    uint256 poolWeight = liquidityShares.mul(market.fees.poolWeight).div(market.liquidity);

    if (action == MarketAction.addLiquidity) {
      market.fees.poolWeight = market.fees.poolWeight.add(poolWeight);
      market.fees.claimed[msg.sender] = market.fees.claimed[msg.sender].add(poolWeight);
    } else {
      market.fees.poolWeight = market.fees.poolWeight.sub(poolWeight);
      market.fees.claimed[msg.sender] = market.fees.claimed[msg.sender].sub(poolWeight);
    }
  }

  /// @dev Transitions market to next state
  function nextState(uint256 marketId) private {
    Market storage market = markets[marketId];
    market.state = MarketState(uint256(market.state) + 1);
  }

  /// @dev Emits a outcome price event for every outcome
  function emitMarketOutcomePriceEvents(uint256 marketId) private {
    Market storage market = markets[marketId];

    for (uint256 i = 0; i < market.outcomeIds.length; i++) {
      emit MarketOutcomePrice(marketId, i, getMarketOutcomePrice(marketId, i), now);
    }

    // liquidity shares also change value
    emit MarketLiquidity(marketId, market.liquidity, getMarketLiquidityPrice(marketId), now);
  }

  /// @dev Adds outcome shares to shares pool
  function addSharesToMarket(uint256 marketId, uint256 shares) private {
    Market storage market = markets[marketId];

    for (uint256 i = 0; i < market.outcomeIds.length; i++) {
      MarketOutcome storage outcome = market.outcomes[i];

      outcome.shares.available = outcome.shares.available.add(shares);
      outcome.shares.total = outcome.shares.total.add(shares);

      // only adding to market total shares, the available remains
      market.sharesAvailable = market.sharesAvailable.add(shares);
    }

    market.balance = market.balance.add(shares);
  }

  /// @dev Removes outcome shares from shares pool
  function removeSharesFromMarket(uint256 marketId, uint256 shares) private {
    Market storage market = markets[marketId];

    for (uint256 i = 0; i < market.outcomeIds.length; i++) {
      MarketOutcome storage outcome = market.outcomes[i];

      outcome.shares.available = outcome.shares.available.sub(shares);
      outcome.shares.total = outcome.shares.total.sub(shares);

      // only subtracting from market total shares, the available remains
      market.sharesAvailable = market.sharesAvailable.sub(shares);
    }

    market.balance = market.balance.sub(shares);
  }

  /// @dev Transfer outcome shares from pool to user balance
  function transferOutcomeSharesfromPool(
    address user,
    uint256 marketId,
    uint256 outcomeId,
    uint256 shares
  ) private {
    Market storage market = markets[marketId];
    MarketOutcome storage outcome = market.outcomes[outcomeId];

    // transfering shares from shares pool to user
    outcome.shares.holders[user] = outcome.shares.holders[user].add(shares);
    outcome.shares.available = outcome.shares.available.sub(shares);
    market.sharesAvailable = market.sharesAvailable.sub(shares);
  }

  /// @dev Transfer outcome shares from user balance back to pool
  function transferOutcomeSharesToPool(
    address user,
    uint256 marketId,
    uint256 outcomeId,
    uint256 shares
  ) private {
    Market storage market = markets[marketId];
    MarketOutcome storage outcome = market.outcomes[outcomeId];

    // adding shares back to pool
    outcome.shares.holders[user] = outcome.shares.holders[user].sub(shares);
    outcome.shares.available = outcome.shares.available.add(shares);
    market.sharesAvailable = market.sharesAvailable.add(shares);
  }

  // ------ Core Functions End ------

  // ------ Getters ------

  function getUserMarketShares(uint256 marketId, address user)
    public
    view
    returns (
      uint256,
      uint256,
      uint256
    )
  {
    Market storage market = markets[marketId];

    return (
      market.liquidityShares[user],
      market.outcomes[0].shares.holders[user],
      market.outcomes[1].shares.holders[user]
    );
  }

  function getUserClaimStatus(uint256 marketId, address user)
    public
    view
    returns (
      bool,
      bool,
      bool,
      bool,
      uint256
    )
  {
    Market storage market = markets[marketId];

    // market still not resolved
    if (market.state != MarketState.resolved) {
      return (false, false, false, false, getUserClaimableFees(marketId, user));
    }

    MarketOutcome storage outcome = market.outcomes[market.resolution.outcomeId];

    return (
      outcome.shares.holders[user] > 0,
      outcome.shares.claims[user],
      market.liquidityShares[user] > 0,
      market.liquidityClaims[user],
      getUserClaimableFees(marketId, user)
    );
  }

  function getUserLiquidityPoolShare(uint256 marketId, address user) public view returns (uint256) {
    Market storage market = markets[marketId];

    return market.liquidityShares[user].mul(ONE).div(market.liquidity);
  }

  function getUserClaimableFees(uint256 marketId, address user) public view returns (uint256) {
    Market storage market = markets[marketId];

    uint256 rawAmount = market.fees.poolWeight.mul(market.liquidityShares[user]).div(market.liquidity);
    return rawAmount.sub(market.fees.claimed[user]);
  }

  function getMarkets() public view returns (uint256[] memory) {
    return marketIds;
  }

  function getMarketData(uint256 marketId)
    public
    view
    returns (
      MarketState,
      uint256,
      uint256,
      uint256,
      uint256,
      int256
    )
  {
    Market storage market = markets[marketId];

    return (
      market.state,
      market.closesAtTimestamp,
      market.liquidity,
      market.balance,
      market.sharesAvailable,
      getMarketResolvedOutcome(marketId)
    );
  }

  function getMarketAltData(uint256 marketId)
    public
    view
    returns (
      uint256,
      bytes32,
      uint256
    )
  {
    Market storage market = markets[marketId];

    return (market.fees.value, market.resolution.questionId, uint256(market.resolution.questionId));
  }

  function getMarketQuestion(uint256 marketId) public view returns (bytes32) {
    Market storage market = markets[marketId];

    return (market.resolution.questionId);
  }

  function getMarketPrices(uint256 marketId)
    public
    view
    returns (
      uint256,
      uint256,
      uint256
    )
  {
    return (getMarketLiquidityPrice(marketId), getMarketOutcomePrice(marketId, 0), getMarketOutcomePrice(marketId, 1));
  }

  function getMarketLiquidityPrice(uint256 marketId) public view returns (uint256) {
    Market storage market = markets[marketId];

    if (market.state == MarketState.resolved && !isMarketVoided(marketId)) {
      // resolved market, price is either 0 or 1
      // final liquidity price = outcome shares / liquidity shares
      return market.outcomes[market.resolution.outcomeId].shares.available.mul(ONE).div(market.liquidity);
    }

    // liquidity price = # liquidity shares / # outcome shares * # outcomes
    return market.liquidity.mul(ONE * market.outcomeIds.length).div(market.sharesAvailable);
  }

  function getMarketResolvedOutcome(uint256 marketId) public view returns (int256) {
    Market storage market = markets[marketId];

    // returning -1 if market still not resolved
    if (market.state != MarketState.resolved) {
      return -1;
    }

    return int256(market.resolution.outcomeId);
  }

  function isMarketVoided(uint256 marketId) public view returns (bool) {
    Market storage market = markets[marketId];

    // market still not resolved, still in valid state
    if (market.state != MarketState.resolved) {
      return false;
    }

    // resolved market id does not match any of the market ids
    return market.resolution.outcomeId >= market.outcomeIds.length;
  }

  // ------ Outcome Getters ------

  function getMarketOutcomeIds(uint256 marketId) public view returns (uint256[] memory) {
    Market storage market = markets[marketId];
    return market.outcomeIds;
  }

  function getMarketOutcomePrice(uint256 marketId, uint256 outcomeId) public view returns (uint256) {
    Market storage market = markets[marketId];
    MarketOutcome storage outcome = market.outcomes[outcomeId];

    if (market.state == MarketState.resolved && !isMarketVoided(marketId)) {
      // resolved market, price is either 0 or 1
      return outcomeId == market.resolution.outcomeId ? ONE : 0;
    }

    return (market.sharesAvailable.sub(outcome.shares.available)).mul(ONE).div(market.sharesAvailable);
  }

  function getMarketOutcomeData(uint256 marketId, uint256 outcomeId)
    public
    view
    returns (
      uint256,
      uint256,
      uint256
    )
  {
    Market storage market = markets[marketId];
    MarketOutcome storage outcome = market.outcomes[outcomeId];

    return (getMarketOutcomePrice(marketId, outcomeId), outcome.shares.available, outcome.shares.total);
  }

  function getMarketOutcomesShares(uint256 marketId) private view returns (uint256[] memory) {
    Market storage market = markets[marketId];

    uint256[] memory shares = new uint256[](market.outcomeIds.length);
    for (uint256 i = 0; i < market.outcomeIds.length; i++) {
      shares[i] = market.outcomes[i].shares.available;
    }

    return shares;
  }
}

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint256","name":"_requiredBalance","type":"uint256"},{"internalType":"address","name":"_realitioAddress","type":"address"},{"internalType":"uint256","name":"_realitioTimeout","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"enum PredictionMarket.MarketAction","name":"action","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outcomeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MarketActionTx","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outcomes","type":"uint256"},{"indexed":false,"internalType":"string","name":"question","type":"string"},{"indexed":false,"internalType":"string","name":"image","type":"string"}],"name":"MarketCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MarketLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"outcomeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MarketOutcomePrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"marketId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outcomeId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"MarketResolved","type":"event"},{"inputs":[],"name":"MAX_UINT_256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"},{"internalType":"uint256","name":"minOutcomeSharesToBuy","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"}],"name":"calcBuyAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"}],"name":"calcSellAmount","outputs":[{"internalType":"uint256","name":"outcomeTokenSellAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"claimFees","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"claimLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"}],"name":"claimVoidedOutcomeShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"claimWinnings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"question","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"uint256","name":"closesAt","type":"uint256"},{"internalType":"address","name":"arbitrator","type":"address"},{"internalType":"uint256","name":"outcomes","type":"uint256"}],"name":"createMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketAltData","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketData","outputs":[{"internalType":"enum PredictionMarket.MarketState","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketLiquidityPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"}],"name":"getMarketOutcomeData","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketOutcomeIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"}],"name":"getMarketOutcomePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketPrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketQuestion","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"getMarketResolvedOutcome","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserClaimStatus","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserClaimableFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserLiquidityPoolShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserMarketShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"isMarketVoided","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"realitioAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"realitioTimeout","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"removeLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requiredBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"resolveMarketOutcome","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"uint256","name":"outcomeId","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"maxOutcomeSharesToSell","type":"uint256"}],"name":"sell","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506040516200341b3803806200341b833981016040819052620000349162000075565b600394909455600680546001600160a01b039485166001600160a01b03199182161790915560079290925560048054919093169116179055600555620000e9565b600080600080600060a086880312156200008d578081fd5b855194506020860151620000a181620000d0565b604087015160608801519195509350620000bb81620000d0565b80925050608086015190509295509295909350565b6001600160a01b0381168114620000e657600080fd5b50565b61332280620000f96000396000f3fe6080604052600436106101945760003560e01c806308560ace146101995780631d7920aa146101c457806328747a80146101f35780632c2aa24e1461021357806331877a38146102445780633620875e146102715780633d41a26b146102865780633fe45e3b1461029b57806340993b26146102b0578063429c9dff146102c35780634397c4ce146102e3578063441cf65e1461030357806351c6590a146103305780635e648eff14610343578063677bd9ff146103635780637b34e6e01461038357806385b91d8e146103a55780638c7adc15146103c55780638cd41552146103da5780639d7de6b3146103fa578063aa22a02e1461040d578063ac68a7481461042d578063b31eb89514610440578063bf45572114610460578063bfacba3d14610480578063c2ee3a08146104b2578063c346a9d0146104c7578063c8f70d01146104e7578063ddca3f4314610507578063ec2c90161461051c578063ec93f0f514610531578063efbc47dc14610551578063efce431314610564578063fc0c546a14610584578063fdff808514610599575b600080fd5b3480156101a557600080fd5b506101ae6105b9565b6040516101bb9190612c41565b60405180910390f35b3480156101d057600080fd5b506101e46101df366004612aab565b6105bf565b6040516101bb93929190613253565b3480156101ff57600080fd5b506101ae61020e366004612aab565b6105de565b34801561021f57600080fd5b5061023361022e366004612ac3565b610758565b6040516101bb959493929190612c1a565b34801561025057600080fd5b5061026461025f366004612aab565b610828565b6040516101bb9190612bcb565b61028461027f366004612b3b565b610891565b005b34801561029257600080fd5b506101ae610ab5565b3480156102a757600080fd5b506101ae610abb565b6102846102be366004612b10565b610ac1565b3480156102cf57600080fd5b506101ae6102de366004612b10565b610c4f565b3480156102ef57600080fd5b506101ae6102fe366004612aab565b610daf565b34801561030f57600080fd5b5061032361031e366004612aab565b610dc4565b6040516101bb9190612c0f565b61028461033e366004612aab565b610e09565b34801561034f57600080fd5b5061028461035e366004612aab565b610e91565b34801561036f57600080fd5b5061028461037e366004612aab565b61104b565b34801561038f57600080fd5b506103986111a3565b6040516101bb9190612bb7565b3480156103b157600080fd5b506101e46103c0366004612aab565b6111b2565b3480156103d157600080fd5b506101ae6111e3565b3480156103e657600080fd5b506101ae6103f5366004612aef565b6111e9565b610284610408366004612aef565b6112a9565b34801561041957600080fd5b506101ae610428366004612ac3565b61169b565b61028461043b366004612aab565b6116ee565b34801561044c57600080fd5b506101e461045b366004612ac3565b6117b7565b34801561046c57600080fd5b506101ae61047b366004612aab565b611812565b34801561048c57600080fd5b506104a061049b366004612aab565b61184f565b6040516101bb96959493929190612c4a565b3480156104be57600080fd5b506101ae6118a8565b3480156104d357600080fd5b506101ae6104e2366004612b10565b6118b4565b3480156104f357600080fd5b506101ae610502366004612aab565b6119e4565b34801561051357600080fd5b506101ae611a97565b34801561052857600080fd5b50610264611a9d565b34801561053d57600080fd5b5061028461054c366004612aef565b611af5565b6101ae61055f366004612a28565b611cb5565b34801561057057600080fd5b506101e461057f366004612aef565b611f60565b34801561059057600080fd5b50610398611fa4565b3480156105a557600080fd5b506101ae6105b4366004612ac3565b611fb3565b60075481565b6000908152600160205260409020600a81015460099091015490918190565b60008181526001602052604081205482904211801561061a575060008181526001602052604081206006015460ff16600281111561061857fe5b145b15610628576106288161202c565b8260018060008381526001602052604090206006015460ff16600281111561064c57fe5b1461065657600080fd5b600085815260016020526040808220600480546009830154935163684e62bf60e11b81528a9593946001600160a01b039092169392849263d09cc57e9261069d9201612c41565b60206040518083038186803b1580156106b557600080fd5b505afa1580156106c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106ed9190810190612a10565b60088401819055604051909150899033907f67a6457c8912ae1b7a9fbdfa311cbd016ba606b548bf06bc80bc751072d91bbc9061072d908590429061329e565b60405180910390a361073e8961207c565b505060080154945061074f8161202c565b50505050919050565b600082815260016020526040812081908190819081906002600682015460ff16600281111561078357fe5b146107a8576000806000806107988c8c611fb3565b955095509550955095505061081e565b60088101546000908152600e8201602090815260408083206001600160a01b038b16845260048082018452828520546005808401865284872054928801865284872054908801909552929094205490939115159260ff9283169290151591166108118d8d611fb3565b9650965096509650965050505b9295509295909350565b600081815260016020908152604091829020600d81018054845181850281018501909552808552606094929383018282801561088357602002820191906000526020600020905b81548152602001906001019080831161086f575b50505050509150505b919050565b6000848152600160205260409020548490421180156108cd575060008181526001602052604081206006015460ff1660028111156108cb57fe5b145b156108db576108db8161202c565b8460008060008381526001602052604090206006015460ff1660028111156108ff57fe5b1461090957600080fd5b6000878152600160209081526040808320898452600e810190925282209091610933888b8b6118b4565b90508681111561095e5760405162461bcd60e51b8152600401610955906131da565b60405180910390fd5b33600090815260048301602052604090205481111561098f5760405162461bcd60e51b81526004016109559061311c565b61099b338b8b8461211f565b60006109ba600354670de0b6b3a76400006121be90919063ffffffff16565b600a8501546109d0908b9063ffffffff6121e616565b816109d757fe5b600b86015491900491506109f1908263ffffffff61222016565b600b8501556000610a088a8363ffffffff61222016565b90508085600101541015610a2e5760405162461bcd60e51b8152600401610955906130d9565b610a388c82612245565b60405133908b156108fc02908c906000818181858888f19350505050158015610a65573d6000803e3d6000fd5b508b6001336001600160a01b03166000805160206132ad8339815191528e878f42604051610a969493929190612c81565b60405180910390a4610aa78c61207c565b505050505050505050505050565b60001981565b60055481565b600083815260016020526040902054839042118015610afd575060008181526001602052604081206006015460ff166002811115610afb57fe5b145b15610b0b57610b0b8161202c565b8360008060008381526001602052604090206006015460ff166002811115610b2f57fe5b14610b3957600080fd5b6000868152600160205260408120903490610b55828a8a610c4f565b905086811015610b775760405162461bcd60e51b8152600401610955906131a3565b600a830154600090670de0b6b3a764000090610b9a90859063ffffffff6121e616565b81610ba157fe5b600b8601549190049150610bbb908263ffffffff61222016565b600b8501556000610bd2848363ffffffff6121be16565b60008b8152600e870160205260409020909150610bef8c836122e8565b6003810154841115610c135760405162461bcd60e51b81526004016109559061315d565b610c1f338d8d87612381565b8b6000336001600160a01b03166000805160206132ad8339815191528e888a42604051610a969493929190612c81565b60008281526001602052604081206060610c6885612410565b90506000610ca8670de0b6b3a7640000610c9285600a01600001548a6121e690919063ffffffff16565b81610c9957fe5b8991900463ffffffff6121be16565b90506000828681518110610cb857fe5b602002602001015190506000610cdf670de0b6b3a7640000836121e690919063ffffffff16565b905060005b8451811015610d4a57878114610d42576000858281518110610d0257fe5b60200260200101519050610d3e610d22868361222090919063ffffffff16565b610d32858463ffffffff6121e616565b9063ffffffff6124a316565b9250505b600101610ce4565b5060008111610d6b5760405162461bcd60e51b815260040161095590612cec565b610da2610d8682670de0b6b3a764000063ffffffff6124a316565b610d96848663ffffffff61222016565b9063ffffffff6121be16565b9998505050505050505050565b60009081526001602052604090206009015490565b60008181526001602052604081206002600682015460ff166002811115610de757fe5b14610df657600091505061088c565b600d810154600890910154101592915050565b600081815260016020526040902054819042118015610e45575060008181526001602052604081206006015460ff166002811115610e4357fe5b145b15610e5357610e538161202c565b8160008060008381526001602052604090206006015460ff166002811115610e7757fe5b14610e8157600080fd5b610e8b84346124d3565b50505050565b8060028060008381526001602052604090206006015460ff166002811115610eb557fe5b14610ebf57600080fd5b6000838152600160205260409020610ed6846116ee565b336000908152600482016020526040902054610f045760405162461bcd60e51b815260040161095590613096565b33600090815260058201602052604090205460ff1615610f365760405162461bcd60e51b81526004016109559061304f565b6000610f41856119e4565b33600090815260048401602052604081205491925090670de0b6b3a764000090610f7290849063ffffffff6121e616565b81610f7957fe5b0490508083600101541015610fa05760405162461bcd60e51b815260040161095590612eb5565b6001830154610fb5908263ffffffff6121be16565b600184810191909155336000818152600580870160209081526040808420805460ff19169096179095556004880190528382205493518a949193926000805160206132ad8339815191529261100d9288904290612c81565b60405180910390a4604051339082156108fc029083906000818181858888f19350505050158015611042573d6000803e3d6000fd5b50505050505050565b8060028060008381526001602052604090206006015460ff16600281111561106f57fe5b1461107957600080fd5b600083815260016020908152604080832060088101548452600e81018352818420338552600481019093529220546110c35760405162461bcd60e51b815260040161095590612dc6565b33600090815260058201602052604090205460ff16156110f55760405162461bcd60e51b815260040161095590612f76565b336000908152600482016020526040902054600183015481111561112b5760405162461bcd60e51b815260040161095590612eb5565b6001830154611140908263ffffffff6121be16565b6001808501919091553360009081526005840160205260409020805460ff1916909117905585600460088501543360008181526004870160205260409081902054905191926000805160206132ad8339815191529261100d929088904290612c81565b6004546001600160a01b031681565b60008060006111c0846119e4565b6111cb8560006111e9565b6111d68660016111e9565b9250925092509193909250565b60025481565b6000828152600160209081526040808320848452600e810190925282206002600683015460ff16600281111561121b57fe5b14801561122e575061122c85610dc4565b155b15611258576008820154841461124557600061124f565b670de0b6b3a76400005b925050506112a3565b6003808301549082015461129e919061129290670de0b6b3a76400009061128690849063ffffffff6121be16565b9063ffffffff6121e616565b9063ffffffff61286b16565b925050505b92915050565b6000828152600160205260409020548290421180156112e5575060008181526001602052604081206006015460ff1660028111156112e357fe5b145b156112f3576112f38161202c565b8260008060008381526001602052604090206006015460ff16600281111561131757fe5b1461132157600080fd5b6000858152600160209081526040808320338452600481019092529091205485111561135f5760405162461bcd60e51b81526004016109559061311c565b611368866116ee565b6113748686600361288c565b50606061138087612410565b9050606081516040519080825280602002602001820160405280156113af578160200160208202803883390190505b50905060001960005b83518110156113ee5760008482815181106113cf57fe5b60200260200101519050808311156113e5578092505b506001016113b8565b50600284015460009061140b906112928b8563ffffffff6121e616565b905060005b84518110156114a95785600201546114448b87848151811061142e57fe5b60200260200101516121e690919063ffffffff16565b8161144b57fe5b0484828151811061145857fe5b60200260200101818152505061148a8285838151811061147457fe5b60200260200101516121be90919063ffffffff16565b84828151811061149657fe5b6020908102919091010152600101611410565b506114b48a82612245565b60028501546114c9908a63ffffffff6121be16565b60028601553360009081526004860160205260409020546114f0908a63ffffffff6121be16565b3360009081526004870160205260408120919091555b84518110156115f157600084828151811061151d57fe5b602002602001015111156115e9576003808701546000838152600e89016020526040902090910154855161156a9033908f9086908a908290811061155d57fe5b6020026020010151612381565b8c6000336001600160a01b03166000805160206132ad833981519152868a888151811061159357fe5b60200260200101516115cd8e600301546112928e8c815181106115b257fe5b60200260200101516112868b8d6121be90919063ffffffff16565b426040516115de9493929190612c81565b60405180910390a450505b600101611506565b50604051339082156108fc029083906000818181858888f1935050505015801561161f573d6000803e3d6000fd5b50896003336001600160a01b03166000805160206132ad83398151915260008d86426040516116519493929190612c81565b60405180910390a4896000805160206132cd83398151915286600201546116778d6119e4565b4260405161168793929190613253565b60405180910390a250505050505050505050565b600082815260016020908152604080832060028101546001600160a01b0386168552600482019093529083205490916116e69161129290670de0b6b3a764000063ffffffff6121e616565b949350505050565b6000818152600160205260408120906117078333611fb3565b9050801561177357336000908152600c83016020526040902054611731908263ffffffff61222016565b336000818152600c85016020526040808220939093559151909183156108fc02918491818181858888f19350505050158015611771573d6000803e3d6000fd5b505b8260063360008181526004860160205260408082205490516000805160206132ad833981519152926117aa92909188904290612c81565b60405180910390a4505050565b60009182526001602081815260408085206001600160a01b03949094168086526004808601845282872054878052600e9096018085528388208389528201855283882054958852845282872091875201909152909220549092565b60008181526001602052604081206002600682015460ff16600281111561183557fe5b146118455760001991505061088c565b6008015492915050565b6000818152600160208190526040822060068101548154600283015493830154600384015486958695869586958695929460ff90921693909290916118938d611812565b949d939c50919a509850965090945092505050565b670de0b6b3a764000081565b600082815260016020526040812060606118cd85612410565b600a8301549091506000906118f190670de0b6b3a76400009063ffffffff6121be16565b61190988670de0b6b3a764000063ffffffff6121e616565b8161191057fe5b049050600082868151811061192157fe5b602002602001015190506000611948670de0b6b3a7640000836121e690919063ffffffff16565b905060005b84518110156119975787811461198f57600085828151811061196b57fe5b6020026020010151905061198b610d2286836121be90919063ffffffff16565b9250505b60010161194d565b50600081116119b85760405162461bcd60e51b815260040161095590612cec565b610da282610d966119d784670de0b6b3a764000063ffffffff6124a316565b869063ffffffff61222016565b60008181526001602052604081206002600682015460ff166002811115611a0757fe5b148015611a1a5750611a1883610dc4565b155b15611a6257600281015460088201546000908152600e83016020526040902060030154611a5a919061129290670de0b6b3a764000063ffffffff6121e616565b91505061088c565b6003810154600d8201546002830154611a9092916112929190670de0b6b3a76400000263ffffffff6121e616565b9392505050565b60035481565b60606000805480602002602001604051908101604052809291908181526020018280548015611aeb57602002820191906000526020600020905b815481526020019060010190808311611ad7575b5050505050905090565b8160028060008381526001602052604090206006015460ff166002811115611b1957fe5b14611b2357600080fd5b6000848152600160209081526040808320868452600e8101835281842033855260048101909352922054611b695760405162461bcd60e51b815260040161095590612d50565b33600090815260068201602052604090205460ff1615611b9b5760405162461bcd60e51b815260040161095590613210565b6000611ba787876111e9565b33600090815260048401602052604081205491925090611bdc90670de0b6b3a76400009061129290859063ffffffff6121e616565b90508084600101541015611c025760405162461bcd60e51b815260040161095590612eb5565b6001840154611c17908263ffffffff6121be16565b6001808601919091553360009081526006850160205260409020805460ff19169091179055876007336000818152600487016020526040908190205490516000805160206132ad83398151915291611c75918d919088904290612c81565b60405180910390a4604051339082156108fc029083906000818181858888f19350505050158015611caa573d6000803e3d6000fd5b505050505050505050565b6007546006546040516370a0823160e01b8152600092916001600160a01b0316906370a0823190611cea903390600401612bb7565b60206040518083038186803b158015611d0257600080fd5b505afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d3a9190810190612a10565b1015611d585760405162461bcd60e51b815260040161095590612f2c565b60025460008054600181810183557f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639091018390558282526020526040902034611db45760405162461bcd60e51b815260040161095590612d21565b42861015611dd45760405162461bcd60e51b815260040161095590613005565b83600214611df45760405162461bcd60e51b815260040161095590612e10565b85815560068101805460ff19169055600354600a820155600019600882015560005b84811015611e5857600d820180546001818101835560009283526020808420909201849055838352600e85019091526040909120848155810182905501611e16565b506004805460055460405163d4876b9f60e01b81526001600160a01b0390921692839263d4876b9f92611e9b926002928f928d9290918f91600091829101612c9c565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611eed9190810190612a10565b6009830155611efc83346124d3565b611f058361207c565b82336001600160a01b03167f928446b14f4c661d8499681f1d2eb118eb6e89066877a7d43e0672a27cc63a32878c8c604051611f4393929190613269565b60405180910390a350506002805460010190559695505050505050565b6000828152600160209081526040808320848452600e8101909252822082918291611f8b87876111e9565b6003820154600290920154909891975095509350505050565b6006546001600160a01b031681565b600082815260016020908152604080832060028101546001600160a01b03861685526004820190935290832054600b82015491928492611ffd92611292919063ffffffff6121e616565b6001600160a01b0385166000908152600c8401602052604090205490915061129e90829063ffffffff6121be16565b6000818152600160205260409020600681015460ff16600281111561204d57fe5b600101600281111561205b57fe5b60068201805460ff1916600183600281111561207357fe5b02179055505050565b6000818152600160205260408120905b600d8201548110156120e45780837f8270f0a0534b13b7f92d1dbd58aa75c5207b40c55fefa7a17110c6136ad7270b6120c586856111e9565b426040516120d492919061329e565b60405180910390a360010161208c565b50816000805160206132cd8339815191528260020154612103856119e4565b4260405161211393929190613253565b60405180910390a25050565b6000838152600160209081526040808320858452600e810183528184206001600160a01b038916855260048101909352922054612162908463ffffffff6121be16565b6001600160a01b03871660009081526004830160205260409020556003810154612192908463ffffffff61222016565b6003808301919091558201546121ae908463ffffffff61222016565b8260030181905550505050505050565b6000828211156121e05760405162461bcd60e51b815260040161095590612e7e565b50900390565b6000826121f5575060006112a3565b8282028284828161220257fe5b0414611a905760405162461bcd60e51b815260040161095590612fc4565b600082820183811015611a905760405162461bcd60e51b815260040161095590612d91565b6000828152600160205260408120905b600d8201548110156122c8576000818152600e8301602052604090206003810154612286908563ffffffff6121be16565b600382015560028101546122a0908563ffffffff6121be16565b600282015560038301546122ba908563ffffffff6121be16565b600384015550600101612255565b5060018101546122de908363ffffffff6121be16565b6001909101555050565b6000828152600160205260408120905b600d82015481101561236b576000818152600e8301602052604090206003810154612329908563ffffffff61222016565b60038201556002810154612343908563ffffffff61222016565b6002820155600383015461235d908563ffffffff61222016565b6003840155506001016122f8565b5060018101546122de908363ffffffff61222016565b6000838152600160209081526040808320858452600e810183528184206001600160a01b0389168552600481019093529220546123c4908463ffffffff61222016565b6001600160a01b038716600090815260048301602052604090205560038101546123f4908463ffffffff6121be16565b6003808301919091558201546121ae908463ffffffff6121be16565b600081815260016020908152604091829020600d81015483518181528184028101909301909352606092909183918015612454578160200160208202803883390190505b50905060005b600d83015481101561249b576000818152600e84016020526040902060030154825183908390811061248857fe5b602090810291909101015260010161245a565b509392505050565b600082156124c2578160018403816124b757fe5b0460010190506112a3565b8183816124cb57fe5b049392505050565b60008281526001602052604090205482904211801561250f575060008181526001602052604081206006015460ff16600281111561250d57fe5b145b1561251d5761251d8161202c565b8260008060008381526001602052604090206006015460ff16600281111561254157fe5b1461254b57600080fd5b6000858152600160205260409020846125765760405162461bcd60e51b815260040161095590612e47565b6000606061258388612410565b9050606081516040519080825280602002602001820160405280156125b2578160200160208202803883390190505b506002850154909150600090156126a15760005b83518110156125fc5760008482815181106125dd57fe5b60200260200101519050808310156125f3578092505b506001016125c6565b5060005b835181101561266c5760008261263286848151811061261b57fe5b60200260200101518d6121e690919063ffffffff16565b8161263957fe5b04905061264c8b8263ffffffff6121be16565b84838151811061265857fe5b602090810291909101015250600101612600565b508061268586600201548b6121e690919063ffffffff16565b8161268c57fe5b04935061269b8a85600261288c565b506126a5565b8893505b60028501546126ba908563ffffffff61222016565b60028601553360009081526004860160205260409020546126e1908563ffffffff61222016565b3360009081526004870160205260409020556126fd8a8a6122e8565b60005b82518110156127c357600083828151811061271757fe5b602002602001015111156127bb576003808701546000838152600e8901602052604090209091015484516127579033908f90869089908290811061155d57fe5b8c6000336001600160a01b03166000805160206132ad8339815191528689888151811061278057fe5b602002602001015161279f8e600301546112928d8c815181106115b257fe5b426040516127b09493929190612c81565b60405180910390a450505b600101612700565b5060006127cf8b6119e4565b90506000670de0b6b3a76400006127ec838863ffffffff6121e616565b816127f357fe5b0490508b6002336001600160a01b03166000805160206132ad83398151915260008a86426040516128279493929190612c81565b60405180910390a48b6000805160206132cd8339815191528860020154844260405161285593929190613253565b60405180910390a2505050505050505050505050565b60008082116124c25760405162461bcd60e51b815260040161095590612ef8565b60008381526001602052604081206002810154600b82015483916128bb9161129290889063ffffffff6121e616565b905060028460078111156128cb57fe5b141561292457600b8201546128e6908263ffffffff61222016565b600b830155336000908152600c8301602052604090205461290d908263ffffffff61222016565b336000908152600c84016020526040902055612973565b600b820154612939908263ffffffff6121be16565b600b830155336000908152600c83016020526040902054612960908263ffffffff6121be16565b336000908152600c840160205260409020555b50509392505050565b80356001600160a01b03811681146112a357600080fd5b600082601f8301126129a3578081fd5b81356001600160401b03808211156129b9578283fd5b604051601f8301601f1916810160200182811182821017156129d9578485fd5b6040528281529250828483016020018610156129f457600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215612a21578081fd5b5051919050565b600080600080600060a08688031215612a3f578081fd5b85356001600160401b0380821115612a55578283fd5b612a6189838a01612993565b96506020880135915080821115612a76578283fd5b50612a8388828901612993565b94505060408601359250612a9a876060880161297c565b949793965091946080013592915050565b600060208284031215612abc578081fd5b5035919050565b60008060408385031215612ad5578182fd5b82359150612ae6846020850161297c565b90509250929050565b60008060408385031215612b01578182fd5b50508035926020909101359150565b600080600060608486031215612b24578283fd5b505081359360208301359350604090920135919050565b60008060008060808587031215612b50578384fd5b5050823594602084013594506040840135936060013592509050565b60008151808452815b81811015612b9157602081850181015186830182015201612b75565b81811115612ba25782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b81811015612c0357835183529284019291840191600101612be7565b50909695505050505050565b901515815260200190565b94151585529215156020850152901515604084015215156060830152608082015260a00190565b90815260200190565b60c0810160038810612c5857fe5b968152602081019590955260408501939093526060840191909152608083015260a09091015290565b93845260208401929092526040830152606082015260800190565b600088825260e06020830152612cb560e0830189612b6c565b6001600160a01b039790971660408301525063ffffffff948516606082015292909316608083015260a082015260c0015292915050565b6020808252601b908201527a6d7573742068617665206e6f6e2d7a65726f2062616c616e63657360281b604082015260600190565b60208082526015908201527407374616b65206e6565647320746f206265203e203605c1b604082015260600190565b60208082526021908201527f7573657220646f6573206e6f7420686f6c64206f7574636f6d652073686172656040820152607360f81b606082015260800190565b6020808252601b908201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604082015260600190565b6020808252602a908201527f7573657220646f6573206e6f7420686f6c64207265736f6c766564206f7574636040820152696f6d652073686172657360b01b606082015260800190565b6020808252601e908201527f6e756d626572206f66206f7574636f6d65732068617320746f20626520320000604082015260600190565b6020808252601f908201527f7374616b652068617320746f2062652067726561746572207468616e20302e00604082015260600190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b60208082526023908201527f4d61726b657420646f6573206e6f74206861766520656e6f7567682062616c616040820152626e636560e81b606082015260800190565b6020808252601a9082015279536166654d6174683a206469766973696f6e206279207a65726f60301b604082015260600190565b6020808252602a908201527f6d73672e73656e646572206d75737420686f6c64206d696e696d756d2065726360408201526932302062616c616e636560b01b606082015260800190565b6020808252602e908201527f7573657220616c726561647920636c61696d6564207265736f6c766564206f7560408201526d74636f6d652077696e6e696e677360901b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252602a908201527f6d61726b6574206d757374207265736f6c7665206166746572207468652063756040820152697272656e74206461746560b01b606082015260800190565b60208082526027908201527f7573657220616c726561647920636c61696d6564206c69717569646974792077604082015266696e6e696e677360c81b606082015260800190565b60208082526023908201527f7573657220646f6573206e6f7420686f6c64206c69717569646974792073686160408201526272657360e81b606082015260800190565b60208082526023908201527f6d61726b657420646f6573206e6f74206861766520656e6f7567682062616c616040820152626e636560e81b606082015260800190565b60208082526021908201527f7573657220646f6573206e6f74206861766520656e6f7567682062616c616e636040820152606560f81b606082015260800190565b60208082526026908201527f6f7574636f6d652073686172657320706f6f6c2062616c616e636520697320746040820152656f6f206c6f7760d01b606082015260800190565b6020808252601e908201527f6d696e696d756d2062757920616d6f756e74206e6f7420726561636865640000604082015260600190565b6020808252601c908201527b1b585e1a5b5d5b481cd95b1b08185b5bdd5b9d08195e18d95959195960221b604082015260600190565b60208082526023908201527f7573657220616c726561647920636c61696d6564206f7574636f6d652073686160408201526272657360e81b606082015260800190565b9283526020830191909152604082015260600190565b6000848252606060208301526132826060830185612b6c565b82810360408401526132948185612b6c565b9695505050505050565b91825260208201526040019056fe9dcabe311735ed0d65f0c22c5425d1f17331f94c9d0767f59e58473cf95ada611eca98f266e5348ae38d5d057a4d8e451e76672f69ac6ba4b0e3b31ea9c7eb2ba2646970667358221220bb3570dbb9f12939d26e065d1baf2ae8ff33a6895b5447dba96d743778cfc85b64736f6c6343000602003300000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000008b29344f368b5fa35595325903fe0eaab70c8e1f00000000000000000000000000000000000000000000003635c9adc5dea0000000000000000000000000000060d7956805ec5a698173def4d0e1ecdefb06cc57000000000000000000000000000000000000000000000000000000000003f480

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

00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000008b29344f368b5fa35595325903fe0eaab70c8e1f00000000000000000000000000000000000000000000003635c9adc5dea0000000000000000000000000000060d7956805ec5a698173def4d0e1ecdefb06cc57000000000000000000000000000000000000000000000000000000000003f480

-----Decoded View---------------
Arg [0] : _fee (uint256): 20000000000000000
Arg [1] : _token (address): 0x8b29344f368b5fa35595325903fe0eaab70c8e1f
Arg [2] : _requiredBalance (uint256): 1000000000000000000000
Arg [3] : _realitioAddress (address): 0x60d7956805ec5a698173def4d0e1ecdefb06cc57
Arg [4] : _realitioTimeout (uint256): 259200

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000470de4df820000
Arg [1] : 0000000000000000000000008b29344f368b5fa35595325903fe0eaab70c8e1f
Arg [2] : 00000000000000000000000000000000000000000000003635c9adc5dea00000
Arg [3] : 00000000000000000000000060d7956805ec5a698173def4d0e1ecdefb06cc57
Arg [4] : 000000000000000000000000000000000000000000000000000000000003f480


Deployed ByteCode Sourcemap

49503:30633:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52542:30;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52542:30:0;;;:::i;:::-;;;;;;;;;;;;;;;;76528:296;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;76528:296:0;;;;;;;;:::i;:::-;;;;;;;;;;65631:641;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;65631:641:0;;;;;;;;:::i;74726:710::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;74726:710:0;;;;;;;;:::i;:::-;;;;;;;;;;;;78663:171;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;78663:171:0;;;;;;;;:::i;:::-;;;;;;;;58968:1272;;;;;;;;;:::i;:::-;;50431:117;;8:9:-1;5:2;;;30:1;27;20:12;5:2;50431:117:0;;;:::i;52417:30::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52417:30:0;;;:::i;57787:1131::-;;;;;;;;;:::i;55803:903::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;55803:903:0;;;;;;;;:::i;76830:175::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;76830:175:0;;;;;;;;:::i;78226:393::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;78226:393:0;;;;;;;;:::i;:::-;;;;;;;;60296:188;;;;;;;;;:::i;68661:1061::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;68661:1061:0;;;;;;;;:::i;66351:1036::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;66351:1036:0;;;;;;;;:::i;52382:30::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52382:30:0;;;:::i;:::-;;;;;;;;77011:264;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;77011:264:0;;;;;;;;:::i;52214:26::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52214:26:0;;;:::i;78840:527::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;78840:527:0;;;;;;;;:::i;63122:2429::-;;;;;;;;;:::i;75442:226::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;75442:226:0;;;;;;;;:::i;69808:545::-;;;;;;;;;:::i;74355:365::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;74355:365:0;;;;;;;;:::i;77908:312::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;77908:312:0;;;;;;;;:::i;76083:439::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;76083:439:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;50555:36;;8:9:-1;5:2;;;30:1;27;20:12;5:2;50555:36:0;;;:::i;56814:924::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;56814:924:0;;;;;;;;:::i;77281:621::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;77281:621:0;;;;;;;;:::i;52264:18::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52264:18:0;;;:::i;75987:90::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;75987:90:0;;;:::i;67468:1104::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;67468:1104:0;;;;;;;;:::i;54000:1724::-;;;;;;;;;:::i;79373:388::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;79373:388:0;;;;;;;;:::i;52474:19::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;52474:19:0;;;:::i;75674:307::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;75674:307:0;;;;;;;;:::i;52542:30::-;;;;:::o;76528:296::-;76616:7;76697:17;;;:7;:17;;;;;76731:11;;;:17;76750:28;;;;;76731:17;;76750:28;;76528:296::o;65631:641::-;65809:7;52805:17;;;:7;:17;;;;;:35;65712:8;;52799:3;:41;:88;;;;-1:-1:-1;52871:16:0;52844:17;;;:7;:17;;;;;:23;;;;;:43;;;;;;;;;52799:88;52795:130;;;52898:19;52908:8;52898:9;:19::i;:::-;65735:8;65745:18:::1;::::0;53013:17:::1;::::0;;;:7:::1;:17;::::0;;;;:23:::1;;::::0;::::1;;:32;::::0;::::1;;;;;;;53005:41;;;::::0;::::1;;65828:21:::3;65852:17:::0;;;:7:::3;:17;::::0;;;;;65917:15:::3;::::0;;66034:28;;;;66015:48;;-1:-1:-1;;;66015:48:0;;65785:8;;65852:17;;-1:-1:-1;;;;;65917:15:0;;::::3;::::0;65828:21;65917:15;;66015:18:::3;::::0;:48:::3;::::0;::::3;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::3;5:2;66015:48:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::3;77:16;74:1;67:27;5:2;66015:48:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;66015:48:0;;;;;;;;;66073:27:::0;;;:39;;;66126:52:::3;::::0;66007:57;;-1:-1:-1;66153:8:0;;66141:10:::3;::::0;66126:52:::3;::::0;::::3;::::0;66007:57;;66174:3:::3;::::0;66126:52:::3;;;;;;;;;;66185:38;66214:8;66185:28;:38::i;:::-;-1:-1:-1::0;;66239:27:0;;;;-1:-1:-1;53248:19:0::2;53258:8;53248:9;:19::i;:::-;53053:1;52931::::1;;65631:641:::0;;;;:::o;74726:710::-;74830:4;74931:17;;;:7;:17;;;;;74830:4;;;;;;;;75011:20;74995:12;;;;;;:36;;;;;;;;;74991:132;;75050:5;75057;75064;75071;75078:36;75099:8;75109:4;75078:20;:36::i;:::-;75042:73;;;;;;;;;;;;;74991:132;75179:27;;;;75131:29;75163:44;;;:15;;;:44;;;;;;;;-1:-1:-1;;;;;75232:28:0;;;;:22;;;;:28;;;;;;75273:21;;;;:27;;;;;;75309:22;;;:28;;;;;;75350:22;;;:28;;;;;;;;75163:44;;75232:32;;;;75273:27;;;;;75309:32;;;;75350:28;75387:36;75408:8;75255:4;75387:20;:36::i;:::-;75216:214;;;;;;;;;;;;74726:710;;;;;;;;;:::o;78663:171::-;78756:21;78780:17;;;:7;:17;;;;;;;;;78811;;;78804:24;;;;;;;;;;;;;;;;;78731:16;;78780:17;;78804:24;;78811:17;78804:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;78663:171;;;;:::o;58968:1272::-;52805:17;;;;:7;:17;;;;;:35;59124:8;;52799:3;:41;:88;;;;-1:-1:-1;52871:16:0;52844:17;;;:7;:17;;;;;:23;;;;;:43;;;;;;;;;52799:88;52795:130;;;52898:19;52908:8;52898:9;:19::i;:::-;59142:8;59152:16:::1;::::0;53013:17:::1;::::0;;;:7:::1;:17;::::0;;;;:23:::1;;::::0;::::1;;:32;::::0;::::1;;;;;;;53005:41;;;::::0;::::1;;59177:21:::2;59201:17:::0;;;:7:::2;:17;::::0;;;;;;;59257:26;;;:15:::2;::::0;::::2;:26:::0;;;;;59201:17;;59309:42:::2;59324:5:::0;59209:8;59273:9;59309:14:::2;:42::i;:::-;59292:59;;59378:22;59368:6;:32;;59360:73;;;;-1:-1:-1::0;;;59360:73:0::2;;;;;;;;;;;;;;;;;59471:10;59448:34;::::0;;;:22;;;:34:::2;::::0;;;;;:44;-1:-1:-1;59448:44:0::2;59440:90;;;;-1:-1:-1::0;;;59440:90:0::2;;;;;;;;;59539:68;59567:10;59579:8;59589:9;59600:6;59539:27;:68::i;:::-;59656:17;59708:12;59716:3;;50585:6;59708:7;;:12;;;;:::i;:::-;59686:11;::::0;::::2;:17:::0;59676:28:::2;::::0;:5;;:28:::2;:9;:28;:::i;:::-;:45;;;;;59753:22:::0;;;;59676:45;;::::2;::::0;-1:-1:-1;59753:37:0::2;::::0;59676:45;59753:37:::2;:26;:37;:::i;:::-;59728:22:::0;;;:62;59797:21:::2;59821:20;:5:::0;59831:9;59821:20:::2;:9;:20;:::i;:::-;59797:44;;59876:13;59858:6;:14;;;:31;;59850:79;;;;-1:-1:-1::0;;;59850:79:0::2;;;;;;;;;59972:47;59995:8;60005:13;59972:22;:47::i;:::-;60063:26;::::0;:10:::2;::::0;:26;::::2;;;::::0;60083:5;;60063:26:::2;::::0;;;60083:5;60063:10;:26;::::2;;;;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;60149:8:0;60130:17:::2;60118:10;-1:-1:-1::0;;;;;60103:86:0::2;-1:-1:-1::0;;;;;;;;;;;60159:9:0::2;60170:6;60178:5;60185:3;60103:86;;;;;;;;;;;;;;;;;;60196:38;60225:8;60196:28;:38::i;:::-;53053:1;;;;;52931::::1;;58968:1272:::0;;;;;:::o;50431:117::-;-1:-1:-1;;50431:117:0;:::o;52417:30::-;;;;:::o;57787:1131::-;52805:17;;;;:7;:17;;;;;:35;57921:8;;52799:3;:41;:88;;;;-1:-1:-1;52871:16:0;52844:17;;;:7;:17;;;;;:23;;;;;:43;;;;;;;;;52799:88;52795:130;;;52898:19;52908:8;52898:9;:19::i;:::-;57939:8;57949:16:::1;::::0;53013:17:::1;::::0;;;:7:::1;:17;::::0;;;;:23:::1;;::::0;::::1;;:32;::::0;::::1;;;;;;;53005:41;;;::::0;::::1;;57974:21:::2;57998:17:::0;;;:7:::2;:17;::::0;;;;;58040:9:::2;::::0;58073:41:::2;58040:9:::0;58006:8;58104:9;58073:13:::2;:41::i;:::-;58056:58;;58139:21;58129:6;:31;;58121:74;;;;-1:-1:-1::0;;;58121:74:0::2;;;;;;;;;58281:11;::::0;::::2;:17:::0;58251::::2;::::0;50585:6:::2;::::0;58271:28:::2;::::0;:5;;:28:::2;:9;:28;:::i;:::-;:34;;;;;58337:22:::0;;;;58271:34;;::::2;::::0;-1:-1:-1;58337:37:0::2;::::0;58271:34;58337:37:::2;:26;:37;:::i;:::-;58312:22:::0;;;:62;58381:22:::2;58406:20;:5:::0;58416:9;58406:20:::2;:9;:20;:::i;:::-;58435:29;58467:26:::0;;;:15:::2;::::0;::::2;:26;::::0;;;;58381:45;;-1:-1:-1;58552:43:0::2;58570:8:::0;58381:45;58552:17:::2;:43::i;:::-;58612:24:::0;;;;:34;-1:-1:-1;58612:34:0::2;58604:85;;;;-1:-1:-1::0;;;58604:85:0::2;;;;;;;;;58698:70;58728:10;58740:8;58750:9;58761:6;58698:29;:70::i;:::-;58827:8:::0;58809:16:::2;58797:10;-1:-1:-1::0;;;;;58782:85:0::2;-1:-1:-1::0;;;;;;;;;;;58837:9:0::2;58848:6;58856:5;58863:3;58782:85;;;;;;;;;;55803:903:::0;55920:7;55960:17;;;:7;:17;;;;;55986:31;56020:33;55968:8;56020:23;:33::i;:::-;55986:67;;56060:23;56086:47;50585:6;56097:29;56108:6;:11;;:17;;;56097:6;:10;;:29;;;;:::i;:::-;:35;;;;;56086:6;;56097:35;;56086:47;:10;:47;:::i;:::-;56060:73;;56140:27;56170:14;56185:9;56170:25;;;;;;;;;;;;;;56140:55;;56202:28;56233;50585:6;56233:19;:23;;:28;;;;:::i;:::-;56202:59;-1:-1:-1;56273:9:0;56268:267;56292:14;:21;56288:1;:25;56268:267;;;56338:9;56333:1;:14;56329:199;;56360:21;56384:14;56399:1;56384:17;;;;;;;;;;;;;;56360:41;;56435:83;56483:34;56501:15;56483:13;:17;;:34;;;;:::i;:::-;56435:39;:20;56460:13;56435:39;:24;:39;:::i;:::-;:47;:83;:47;:83;:::i;:::-;56412:106;;56329:199;;56315:3;;56268:267;;;;56572:1;56549:20;:24;56541:64;;;;-1:-1:-1;;;56541:64:0;;;;;;;;;56621:79;56666:33;:20;50585:6;56666:33;:28;:33;:::i;:::-;56621:40;:19;56645:15;56621:40;:23;:40;:::i;:::-;:44;:79;:44;:79;:::i;:::-;56614:86;55803:903;-1:-1:-1;;;;;;;;;55803:903:0:o;76830:175::-;76896:7;76936:17;;;:7;:17;;;;;76970:28;;;;76830:175::o;78226:393::-;78289:4;78326:17;;;:7;:17;;;;;78428:20;78412:12;;;;;;:36;;;;;;;;;78408:71;;78466:5;78459:12;;;;;78408:71;78589:17;;;:24;78558:27;;;;;:55;;;78226:393;-1:-1:-1;;78226:393:0:o;60296:188::-;52805:17;;;;:7;:17;;;;;:35;60384:8;;52799:3;:41;:88;;;;-1:-1:-1;52871:16:0;52844:17;;;:7;:17;;;;;:23;;;;;:43;;;;;;;;;52799:88;52795:130;;;52898:19;52908:8;52898:9;:19::i;:::-;60407:8;60417:16:::1;::::0;53013:17:::1;::::0;;;:7:::1;:17;::::0;;;;:23:::1;;::::0;::::1;;:32;::::0;::::1;;;;;;;53005:41;;;::::0;::::1;;60445:33:::2;60458:8;60468:9;60445:12;:33::i;:::-;52931:1:::1;;60296:188:::0;;:::o;68661:1061::-;68718:8;68728:20;;53013:17;;;;:7;:17;;;;;:23;;;;;:32;;;;;;;;;53005:41;;;;;;68757:21:::1;68781:17:::0;;;:7:::1;:17;::::0;;;;68841:19:::1;68789:8:::0;68841:9:::1;:19::i;:::-;68900:10;68914:1;68877:34:::0;;;:22:::1;::::0;::::1;:34;::::0;;;;;68869:86:::1;;;;-1:-1:-1::0;;;68869:86:0::1;;;;;;;;;68993:10;68970:34;::::0;;;:22:::1;::::0;::::1;:34;::::0;;;;;::::1;;:43;68962:95;;;;-1:-1:-1::0;;;68962:95:0::1;;;;;;;;;69134:22;69159:33;69183:8;69159:23;:33::i;:::-;69257:10;69199:13;69234:34:::0;;;:22:::1;::::0;::::1;:34;::::0;;;;;69134:58;;-1:-1:-1;69199:13:0;50585:6:::1;::::0;69215:54:::1;::::0;69134:58;;69215:54:::1;:18;:54;:::i;:::-;:60;;;;;;69199:76;;69351:5;69333:6;:14;;;:23;;69325:71;;;;-1:-1:-1::0;;;69325:71:0::1;;;;;;;;;69422:14;::::0;::::1;::::0;:25:::1;::::0;69441:5;69422:25:::1;:18;:25;:::i;:::-;69405:14;::::0;;::::1;:42:::0;;;;69477:10:::1;69454:34;::::0;;;:22:::1;::::0;;::::1;:34;::::0;;;;;;;:41;;-1:-1:-1;;69454:41:0::1;::::0;;::::1;::::0;;;69614:22:::1;::::0;::::1;:34:::0;;;;;;69509:172;;69587:8;;69454:22;;69477:10;-1:-1:-1;;;;;;;;;;;69509:172:0;::::1;::::0;69657:5;;69671:3:::1;::::0;69509:172:::1;;;;;;;;;;69690:26;::::0;:10:::1;::::0;:26;::::1;;;::::0;69710:5;;69690:26:::1;::::0;;;69710:5;69690:10;:26;::::1;;;;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;69690:26:0;53053:1;;;68661:1061:::0;;;:::o;66351:1036::-;66407:8;66417:20;;53013:17;;;;:7;:17;;;;;:23;;;;;:32;;;;;;;;;53005:41;;;;;;66446:21:::1;66470:17:::0;;;:7:::1;:17;::::0;;;;;;;66550:27;;;;66534:44;;:15:::1;::::0;::::1;:44:::0;;;;;66626:10:::1;66595:42:::0;;:30;;;:42;;;;;;66587:101:::1;;;;-1:-1:-1::0;;;66587:101:0::1;;;;;;;;;66733:10;66703:41;::::0;;;:29;;;:41:::1;::::0;;;;;::::1;;:50;66695:109;;;;-1:-1:-1::0;;;66695:109:0::1;;;;;;;;;66889:10;66842:13;66858:42:::0;;;:30;;;:42:::1;::::0;;;;;66958:14:::1;::::0;::::1;::::0;:23;-1:-1:-1;66958:23:0::1;66950:71;;;;-1:-1:-1::0;;;66950:71:0::1;;;;;;;;;67047:14;::::0;::::1;::::0;:25:::1;::::0;67066:5;67047:25:::1;:18;:25;:::i;:::-;67030:14;::::0;;::::1;:42:::0;;;;67109:10:::1;67079:41;::::0;;;:29;;;:41:::1;::::0;;;;:48;;-1:-1:-1;;67079:48:0::1;::::0;;::::1;::::0;;67218:8;67183:26:::1;67235:27:::0;;;;67164:10:::1;67271:42;::::0;;;:30;;;:42:::1;::::0;;;;;;;67141:205;;67164:10;;-1:-1:-1;;;;;;;;;;;67141:205:0;::::1;::::0;67271:42;67322:5;;67336:3:::1;::::0;67141:205:::1;;52382:30:::0;;;-1:-1:-1;;;;;52382:30:0;;:::o;77011:264::-;77098:7;77114;77130;77163:33;77187:8;77163:23;:33::i;:::-;77198:34;77220:8;77230:1;77198:21;:34::i;:::-;77234;77256:8;77266:1;77234:21;:34::i;:::-;77155:114;;;;;;77011:264;;;;;:::o;52214:26::-;;;;:::o;78840:527::-;78929:7;78969:17;;;:7;:17;;;;;;;;79025:26;;;:15;;;:26;;;;;79080:20;79064:12;;;;;;:36;;;;;;;;;:65;;;;;79105:24;79120:8;79105:14;:24::i;:::-;79104:25;79064:65;79060:195;;;79210:27;;;;79197:40;;:50;;79246:1;79197:50;;;50585:6;79197:50;79190:57;;;;;;79060:195;79338:22;;;;;79298:24;;;;79270:91;;79338:22;79270:63;;50585:6;;79271:52;;79338:22;;79271:52;:26;:52;:::i;:::-;79270:58;:63;:58;:63;:::i;:::-;:67;:91;:67;:91;:::i;:::-;79263:98;;;;78840:527;;;;;:::o;63122:2429::-;52805:17;;;;:7;:17;;;;;:35;63229:8;;52799:3;:41;:88;;;;-1:-1:-1;52871:16:0;52844:17;;;:7;:17;;;;;:23;;;;;:43;;;;;;;;;52799:88;52795:130;;;52898:19;52908:8;52898:9;:19::i;:::-;63252:8;63262:16:::1;::::0;53013:17:::1;::::0;;;:7:::1;:17;::::0;;;;:23:::1;;::::0;::::1;;:32;::::0;::::1;;;;;;;53005:41;;;::::0;::::1;;63290:21:::2;63314:17:::0;;;:7:::2;:17;::::0;;;;;;;63371:10:::2;63348:34:::0;;:22:::2;::::0;::::2;:34:::0;;;;;;;:44;-1:-1:-1;63348:44:0::2;63340:90;;;;-1:-1:-1::0;;;63340:90:0::2;;;;;;;;;63471:19;63481:8;63471:9;:19::i;:::-;63530:65;63548:8;63558:6;63566:28;63530:17;:65::i;:::-;;63604:31;63638:33;63662:8;63638:23;:33::i;:::-;63604:67;;63678:28;63723:14;:21;63709:36;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;::::0;-1:-1;63709:36:0::2;-1:-1:-1::0;63678:67:0;-1:-1:-1;;;63752:18:0::2;63882:177;63906:14;:21;63902:1;:25;63882:177;;;63943:21;63967:14;63982:1;63967:17;;;;;;;;;;;;;;63943:41;;64010:13;63997:10;:26;63993:58;;;64038:13;64025:26;;63993:58;-1:-1:-1::0;63929:3:0::2;;63882:177;;;-1:-1:-1::0;64120:16:0::2;::::0;::::2;::::0;64067:23:::2;::::0;64093:44:::2;::::0;:22:::2;:6:::0;64104:10;64093:22:::2;:10;:22;:::i;:44::-;64067:70:::0;-1:-1:-1;64151:9:0::2;64146:195;64170:14;:21;64166:1;:25;64146:195;;;64256:6;:16;;;64224:29;64246:6;64224:14;64239:1;64224:17;;;;;;;;;;;;;;:21;;:29;;;;:::i;:::-;:48;;;;;;64207:11;64219:1;64207:14;;;;;;;;;;;;;:65;;;::::0;::::2;64298:35;64317:15;64298:11;64310:1;64298:14;;;;;;;;;;;;;;:18;;:35;;;;:::i;:::-;64281:11;64293:1;64281:14;;;;;;;;;::::0;;::::2;::::0;;;;;:52;64193:3:::2;;64146:195;;;;64388:49;64411:8;64421:15;64388:22;:49::i;:::-;64463:16;::::0;::::2;::::0;:28:::2;::::0;64484:6;64463:28:::2;:20;:28;:::i;:::-;64444:16;::::0;::::2;:47:::0;64612:10:::2;64589:34;::::0;;;:22:::2;::::0;::::2;:34;::::0;;;;;:46:::2;::::0;64628:6;64589:46:::2;:38;:46;:::i;:::-;64575:10;64552:34;::::0;;;:22:::2;::::0;::::2;:34;::::0;;;;:83;;;;64644:594:::2;64668:14;:21;64664:1;:25;64644:594;;;64726:1;64709:11;64721:1;64709:14;;;;;;;;;;;;;;:18;64705:526;;;64763:22;::::0;;::::2;::::0;64740:20:::2;64820:18:::0;;;:15:::2;::::0;::::2;:18;::::0;;;;:35;;;;64923:14;;64868:70:::2;::::0;64898:10:::2;::::0;64910:8;;64836:1;;64923:11;;64836:1;;64923:14;::::2;;;;;;;;;;;64868:29;:70::i;:::-;65033:8:::0;65004:16:::2;64981:10;-1:-1:-1::0;;;;;64954:267:0::2;-1:-1:-1::0;;;;;;;;;;;65054:1:0::2;65068:11;65080:1;65068:14;;;;;;;;;;;;;;65095:81;65153:6;:22;;;65095:53;65133:11;65145:1;65133:14;;;;;;;;;;;;;;65096:31;65113:13;65096:12;:16;;:31;;;;:::i;65095:81::-;65207:3;64954:267;;;;;;;;;;;;;;;;;;64705:526;;;64691:3;;64644:594;;;-1:-1:-1::0;65301:36:0::2;::::0;:10:::2;::::0;:36;::::2;;;::::0;65321:15;;65301:36:::2;::::0;;;65321:15;65301:10;:36;::::2;;;;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;65408:8:0;65378:28:::2;65366:10;-1:-1:-1::0;;;;;65351:99:0::2;-1:-1:-1::0;;;;;;;;;;;65418:1:0::2;65421:6;65429:15;65446:3;65351:99;;;;;;;;;;;;;;;;;;65478:8;-1:-1:-1::0;;;;;;;;;;;65488:6:0::2;:16;;;65506:33;65530:8;65506:23;:33::i;:::-;65541:3;65462:83;;;;;;;;;;;;;;;;;53053:1;;;;;52931::::1;;63122:2429:::0;;;:::o;75442:226::-;75530:7;75570:17;;;:7;:17;;;;;;;;75645:16;;;;-1:-1:-1;;;;;75603:28:0;;;;:22;;;:28;;;;;;;75570:17;;75603:59;;:37;;50585:6;75603:37;:32;:37;:::i;:59::-;75596:66;75442:226;-1:-1:-1;;;;75442:226:0:o;69808:545::-;69867:21;69891:17;;;:7;:17;;;;;;69941:42;69899:8;69972:10;69941:20;:42::i;:::-;69917:66;-1:-1:-1;69996:17:0;;69992:167;;70078:10;70058:31;;;;:19;;;:31;;;;;;:50;;70094:13;70058:50;:35;:50;:::i;:::-;70044:10;70024:31;;;;:19;;;:31;;;;;;:84;;;;70117:34;;70044:10;;70117:34;;;;;70137:13;;70117:34;70024:31;70117:34;70137:13;70044:10;70117:34;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;70117:34:0;69992:167;70245:8;70214:22;70195:10;70262:1;70272:34;;;:22;;;:34;;;;;;;70172:175;;-1:-1:-1;;;;;;;;;;;70172:175:0;;;70262:1;;70315:13;;70337:3;;70172:175;;;;;;;;;;69808:545;;;:::o;74355:365::-;74460:7;74541:17;;;:7;:17;;;;;;;;-1:-1:-1;;;;;74583:28:0;;;;;;;:22;;;;:28;;;;;;74620:18;;;:15;;;;:18;;;;;;:39;;;:33;;:39;;;;;;74668:18;;;;;;;;:39;;;:33;:39;;;;;;;74583:28;;74355:365::o;77908:312::-;77981:6;78020:17;;;:7;:17;;;;;78116:20;78100:12;;;;;;:36;;;;;;;;;78096:68;;-1:-1:-1;;78147:9:0;;;;;78096:68;78186:27;;;;77908:312;-1:-1:-1;;77908:312:0:o;76083:439::-;76168:11;76300:17;;;:7;:17;;;;;;;76342:12;;;;76363:24;;76396:16;;;;76421:14;;;;76444:22;;;;76168:11;;;;;;;;;;76300:17;;76342:12;;;;;76363:24;;76396:16;;76475:34;76308:8;76475:24;:34::i;:::-;76326:190;;;;-1:-1:-1;76326:190:0;;-1:-1:-1;76326:190:0;-1:-1:-1;76326:190:0;-1:-1:-1;76326:190:0;;-1:-1:-1;76083:439:0;-1:-1:-1;;;76083:439:0:o;50555:36::-;50585:6;50555:36;:::o;56814:924::-;56932:30;56995:17;;;:7;:17;;;;;57021:31;57055:33;57003:8;57055:23;:33::i;:::-;57146:11;;;:17;57021:67;;-1:-1:-1;57095:22:0;;57138:26;;50585:6;;57138:26;:7;:26;:::i;:::-;57120:15;:6;50585;57120:15;:10;:15;:::i;:::-;:44;;;;;;57095:69;;57171:28;57202:14;57217:9;57202:25;;;;;;;;;;;;;;57171:56;;57234:28;57265:29;50585:6;57265:20;:24;;:29;;;;:::i;:::-;57234:60;-1:-1:-1;57306:9:0;57301:266;57325:14;:21;57321:1;:25;57301:266;;;57371:9;57366:1;:14;57362:198;;57393:21;57417:14;57432:1;57417:17;;;;;;;;;;;;;;57393:41;;57468:82;57516:33;57534:14;57516:13;:17;;:33;;;;:::i;57468:82::-;57445:105;;57362:198;;57348:3;;57301:266;;;;57604:1;57581:20;:24;57573:64;;;;-1:-1:-1;;;57573:64:0;;;;;;;;;57653:79;57711:20;57653:53;57672:33;:20;50585:6;57672:33;:28;:33;:::i;:::-;57653:14;;:53;:18;:53;:::i;77281:621::-;77353:7;77393:17;;;:7;:17;;;;;77439:20;77423:12;;;;;;:36;;;;;;;;;:65;;;;;77464:24;77479:8;77464:14;:24::i;:::-;77463:25;77423:65;77419:305;;;77699:16;;;;77640:27;;;;77624:44;;;;:15;;;:44;;;;;:61;;;:92;;77699:16;77624:70;;50585:6;77624:70;:65;:70;:::i;:92::-;77617:99;;;;;77419:305;77873:22;;;;77843:17;;;:24;77816:16;;;;:80;;77873:22;77816:52;;:16;50585:6;77837:30;77816:52;:20;:52;:::i;:80::-;77809:87;77281:621;-1:-1:-1;;;77281:621:0:o;52264:18::-;;;;:::o;75987:90::-;76030:16;76062:9;76055:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75987:90;:::o;67468:1104::-;67564:8;67574:20;;53013:17;;;;:7;:17;;;;;:23;;;;;:32;;;;;;;;;53005:41;;;;;;67606:21:::1;67630:17:::0;;;:7:::1;:17;::::0;;;;;;;67686:26;;;:15:::1;::::0;::::1;:26:::0;;;;;67752:10:::1;67729:34:::0;;:22;;;:34;;;;;;67721:84:::1;;;;-1:-1:-1::0;;;67721:84:0::1;;;;;;;;;67848:10;67820:39;::::0;;;:27;;;:39:::1;::::0;;;;;::::1;;:48;67812:96;;;;-1:-1:-1::0;;;67812:96:0::1;;;;;;;;;67980:13;67996:42;68018:8;68028:9;67996:21;:42::i;:::-;68094:10;68045:13;68071:34:::0;;;:22;;;:34:::1;::::0;;;;;67980:58;;-1:-1:-1;68045:13:0;68061:54:::1;::::0;50585:6:::1;::::0;68061:45:::1;::::0;67980:58;;68061:45:::1;:9;:45;:::i;:54::-;68045:70;;68191:5;68173:6;:14;;;:23;;68165:71;;;;-1:-1:-1::0;;;68165:71:0::1;;;;;;;;;68262:14;::::0;::::1;::::0;:25:::1;::::0;68281:5;68262:25:::1;:18;:25;:::i;:::-;68245:14;::::0;;::::1;:42:::0;;;;68322:10:::1;68294:39;::::0;;;:27;;;:39:::1;::::0;;;;:46;;-1:-1:-1;;68294:46:0::1;::::0;;::::1;::::0;;68429:8;68396:24:::1;68377:10;68464:34;::::0;;;:22;;;:34:::1;::::0;;;;;;;68354:177;;-1:-1:-1;;;;;;;;;;;68354:177:0;::::1;::::0;68446:9;;68464:34;68507:5;;68521:3:::1;::::0;68354:177:::1;;;;;;;;;;68540:26;::::0;:10:::1;::::0;:26;::::1;;;::::0;68560:5;;68540:26:::1;::::0;;;68560:5;68540:10;:26;::::1;;;;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;68540:26:0;53053:1;;;;67468:1104:::0;;;;:::o;54000:1724::-;53360:15;;53329:5;;:27;;-1:-1:-1;;;53329:27:0;;54203:7;;53360:15;-1:-1:-1;;;;;53329:5:0;;:15;;:27;;53345:10;;53329:27;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;53329:27:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;53329:27:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;53329:27:0;;;;;;;;;:46;;53321:101;;;;-1:-1:-1;;;53321:101:0;;;;;;;;;54238:11:::1;::::0;54219:16:::1;27:10:-1::0;;39:1:::1;23:18:::0;;::::1;45:23:::0;;54256:24:0;;;::::1;::::0;;;54313:17;;;54256:24:::1;54313:17:::0;;;;54347:9:::1;54339:47;;;;-1:-1:-1::0;;;54339:47:0::1;;;;;;;;;54413:3;54401:8;:15;;54393:70;;;;-1:-1:-1::0;;;54393:70:0::1;;;;;;;;;54590:8;54602:1;54590:13;54582:56;;;;-1:-1:-1::0;;;54582:56:0::1;;;;;;;;;54647:35:::0;;;54689:12:::1;::::0;::::1;:31:::0;;-1:-1:-1;;54689:31:0::1;::::0;;54747:3:::1;::::0;54727:11:::1;::::0;::::1;:23:::0;-1:-1:-1;;54835:27:0;;;:42;54647:24:::1;54919:201;54943:8;54939:1;:12;54919:201;;;54967:17;::::0;::::1;27:10:-1::0;;39:1:::1;23:18:::0;;::::1;45:23:::0;;-1:-1;54967:25:0;;;::::1;::::0;;;;;::::1;::::0;;;55033:18;;;:15:::1;::::0;::::1;:18:::0;;;;;;;55062:27;;;55098:10;::::1;:14:::0;;;54953:3:::1;54919:201;;;-1:-1:-1::0;55205:15:0::1;::::0;;55348::::1;::::0;55261:155:::1;::::0;-1:-1:-1;;;55261:155:0;;-1:-1:-1;;;;;55205:15:0;;::::1;::::0;;;55261:25:::1;::::0;:155:::1;::::0;55295:1:::1;::::0;55305:8;;55322:10;;55348:15;;55380:8;;55166:22:::1;::::0;;;55261:155:::1;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27::::0;20:12:::1;5:2;55261:155:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;55261:155:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;55261:155:0;;;;;;;;;55230:28:::0;;;:186;55425:33:::1;55438:8:::0;55448:9:::1;55425:12;:33::i;:::-;55504:38;55533:8;55504:28;:38::i;:::-;55580:8;55568:10;-1:-1:-1::0;;;;;55554:62:0::1;;55590:8;55600;55610:5;55554:62;;;;;;;;;;;;;;;;;-1:-1:-1::0;;55679:11:0::1;::::0;;55693:1:::1;55679:15;55665:29:::0;;55710:8;54000:1724;-1:-1:-1;;;;;;54000:1724:0:o;79373:388::-;79484:7;79565:17;;;:7;:17;;;;;;;;79621:26;;;:15;;;:26;;;;;79484:7;;;;79664:42;79573:8;79637:9;79664:21;:42::i;:::-;79708:24;;;;:14;;;;79734:20;79656:99;;79708:24;;-1:-1:-1;79734:20:0;-1:-1:-1;79373:388:0;-1:-1:-1;;;;79373:388:0:o;52474:19::-;;;-1:-1:-1;;;;;52474:19:0;;:::o;75674:307::-;75757:7;75797:17;;;:7;:17;;;;;;;;75904:16;;;;-1:-1:-1;;;;;75870:28:0;;;;:22;;;:28;;;;;;;75843:22;;;;75797:17;;75757:7;;75843:78;;:56;;:22;:56;:26;:56;:::i;:78::-;-1:-1:-1;;;;;75949:25:0;;;;;;:19;;;:25;;;;;;75823:98;;-1:-1:-1;75935:40:0;;75823:98;;75935:40;:13;:40;:::i;71181:159::-;71233:21;71257:17;;;:7;:17;;;;;71316:12;;;;;;71308:21;;;;;;;;71332:1;71308:25;71296:38;;;;;;;;71281:12;;;:53;;-1:-1:-1;;71281:53:0;;;;;;;;;;;;;;;;71181:159;;:::o;71404:415::-;71475:21;71499:17;;;:7;:17;;;;;;71525:149;71549:17;;;:24;71545:28;;71525:149;;;71623:1;71613:8;71594:72;71626:34;71648:8;71658:1;71626:21;:34::i;:::-;71662:3;71594:72;;;;;;;;;;;;;;;;71575:3;;71525:149;;;;71746:8;-1:-1:-1;;;;;;;;;;;71756:6:0;:16;;;71774:33;71798:8;71774:23;:33::i;:::-;71809:3;71730:83;;;;;;;;;;;;;;;;;71404:415;;:::o;73771:507::-;73915:21;73939:17;;;:7;:17;;;;;;;;73995:26;;;:15;;;:26;;;;;-1:-1:-1;;;;;74096:28:0;;;;:22;;;:28;;;;;;:40;;74129:6;74096:40;:32;:40;:::i;:::-;-1:-1:-1;;;;;74065:28:0;;;;;;:22;;;:28;;;;;:71;74170:24;;;;:36;;74199:6;74170:36;:28;:36;:::i;:::-;74143:24;;;;:63;;;;74238:22;;;:34;;74265:6;74238:34;:26;:34;:::i;:::-;74213:6;:22;;:59;;;;73771:507;;;;;;:::o;44933:158::-;44991:7;45024:1;45019;:6;;45011:49;;;;-1:-1:-1;;;45011:49:0;;;;;;;;;-1:-1:-1;45078:5:0;;;44933:158::o;45350:220::-;45408:7;45432:6;45428:20;;-1:-1:-1;45447:1:0;45440:8;;45428:20;45471:5;;;45475:1;45471;:5;:1;45495:5;;;;;:10;45487:56;;;;-1:-1:-1;;;45487:56:0;;;;;;;;44471:179;44529:7;44561:5;;;44585:6;;;;44577:46;;;;-1:-1:-1;;;44577:46:0;;;;;;;;72511:593;72592:21;72616:17;;;:7;:17;;;;;;72642:405;72666:17;;;:24;72662:28;;72642:405;;;72706:29;72738:18;;;:15;;;:18;;;;;72794:24;;;;:36;;72823:6;72794:36;:28;:36;:::i;:::-;72767:24;;;:63;:14;;;72862:20;:32;;72887:6;72862:32;:24;:32;:::i;:::-;72839:14;;;:55;73005:22;;;;:34;;73032:6;73005:34;:26;:34;:::i;:::-;72980:22;;;:59;-1:-1:-1;72692:3:0;;72642:405;;;-1:-1:-1;73072:14:0;;;;:26;;73091:6;73072:26;:18;:26;:::i;:::-;73055:14;;;;:43;-1:-1:-1;;72511:593:0:o;71872:581::-;71948:21;71972:17;;;:7;:17;;;;;;71998:398;72022:17;;;:24;72018:28;;71998:398;;;72062:29;72094:18;;;:15;;;:18;;;;;72150:24;;;;:36;;72179:6;72150:36;:28;:36;:::i;:::-;72123:24;;;:63;:14;;;72218:20;:32;;72243:6;72218:32;:24;:32;:::i;:::-;72195:14;;;:55;72354:22;;;;:34;;72381:6;72354:34;:26;:34;:::i;:::-;72329:22;;;:59;-1:-1:-1;72048:3:0;;71998:398;;;-1:-1:-1;72421:14:0;;;;:26;;72440:6;72421:26;:18;:26;:::i;73172:526::-;73318:21;73342:17;;;:7;:17;;;;;;;;73398:26;;;:15;;;:26;;;;;-1:-1:-1;;;;;73516:28:0;;;;:22;;;:28;;;;;;:40;;73549:6;73516:40;:32;:40;:::i;:::-;-1:-1:-1;;;;;73485:28:0;;;;;;:22;;;:28;;;;;:71;73590:24;;;;:36;;73619:6;73590:36;:28;:36;:::i;:::-;73563:24;;;;:63;;;;73658:22;;;:34;;73685:6;73658:34;:26;:34;:::i;79767:366::-;79865:21;79889:17;;;:7;:17;;;;;;;;;79955;;;:24;79941:39;;;;;;;;;;;;;;;;79840:16;;79889:17;;79840:16;;79941:39;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;79941:39:0;-1:-1:-1;79915:65:0;-1:-1:-1;79992:9:0;79987:119;80011:17;;;:24;80007:28;;79987:119;;;80063:18;;;;:15;;;:18;;;;;:35;;;80051:9;;:6;;80079:1;;80051:9;;;;;;;;;;;;;;;:47;80037:3;;79987:119;;;-1:-1:-1;80121:6:0;79767:366;-1:-1:-1;;;79767:366:0:o;49322:138::-;49384:7;49404:5;;49400:35;;49429:1;49424;49420;:5;49419:11;;;;;;49434:1;49418:17;49411:24;;;;49400:35;49453:1;49449;:5;;;;;;;49322:138;-1:-1:-1;;;49322:138:0:o;60558:2505::-;52805:17;;;;:7;:17;;;;;:35;60647:8;;52799:3;:41;:88;;;;-1:-1:-1;52871:16:0;52844:17;;;:7;:17;;;;;:23;;;;;:43;;;;;;;;;52799:88;52795:130;;;52898:19;52908:8;52898:9;:19::i;:::-;60670:8;60680:16:::1;::::0;53013:17:::1;::::0;;;:7:::1;:17;::::0;;;;:23:::1;;::::0;::::1;;:32;::::0;::::1;;;;;;;53005:41;;;::::0;::::1;;60708:21:::2;60732:17:::0;;;:7:::2;:17;::::0;;;;60766:9;60758:53:::2;;;;-1:-1:-1::0;;;60758:53:0::2;;;;;;;;;60820:23;60852:31;60886:33;60910:8;60886:23;:33::i;:::-;60852:67;;60926:32;60975:14;:21;60961:36;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;::::0;-1:-1;60961:36:0::2;-1:-1:-1::0;61039:16:0::2;::::0;::::2;::::0;60926:71;;-1:-1:-1;61004:18:0::2;::::0;61039:20;61035:784:::2;;61165:9;61160:183;61184:14;:21;61180:1;:25;61160:183;;;61223:21;61247:14;61262:1;61247:17;;;;;;;;;;;;;;61223:41;;61292:13;61279:10;:26;61275:58;;;61320:13;61307:26;;61275:58;-1:-1:-1::0;61207:3:0::2;;61160:183;;;-1:-1:-1::0;61358:9:0::2;61353:186;61377:14;:21;61373:1;:25;61353:186;;;61416:17;61467:10;61436:28;61446:14;61461:1;61446:17;;;;;;;;;;;;;;61436:5;:9;;:28;;;;:::i;:::-;:41;;;;;;::::0;-1:-1:-1;61509:20:0::2;:5:::0;61436:41;61509:20:::2;:9;:20;:::i;:::-;61488:15;61504:1;61488:18;;;;;;;;;::::0;;::::2;::::0;;;;;:41;-1:-1:-1;61400:3:0::2;;61353:186;;;;61597:10;61567:27;61577:6;:16;;;61567:5;:9;;:27;;;;:::i;:::-;:40;;;;;;61549:58;;61651:71;61669:8;61679:15;61696:25;61651:17;:71::i;:::-;;61035:784;;;61806:5;61788:23;;61035:784;61869:16;::::0;::::2;::::0;:37:::2;::::0;61890:15;61869:37:::2;:20;:37;:::i;:::-;61850:16;::::0;::::2;:56:::0;61973:10:::2;61950:34;::::0;;;:22:::2;::::0;::::2;:34;::::0;;;;;:55:::2;::::0;61989:15;61950:55:::2;:38;:55;:::i;:::-;61936:10;61913:34;::::0;;;:22:::2;::::0;::::2;:34;::::0;;;;:92;62014:34:::2;62032:8:::0;62042:5;62014:17:::2;:34::i;:::-;62122:9;62117:609;62141:15;:22;62137:1;:26;62117:609;;;62204:1;62183:15;62199:1;62183:18;;;;;;;;;;;;;;:22;62179:540;;;62241:22;::::0;;::::2;::::0;62218:20:::2;62298:18:::0;;;:15:::2;::::0;::::2;:18;::::0;;;;:35;;;;62399:18;;62344:74:::2;::::0;62374:10:::2;::::0;62386:8;;62314:1;;62399:15;;62314:1;;62399:18;::::2;;;;62344:74;62513:8:::0;62484:16:::2;62461:10;-1:-1:-1::0;;;;;62434:275:0::2;-1:-1:-1::0;;;;;;;;;;;62534:1:0::2;62548:15;62564:1;62548:18;;;;;;;;;;;;;;62579:85;62641:6;:22;;;62579:57;62617:15;62633:1;62617:18;;;;;;;62579:85;62695:3;62434:275;;;;;;;;;;;;;;;;;;62179:540;;;62165:3;;62117:609;;;;62734:22;62759:33;62783:8;62759:23;:33::i;:::-;62734:58:::0;-1:-1:-1;62799:22:0::2;50585:6;62824:35;62734:58:::0;62843:15;62824:35:::2;:18;:35;:::i;:::-;:41;;;;;;::::0;-1:-1:-1;62931:8:0;62904:25:::2;62892:10;-1:-1:-1::0;;;;;62877:104:0::2;-1:-1:-1::0;;;;;;;;;;;62941:1:0::2;62944:15;62961:14;62977:3;62877:104;;;;;;;;;;;;;;;;;;63009:8;-1:-1:-1::0;;;;;;;;;;;63019:6:0::2;:16;;;63037:14;63053:3;62993:64;;;;;;;;;;;;;;;;;53053:1;;;;;;;52931::::1;;60558:2505:::0;;;:::o;46048:153::-;46106:7;46138:1;46134;:5;46126:44;;;;-1:-1:-1;;;46126:44:0;;;;;;;;70449:681;70577:7;70617:17;;;:7;:17;;;;;70712:16;;;;70684:22;;;;70577:7;;70664:65;;:43;;:15;;:43;:19;:43;:::i;:65::-;70643:86;-1:-1:-1;70752:25:0;70742:6;:35;;;;;;;;;70738:387;;;70813:22;;;;:38;;70840:10;70813:38;:26;:38;:::i;:::-;70788:22;;;:63;70914:10;70894:31;;;;:19;;;:31;;;;;;:47;;70930:10;70894:47;:35;:47;:::i;:::-;70880:10;70860:31;;;;:19;;;:31;;;;;:81;70738:387;;;70989:22;;;;:38;;71016:10;70989:38;:26;:38;:::i;:::-;70964:22;;;:63;71090:10;71070:31;;;;:19;;;:31;;;;;;:47;;71106:10;71070:47;:35;:47;:::i;:::-;71056:10;71036:31;;;;:19;;;:31;;;;;:81;70738:387;70449:681;;;;;;;:::o;5:130:-1:-;72:20;;-1:-1;;;;;34731:54;;36732:35;;36722:2;;36781:1;;36771:12;284:442;;386:3;379:4;371:6;367:17;363:27;353:2;;-1:-1;;394:12;353:2;428:20;;-1:-1;;;;;33076:30;;;33073:2;;;-1:-1;;33109:12;33073:2;32742;32736:9;33182;33163:17;;-1:-1;;33159:33;32768:17;;33250:4;32768:17;32828:34;;;32864:22;;;32825:62;32822:2;;;-1:-1;;32890:12;32822:2;32742;32909:22;534:21;;;454:74;-1:-1;454:74;634:16;;;33250:4;634:16;631:25;-1:-1;628:2;;;669:1;;659:12;628:2;36105:6;33250:4;576:6;572:17;33250:4;610:5;606:16;36082:30;36161:1;33250:4;36152:6;610:5;36143:16;;36136:27;;;;346:380;;;;;1012:263;;1127:2;1115:9;1106:7;1102:23;1098:32;1095:2;;;-1:-1;;1133:12;1095:2;-1:-1;220:13;;1089:186;-1:-1;1089:186;1282:955;;;;;;1474:3;1462:9;1453:7;1449:23;1445:33;1442:2;;;-1:-1;;1481:12;1442:2;1526:31;;-1:-1;;;;;1566:30;;;1563:2;;;-1:-1;;1599:12;1563:2;1629:63;1684:7;1675:6;1664:9;1660:22;1629:63;;;1619:73;;1757:2;1746:9;1742:18;1729:32;1715:46;;1577:18;1773:6;1770:30;1767:2;;;-1:-1;;1803:12;1767:2;;1833:63;1888:7;1879:6;1868:9;1864:22;1833:63;;;1823:73;;;1933:2;1976:9;1972:22;801:20;1941:63;;2059:53;2104:7;2041:2;2084:9;2080:22;2059:53;;;1436:801;;;;-1:-1;1436:801;;2149:3;2189:22;801:20;;1436:801;-1:-1;;1436:801;2244:241;;2348:2;2336:9;2327:7;2323:23;2319:32;2316:2;;;-1:-1;;2354:12;2316:2;-1:-1;801:20;;2310:175;-1:-1;2310:175;2762:366;;;2883:2;2871:9;2862:7;2858:23;2854:32;2851:2;;;-1:-1;;2889:12;2851:2;814:6;801:20;2941:63;;3059:53;3104:7;3041:2;3084:9;3080:22;3059:53;;;3049:63;;2845:283;;;;;;3135:366;;;3256:2;3244:9;3235:7;3231:23;3227:32;3224:2;;;-1:-1;;3262:12;3224:2;-1:-1;;801:20;;;3414:2;3453:22;;;801:20;;-1:-1;3218:283;3508:491;;;;3646:2;3634:9;3625:7;3621:23;3617:32;3614:2;;;-1:-1;;3652:12;3614:2;-1:-1;;801:20;;;3804:2;3843:22;;801:20;;-1:-1;3912:2;3951:22;;;801:20;;3608:391;-1:-1;3608:391;4006:617;;;;;4161:3;4149:9;4140:7;4136:23;4132:33;4129:2;;;-1:-1;;4168:12;4129:2;-1:-1;;801:20;;;4320:2;4359:22;;801:20;;-1:-1;4428:2;4467:22;;801:20;;4536:2;4575:22;801:20;;-1:-1;4123:500;-1:-1;4123:500;6776:347;;6921:5;33533:12;33949:6;33944:3;33937:19;-1:-1;36250:101;36264:6;36261:1;36258:13;36250:101;;;33986:4;36331:11;;;;;36325:18;36312:11;;;;;36305:39;36279:10;36250:101;;;36366:6;36363:1;36360:13;36357:2;;;-1:-1;33986:4;36422:6;33981:3;36413:16;;36406:27;36357:2;-1:-1;33182:9;36522:14;-1:-1;;36518:28;7079:39;;;;33986:4;7079:39;;6868:255;-1:-1;;6868:255;15829:213;-1:-1;;;;;34731:54;;;;5032:37;;15947:2;15932:18;;15918:124;16285:361;16453:2;16467:47;;;33533:12;;16438:18;;;33937:19;;;16285:361;;16453:2;33387:14;;;;33977;;;;16285:361;5520:260;5545:6;5542:1;5539:13;5520:260;;;5606:13;;5992:37;;33792:14;;;;4784;;;;5567:1;5560:9;5520:260;;;-1:-1;16520:116;;16424:222;-1:-1;;;;;;16424:222;16653:201;34341:13;;34334:21;5875:34;;16765:2;16750:18;;16736:118;16861:611;34341:13;;34334:21;5875:34;;34341:13;;34334:21;17220:2;17205:18;;5875:34;34341:13;;34334:21;17297:2;17282:18;;5875:34;34341:13;34334:21;17374:2;17359:18;;5875:34;17457:3;17442:19;;5992:37;17067:3;17052:19;;17038:434;17479:213;5992:37;;;17597:2;17582:18;;17568:124;17945:795;18215:3;18200:19;;36644:1;36634:12;;36624:2;;36650:9;36624:2;6285:64;;;18394:2;18379:18;;5992:37;;;;18477:2;18462:18;;5992:37;;;;18560:2;18545:18;;5992:37;;;;18643:3;18628:19;;5992:37;18725:3;18710:19;;;5992:37;18186:554;;18963:563;6557:58;;;19346:2;19331:18;;5992:37;;;;19429:2;19414:18;;5992:37;19512:2;19497:18;;5992:37;19173:3;19158:19;;19144:382;19533:1011;;35621:24;6564:3;6557:58;19859:3;19986:2;19975:9;19971:18;19964:48;20026:78;19859:3;19848:9;19844:19;20090:6;20026:78;;;-1:-1;;;;;34731:54;;;;20183:2;20168:18;;5032:37;-1:-1;34948:10;34937:22;;;20264:2;20249:18;;15781:36;34937:22;;;;20345:3;20330:19;;15781:36;34742:42;20422:19;;6557:58;20529:3;20514:19;6557:58;20018:86;19830:714;-1:-1;;19830:714;20551:407;20742:2;20756:47;;;7355:2;20727:18;;;33937:19;-1:-1;;;33977:14;;;7371:50;7440:12;;;20713:245;20965:407;21156:2;21170:47;;;7691:2;21141:18;;;33937:19;-1:-1;;;33977:14;;;7707:44;7770:12;;;21127:245;21379:407;21570:2;21584:47;;;8021:2;21555:18;;;33937:19;8057:34;33977:14;;;8037:55;-1:-1;;;8112:12;;;8105:25;8149:12;;;21541:245;21793:407;21984:2;21998:47;;;8400:2;21969:18;;;33937:19;-1:-1;;;33977:14;;;8416:50;8485:12;;;21955:245;22207:407;22398:2;22412:47;;;8736:2;22383:18;;;33937:19;8772:34;33977:14;;;8752:55;-1:-1;;;8827:12;;;8820:34;8873:12;;;22369:245;22621:407;22812:2;22826:47;;;9124:2;22797:18;;;33937:19;9160:32;33977:14;;;9140:53;9212:12;;;22783:245;23035:407;23226:2;23240:47;;;9463:2;23211:18;;;33937:19;9499:33;33977:14;;;9479:54;9552:12;;;23197:245;23449:407;23640:2;23654:47;;;9803:2;23625:18;;;33937:19;9839:32;33977:14;;;9819:53;9891:12;;;23611:245;23863:407;24054:2;24068:47;;;10142:2;24039:18;;;33937:19;10178:34;33977:14;;;10158:55;-1:-1;;;10233:12;;;10226:27;10272:12;;;24025:245;24277:407;24468:2;24482:47;;;10523:2;24453:18;;;33937:19;-1:-1;;;33977:14;;;10539:49;10607:12;;;24439:245;24691:407;24882:2;24896:47;;;10858:2;24867:18;;;33937:19;10894:34;33977:14;;;10874:55;-1:-1;;;10949:12;;;10942:34;10995:12;;;24853:245;25105:407;25296:2;25310:47;;;11246:2;25281:18;;;33937:19;11282:34;33977:14;;;11262:55;-1:-1;;;11337:12;;;11330:38;11387:12;;;25267:245;25519:407;25710:2;25724:47;;;11638:2;25695:18;;;33937:19;11674:34;33977:14;;;11654:55;-1:-1;;;11729:12;;;11722:25;11766:12;;;25681:245;25933:407;26124:2;26138:47;;;12017:2;26109:18;;;33937:19;12053:34;33977:14;;;12033:55;-1:-1;;;12108:12;;;12101:34;12154:12;;;26095:245;26347:407;26538:2;26552:47;;;12405:2;26523:18;;;33937:19;12441:34;33977:14;;;12421:55;-1:-1;;;12496:12;;;12489:31;12539:12;;;26509:245;26761:407;26952:2;26966:47;;;12790:2;26937:18;;;33937:19;12826:34;33977:14;;;12806:55;-1:-1;;;12881:12;;;12874:27;12920:12;;;26923:245;27175:407;27366:2;27380:47;;;13171:2;27351:18;;;33937:19;13207:34;33977:14;;;13187:55;-1:-1;;;13262:12;;;13255:27;13301:12;;;27337:245;27589:407;27780:2;27794:47;;;13552:2;27765:18;;;33937:19;13588:34;33977:14;;;13568:55;-1:-1;;;13643:12;;;13636:25;13680:12;;;27751:245;28003:407;28194:2;28208:47;;;13931:2;28179:18;;;33937:19;13967:34;33977:14;;;13947:55;-1:-1;;;14022:12;;;14015:30;14064:12;;;28165:245;28831:407;29022:2;29036:47;;;14650:2;29007:18;;;33937:19;14686:32;33977:14;;;14666:53;14738:12;;;28993:245;29245:407;29436:2;29450:47;;;14989:2;29421:18;;;33937:19;-1:-1;;;33977:14;;;15005:51;15075:12;;;29407:245;29659:407;29850:2;29864:47;;;15326:2;29835:18;;;33937:19;15362:34;33977:14;;;15342:55;-1:-1;;;15417:12;;;15410:27;15456:12;;;29821:245;30293:435;5992:37;;;30631:2;30616:18;;5992:37;;;;30714:2;30699:18;;5992:37;30467:2;30452:18;;30438:290;30735:611;;6022:5;5999:3;5992:37;30949:2;31067;31056:9;31052:18;31045:48;31107:78;30949:2;30938:9;30934:18;31171:6;31107:78;;;31233:9;31227:4;31223:20;31218:2;31207:9;31203:18;31196:48;31258:78;31331:4;31322:6;31258:78;;;31250:86;30920:426;-1:-1;;;;;;30920:426;31353:324;5992:37;;;31663:2;31648:18;;5992:37;31499:2;31484:18;;31470:207

Swarm Source

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