Overview
GLMR Balance
GLMR Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 249 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim Achievemen... | 4804217 | 534 days ago | IN | 0 GLMR | 0.02916996 | ||||
Claim Achievemen... | 3715437 | 687 days ago | IN | 0 GLMR | 0.03169954 | ||||
Claim Achievemen... | 2830306 | 815 days ago | IN | 0 GLMR | 0.02932432 | ||||
Claim Achievemen... | 2613479 | 845 days ago | IN | 0 GLMR | 0.03713841 | ||||
Claim Achievemen... | 2593528 | 848 days ago | IN | 0 GLMR | 0.02707991 | ||||
Claim Achievemen... | 2593523 | 848 days ago | IN | 0 GLMR | 0.02295036 | ||||
Claim Achievemen... | 2592650 | 848 days ago | IN | 0 GLMR | 0.04104592 | ||||
Claim Achievemen... | 2590103 | 849 days ago | IN | 0 GLMR | 0.03713841 | ||||
Claim Achievemen... | 2554832 | 854 days ago | IN | 0 GLMR | 0.02317648 | ||||
Claim Achievemen... | 2551741 | 854 days ago | IN | 0 GLMR | 0.03713841 | ||||
Claim Achievemen... | 2549518 | 854 days ago | IN | 0 GLMR | 0.02932432 | ||||
Claim Achievemen... | 2549516 | 854 days ago | IN | 0 GLMR | 0.02737098 | ||||
Claim Achievemen... | 2549514 | 854 days ago | IN | 0 GLMR | 0.02317648 | ||||
Claim Achievemen... | 2545368 | 855 days ago | IN | 0 GLMR | 0.05920762 | ||||
Claim Achievemen... | 2544419 | 855 days ago | IN | 0 GLMR | 0.04495393 | ||||
Claim Achievemen... | 2544416 | 855 days ago | IN | 0 GLMR | 0.05136459 | ||||
Claim Achievemen... | 2542805 | 855 days ago | IN | 0 GLMR | 0.0708768 | ||||
Claim Achievemen... | 2542799 | 855 days ago | IN | 0 GLMR | 0.05277089 | ||||
Claim Achievemen... | 2542776 | 855 days ago | IN | 0 GLMR | 0.02932432 | ||||
Claim Achievemen... | 2542776 | 855 days ago | IN | 0 GLMR | 0.042964 | ||||
Claim Achievemen... | 2540688 | 856 days ago | IN | 0 GLMR | 0.05277089 | ||||
Claim Achievemen... | 2536428 | 856 days ago | IN | 0 GLMR | 0.03323111 | ||||
Claim Achievemen... | 2533777 | 857 days ago | IN | 0 GLMR | 0.03713841 | ||||
Claim Achievemen... | 2533773 | 857 days ago | IN | 0 GLMR | 0.04159398 | ||||
Claim Achievemen... | 2532032 | 857 days ago | IN | 0 GLMR | 0.04495393 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Achievements
Compiler Version
v0.6.2+commit.bacdbe57
Contract Source Code (Solidity)
/** *Submitted for verification at moonbeam.moonscan.io on 2022-11-21 */ // 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 IERC20R { 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 { IERC20R 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(IERC20R _token) public { require(token == IERC20R(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/PredictionMarketV2.sol pragma solidity ^0.6.0; // 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 PredictionMarketV2 { 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; IERC20R token; // ERC20 token market will use for trading } 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 } struct CreateMarketArgs { uint256 value; uint256 closesAt; uint256 outcomes; IERC20R token; uint256[] distribution; string question; string image; address arbitrator; } uint256[] marketIds; mapping(uint256 => Market) markets; uint256 public marketIndex; // governance uint256 public fee; // fee % taken from every transaction // realitio configs address public realitioAddress; uint256 public realitioTimeout; // market creation IERC20R public requiredBalanceToken; // token used for rewards / market creation uint256 public requiredBalance; // required balance for market creation // ------ Modifiers ------ modifier isMarket(uint256 marketId) { require(marketId < marketIndex, "Market not found"); _; } 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, "Market in incorrect state"); _; } modifier notAtState(uint256 marketId, MarketState state) { require(markets[marketId].state != state, "Market in incorrect state"); _; } modifier transitionNext(uint256 marketId) { _; nextState(marketId); } modifier mustHoldRequiredBalance() { require( requiredBalance == 0 || requiredBalanceToken.balanceOf(msg.sender) >= requiredBalance, "msg.sender must hold minimum erc20 balance" ); _; } // ------ Modifiers End ------ /// @dev protocol is immutable and has no ownership constructor( uint256 _fee, IERC20R _requiredBalanceToken, uint256 _requiredBalance, address _realitioAddress, uint256 _realitioTimeout ) public { require(_realitioAddress != address(0), "_realitioAddress is address 0"); require(_realitioTimeout > 0, "timeout must be positive"); fee = _fee; requiredBalanceToken = _requiredBalanceToken; 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(CreateMarketArgs calldata args) external mustHoldRequiredBalance returns (uint256) { uint256 marketId = marketIndex; marketIds.push(marketId); Market storage market = markets[marketId]; require(args.value > 0, "stake needs to be > 0"); require(args.closesAt > now, "market must resolve after the current date"); require(args.arbitrator != address(0), "invalid arbitrator address"); require(args.outcomes <= 2 ** 8, "number of outcomes has to be less or equal than 256"); market.token = args.token; market.closesAtTimestamp = args.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 < args.outcomes; i++) { market.outcomeIds.push(i); MarketOutcome storage outcome = market.outcomes[i]; outcome.marketId = marketId; outcome.id = i; } // creating question in realitio RealitioERC20(realitioAddress).askQuestionERC20( 2, args.question, args.arbitrator, uint32(realitioTimeout), uint32(args.closesAt), 0, 0 ); addLiquidity(marketId, args.value, args.distribution); // emiting initial price events emitMarketOutcomePriceEvents(marketId); emit MarketCreated(msg.sender, marketId, args.outcomes, args.question, args.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, uint256 value ) external timeTransitions(marketId) atState(marketId, MarketState.open) { Market storage market = markets[marketId]; uint256 shares = calcBuyAmount(value, marketId, outcomeId); require(shares >= minOutcomeSharesToBuy, "minimum buy amount not reached"); require(shares > 0, "shares amount is 0"); // 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); require(market.token.transferFrom(msg.sender, address(this), value), "erc20 transfer failed"); 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 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(shares > 0, "shares amount is 0"); 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 require(market.token.transfer(msg.sender, value), "erc20 transfer failed"); emit MarketActionTx(msg.sender, MarketAction.sell, marketId, outcomeId, shares, value, now); emitMarketOutcomePriceEvents(marketId); } /// @dev Adds liquidity to a market - external function addLiquidity( uint256 marketId, uint256 value, uint256[] memory distribution ) public 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) { require(distribution.length == 0, "market already has liquidity, can't distribute liquidity"); // 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 if (distribution.length > 0) { require(distribution.length == outcomesShares.length, "weight distribution length does not match"); uint256 maxHint = 0; for (uint256 i = 0; i < distribution.length; i++) { uint256 hint = distribution[i]; if (maxHint < hint) maxHint = hint; } for (uint256 i = 0; i < distribution.length; i++) { uint256 remaining = value.mul(distribution[i]) / maxHint; require(remaining > 0, "must hint a valid distribution"); sendBackAmounts[i] = value.sub(remaining); } } // funding market with total liquidity amount 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; require(market.token.transferFrom(msg.sender, address(this), value), "erc20 transfer failed"); 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 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 require(market.token.transfer(msg.sender, liquidityAmount), "erc20 transfer failed"); 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) external 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) external 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 ); require(market.token.transfer(msg.sender, value), "erc20 transfer failed"); } /// @dev Allows holders of voided outcome shares to claim balance back. function claimVoidedOutcomeShares(uint256 marketId, uint256 outcomeId) external 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 ); require(market.token.transfer(msg.sender, value), "erc20 transfer failed"); } /// @dev Allows liquidity providers to claim earnings from liquidity providing. function claimLiquidity(uint256 marketId) external 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 ); require(market.token.transfer(msg.sender, value), "erc20 transfer failed"); } /// @dev Allows liquidity providers to claim their fees share from fees pool function claimFees(uint256 marketId) public { 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); require(market.token.transfer(msg.sender, claimableFees), "erc20 transfer failed"); } 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) external view returns ( uint256, uint256[] memory ) { Market storage market = markets[marketId]; uint256[] memory outcomeShares = new uint256[](market.outcomeIds.length); for (uint256 i = 0; i < market.outcomeIds.length; i++) { outcomeShares[i] = market.outcomes[i].shares.holders[user]; } return ( market.liquidityShares[user], outcomeShares ); } function getUserClaimStatus(uint256 marketId, address user) external 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) external 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); // No fees left to claim if (market.fees.claimed[user] > rawAmount) return 0; return rawAmount.sub(market.fees.claimed[user]); } function getMarkets() external view returns (uint256[] memory) { return marketIds; } function getMarketData(uint256 marketId) external 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) external 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) external view returns (bytes32) { Market storage market = markets[marketId]; return (market.resolution.questionId); } function getMarketPrices(uint256 marketId) external view returns ( uint256, uint256[] memory ) { Market storage market = markets[marketId]; uint256[] memory prices = new uint256[](market.outcomeIds.length); for (uint256 i = 0; i < market.outcomeIds.length; i++) { prices[i] = getMarketOutcomePrice(marketId, i); } return (getMarketLiquidityPrice(marketId), prices); } function getMarketLiquidityPrice(uint256 marketId) public view returns (uint256) { Market storage market = markets[marketId]; if (market.state == MarketState.resolved && !isMarketVoided(marketId)) { // resolved market, outcome prices are 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 = product(every outcome shares) / sum (every outcomeOddsWeight) * # outcomes / liquidity shares uint256 marketSharesProduct = ONE; uint256 marketSharesSum = 0; for (uint256 i = 0; i < market.outcomeIds.length; i++) { MarketOutcome storage outcome = market.outcomes[i]; marketSharesProduct = marketSharesProduct.mul(outcome.shares.available).div(ONE); marketSharesSum = marketSharesSum.add(getOutcomeOddsWeight(marketId, i)); } return marketSharesProduct.mul(market.outcomeIds.length).mul(ONE).div(marketSharesSum).mul(ONE).div(market.liquidity); } 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) external view returns (uint256[] memory) { Market storage market = markets[marketId]; return market.outcomeIds; } function getOutcomeOddsWeight(uint256 marketId, uint256 outcomeId) public view returns (uint256) { Market storage market = markets[marketId]; uint256 productWeight = ONE; for (uint256 i = 0; i < market.outcomeIds.length; i++) { if (i == outcomeId) continue; productWeight = productWeight.mul(market.outcomes[i].shares.available).div(ONE); } return productWeight; } function getMarketOutcomePrice(uint256 marketId, uint256 outcomeId) public view returns (uint256) { Market storage market = markets[marketId]; if (market.state == MarketState.resolved && !isMarketVoided(marketId)) { // resolved market, price is either 0 or 1 return outcomeId == market.resolution.outcomeId ? ONE : 0; } uint256 sumOutcomeOddsWeight = 0; for (uint256 i = 0; i < market.outcomeIds.length; i++) { sumOutcomeOddsWeight = sumOutcomeOddsWeight.add(getOutcomeOddsWeight(marketId, i)); } // outcome price = outcomeOddsWeight / sum(every outcomeOddsWeight) return getOutcomeOddsWeight(marketId, outcomeId).mul(ONE).div(sumOutcomeOddsWeight); } function getMarketOutcomeData(uint256 marketId, uint256 outcomeId) external 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; } } // File: @openzeppelin/contracts/utils/EnumerableSet.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } // File: @openzeppelin/contracts/utils/Address.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File: @openzeppelin/contracts/utils/Context.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } // File: @openzeppelin/contracts/access/AccessControl.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context { using EnumerableSet for EnumerableSet.AddressSet; using Address for address; struct RoleData { EnumerableSet.AddressSet members; bytes32 adminRole; } mapping (bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual { require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { emit RoleAdminChanged(role, _roles[role].adminRole, adminRole); _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (_roles[role].members.add(account)) { emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (_roles[role].members.remove(account)) { emit RoleRevoked(role, account, _msgSender()); } } } // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts/token/ERC20/ERC20.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } // File: @openzeppelin/contracts/token/ERC20/ERC20Burnable.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { using SafeMath for uint256; /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance"); _approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } } // File: @openzeppelin/contracts/utils/Pausable.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor () internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File: @openzeppelin/contracts/token/ERC20/ERC20Pausable.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev ERC20 token with pausable token transfers, minting and burning. * * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. */ abstract contract ERC20Pausable is ERC20, Pausable { /** * @dev See {ERC20-_beforeTokenTransfer}. * * Requirements: * * - the contract must not be paused. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { super._beforeTokenTransfer(from, to, amount); require(!paused(), "ERC20Pausable: token transfer while paused"); } } // File: @openzeppelin/contracts/presets/ERC20PresetMinterPauser.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev {ERC20} token, including: * * - ability for holders to burn (destroy) their tokens * - a minter role that allows for token minting (creation) * - a pauser role that allows to stop all token transfers * * This contract uses {AccessControl} to lock permissioned functions using the * different roles - head to its documentation for details. * * The account that deploys the contract will be granted the minter and pauser * roles, as well as the default admin role, which will let it grant both minter * and pauser roles to other accounts. */ contract ERC20PresetMinterPauser is Context, AccessControl, ERC20Burnable, ERC20Pausable { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); /** * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the * account that deploys the contract. * * See {ERC20-constructor}. */ constructor(string memory name, string memory symbol) public ERC20(name, symbol) { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setupRole(MINTER_ROLE, _msgSender()); _setupRole(PAUSER_ROLE, _msgSender()); } /** * @dev Creates `amount` new tokens for `to`. * * See {ERC20-_mint}. * * Requirements: * * - the caller must have the `MINTER_ROLE`. */ function mint(address to, uint256 amount) public virtual { require(hasRole(MINTER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have minter role to mint"); _mint(to, amount); } /** * @dev Pauses all token transfers. * * See {ERC20Pausable} and {Pausable-_pause}. * * Requirements: * * - the caller must have the `PAUSER_ROLE`. */ function pause() public virtual { require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to pause"); _pause(); } /** * @dev Unpauses all token transfers. * * See {ERC20Pausable} and {Pausable-_unpause}. * * Requirements: * * - the caller must have the `PAUSER_ROLE`. */ function unpause() public virtual { require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to unpause"); _unpause(); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override(ERC20, ERC20Pausable) { super._beforeTokenTransfer(from, to, amount); } } // File: contracts/FantasyERC20.sol pragma solidity ^0.6.0; contract FantasyERC20 is ERC20PresetMinterPauser { event TokensClaimed( address indexed user, uint256 amount, uint256 timestamp ); mapping(address => bool) usersClaimed; address public tokenManager; uint256 public tokenAmountToClaim; // ------ Modifiers ------ modifier shouldNotHaveClaimedYet() { require(usersClaimed[msg.sender] == false, "FantasyERC20: address already claimed the tokens"); _; } constructor( string memory name, string memory symbol, uint256 _tokenAmountToClaim, address _tokenManager ) public ERC20PresetMinterPauser(name, symbol) { tokenAmountToClaim = _tokenAmountToClaim; tokenManager = _tokenManager; } /// @dev Validates if the transfer is from or to the tokenManager, blocking it otherwise function _transfer( address from, address to, uint256 amount ) internal override { require(from == tokenManager || to == tokenManager, "FantasyERC20: token transfer not allowed between the addresses"); super._transfer(from, to, amount); } /// @dev Allows user to claim the amount of tokens by minting them function claimTokens() shouldNotHaveClaimedYet public { _mint(msg.sender, tokenAmountToClaim); usersClaimed[msg.sender] = true; emit TokensClaimed(msg.sender, tokenAmountToClaim, now); } /// @dev Allows user to approve and claim the amount of tokens by minting them function claimAndApproveTokens() shouldNotHaveClaimedYet external { claimTokens(); approve(tokenManager, 2 ** 128 - 1); } /// @dev Returns if the address has already claimed or not the tokens function hasUserClaimedTokens(address user) external view returns (bool) { return usersClaimed[user]; } } // File: @openzeppelin/contracts/access/Ownable.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } // File: contracts/PredictionMarketResolver.sol pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; // openzeppelin imports contract PredictionMarketResolver is Ownable { using SafeMath for uint256; event MarketResolved( address indexed user, uint256 indexed marketId, uint256 outcomeId, uint256 timestamp ); event MarketClaimed( address indexed user, uint256 indexed marketId, uint256 outcomeId, uint256 shares, uint256 timestamp ); struct MarketResolution { bool resolved; uint256 outcomeId; } mapping(uint256 => mapping(address => bool)) public claims; mapping(uint256 => MarketResolution) markets; FantasyERC20 public token; PredictionMarketV2 public predictionMarket; // ------ Modifiers ------ modifier marketIsResolved(uint256 marketId) { require(markets[marketId].resolved, "Market is not resolved"); _; } // ------ Modifiers End ------ // ------ Admin ------ function setToken(FantasyERC20 _token) external onlyOwner { token = _token; } function setPredictionMarket(PredictionMarketV2 _predictionMarket) external onlyOwner { predictionMarket = _predictionMarket; } function resolveMarket(uint256 marketId, uint256 outcomeId) external onlyOwner { markets[marketId] = MarketResolution(true, outcomeId); emit MarketResolved(msg.sender, marketId, outcomeId, block.timestamp); } // ------ Admin End ------ function getMarketResolution(uint256 marketId) external view returns (MarketResolution memory) { return markets[marketId]; } function hasUserClaimedMarket(uint256 marketId, address user) external view returns (bool) { return claims[marketId][user]; } function getUserMarketShares(uint256 marketId, address user) public view returns (uint256[] memory) { uint[] memory shares; // fetching user shares from predictionMarket (, shares) = predictionMarket.getUserMarketShares(marketId, user); return shares; } function claim(uint256 marketId, address user) marketIsResolved(marketId) public { require(!claims[marketId][user], "Already claimed"); uint256 outcomeId = markets[marketId].outcomeId; uint[] memory shares; // fetching user shares from predictionMarket (, shares) = predictionMarket.getUserMarketShares(marketId, user); // calculating user winnings require(shares[outcomeId] > 0, "User has no winning shares"); claims[marketId][user] = true; // minting tokens for user token.mint(user, shares[outcomeId]); emit MarketClaimed(user, marketId, outcomeId, shares[outcomeId], block.timestamp); } function claimMultiple(uint256 marketId, address[] calldata users) external { for (uint256 i = 0; i < users.length; i++) { claim(marketId, users[i]); } } } // File: @openzeppelin/contracts/introspection/IERC165.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } // File: @openzeppelin/contracts/token/ERC721/IERC721.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; } // File: @openzeppelin/contracts/token/ERC721/IERC721Metadata.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); } // File: @openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); } // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); } // File: @openzeppelin/contracts/introspection/ERC165.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } // File: @openzeppelin/contracts/utils/EnumerableMap.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are * supported. */ library EnumerableMap { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Map type with // bytes32 keys and values. // The Map implementation uses private functions, and user-facing // implementations (such as Uint256ToAddressMap) are just wrappers around // the underlying Map. // This means that we can only create new EnumerableMaps for types that fit // in bytes32. struct MapEntry { bytes32 _key; bytes32 _value; } struct Map { // Storage of map keys and values MapEntry[] _entries; // Position of the entry defined by a key in the `entries` array, plus 1 // because index 0 means a key is not in the map. mapping (bytes32 => uint256) _indexes; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) { // Equivalent to !contains(map, key) map._entries.push(MapEntry({ _key: key, _value: value })); // The entry is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value map._indexes[key] = map._entries.length; return true; } else { map._entries[keyIndex - 1]._value = value; return false; } } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function _remove(Map storage map, bytes32 key) private returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map._indexes[key]; if (keyIndex != 0) { // Equivalent to contains(map, key) // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one // in the array, and then remove the last entry (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = keyIndex - 1; uint256 lastIndex = map._entries.length - 1; // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. MapEntry storage lastEntry = map._entries[lastIndex]; // Move the last entry to the index where the entry to delete is map._entries[toDeleteIndex] = lastEntry; // Update the index for the moved entry map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved entry was stored map._entries.pop(); // Delete the index for the deleted slot delete map._indexes[key]; return true; } else { return false; } } /** * @dev Returns true if the key is in the map. O(1). */ function _contains(Map storage map, bytes32 key) private view returns (bool) { return map._indexes[key] != 0; } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function _length(Map storage map) private view returns (uint256) { return map._entries.length; } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) { require(map._entries.length > index, "EnumerableMap: index out of bounds"); MapEntry storage entry = map._entries[index]; return (entry._key, entry._value); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. */ function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) { uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key) return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function _get(Map storage map, bytes32 key) private view returns (bytes32) { uint256 keyIndex = map._indexes[key]; require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key) return map._entries[keyIndex - 1]._value; // All indexes are 1-based } /** * @dev Same as {_get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {_tryGet}. */ function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) { uint256 keyIndex = map._indexes[key]; require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key) return map._entries[keyIndex - 1]._value; // All indexes are 1-based } // UintToAddressMap struct UintToAddressMap { Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return _remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return _contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return _length(map._inner); } /** * @dev Returns the element stored at position `index` in the set. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = _at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } /** * @dev Tries to returns the value associated with `key`. O(1). * Does not revert if `key` is not in the map. * * _Available since v3.4._ */ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key)); return (success, address(uint160(uint256(value)))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint160(uint256(_get(map._inner, bytes32(key))))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryGet}. */ function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) { return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))); } } // File: @openzeppelin/contracts/utils/Strings.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev String operations. */ library Strings { /** * @dev Converts a `uint256` to its ASCII `string` representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); uint256 index = digits - 1; temp = value; while (temp != 0) { buffer[index--] = bytes1(uint8(48 + temp % 10)); temp /= 10; } return string(buffer); } } // File: @openzeppelin/contracts/token/ERC721/ERC721.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { using SafeMath for uint256; using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableMap for EnumerableMap.UintToAddressMap; using Strings for uint256; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from holder address to their (enumerable) set of owned tokens mapping (address => EnumerableSet.UintSet) private _holderTokens; // Enumerable mapping from token ids to their owners EnumerableMap.UintToAddressMap private _tokenOwners; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; // Token name string private _name; // Token symbol string private _symbol; // Optional mapping for token URIs mapping (uint256 => string) private _tokenURIs; // Base URI string private _baseURI; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; /* * bytes4(keccak256('name()')) == 0x06fdde03 * bytes4(keccak256('symbol()')) == 0x95d89b41 * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd * * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f */ bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; /* * bytes4(keccak256('totalSupply()')) == 0x18160ddd * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 * * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 */ bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); _registerInterface(_INTERFACE_ID_ERC721_METADATA); _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _holderTokens[owner].length(); } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token"); } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory _tokenURI = _tokenURIs[tokenId]; string memory base = baseURI(); // If there is no base URI, return the token URI. if (bytes(base).length == 0) { return _tokenURI; } // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). if (bytes(_tokenURI).length > 0) { return string(abi.encodePacked(base, _tokenURI)); } // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI. return string(abi.encodePacked(base, tokenId.toString())); } /** * @dev Returns the base URI set via {_setBaseURI}. This will be * automatically added as a prefix in {tokenURI} to each token's URI, or * to the token ID if no specific URI is set for that token ID. */ function baseURI() public view virtual returns (string memory) { return _baseURI; } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { return _holderTokens[owner].at(index); } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds return _tokenOwners.length(); } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual override returns (uint256) { (uint256 tokenId, ) = _tokenOwners.at(index); return tokenId; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { require(operator != _msgSender(), "ERC721: approve to caller"); _operatorApprovals[_msgSender()][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _tokenOwners.contains(tokenId); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: d* * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { _mint(to, tokenId); require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _holderTokens[to].add(tokenId); _tokenOwners.set(tokenId, to); emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); // internal owner _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); // Clear metadata (if any) if (bytes(_tokenURIs[tokenId]).length != 0) { delete _tokenURIs[tokenId]; } _holderTokens[owner].remove(tokenId); _tokenOwners.remove(tokenId); emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _holderTokens[from].remove(tokenId); _holderTokens[to].add(tokenId); _tokenOwners.set(tokenId, to); emit Transfer(from, to, tokenId); } /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); _tokenURIs[tokenId] = _tokenURI; } /** * @dev Internal function to set the base URI for all token IDs. It is * automatically added as a prefix to the value returned in {tokenURI}, * or to the token ID if {tokenURI} is empty. */ function _setBaseURI(string memory baseURI_) internal virtual { _baseURI = baseURI_; } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) private returns (bool) { if (!to.isContract()) { return true; } bytes memory returndata = to.functionCall(abi.encodeWithSelector( IERC721Receiver(to).onERC721Received.selector, _msgSender(), from, tokenId, _data ), "ERC721: transfer to non ERC721Receiver implementer"); bytes4 retval = abi.decode(returndata, (bytes4)); return (retval == _ERC721_RECEIVED); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } } // File: @openzeppelin/contracts/utils/Counters.sol // SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: contracts/Achievements.sol pragma solidity ^0.6.0; // openzeppelin imports /// @title Prediction Market Achievements Contract contract Achievements is ERC721 { using Counters for Counters.Counter; Counters.Counter private _tokenIds; /// @dev protocol is immutable and has no ownership RealitioERC20 public realitioERC20; PredictionMarketV2 public predictionMarket; PredictionMarketResolver public predictionMarketResolver; event LogNewAchievement(uint256 indexed achievementId, address indexed user, string content); // Buy: Claim through market[x].outcome[y].shares.holders[msg.sender] > 0 // AddLiquidity: Claim through market[x].liquidityShares[msg.sender] > 0 // CreateMarket: RealitioERC20 question arbitrator == msg.sender // ClaimWinnings: Claim through market[x].outcome[y].shares.holders[msg.sender] > 0 && y == market.resolution.outcomeId // Bond: Use RealitioERC20 historyHashes logic value and ensure addrs.includes(msg.sender) enum Action { Buy, AddLiquidity, Bond, ClaimWinnings, CreateMarket } struct Achievement { Action action; uint256 occurrences; mapping(address => bool) claims; } uint256 public achievementIndex = 0; mapping(uint256 => Achievement) public achievements; mapping(uint256 => uint256) public tokens; // tokenId => achievementId constructor(string memory token, string memory ticker) public ERC721(token, ticker) {} function setContracts( PredictionMarketV2 _predictionMarket, PredictionMarketResolver _predictionMarketResolver, RealitioERC20 _realitioERC20 ) public { require(address(predictionMarket) == address(0), "predictionMarket can only be initialized once"); require(address(predictionMarketResolver) == address(0), "predictionMarket can only be initialized once"); require(address(realitioERC20) == address(0), "realitioERC20 can only be initialized once"); require(address(_predictionMarket) != address(0), "_predictionMarket address is 0"); require(address(_predictionMarketResolver) != address(0), "_predictionMarketResolver address is 0"); require(address(_realitioERC20) != address(0), "_realitioERC20 address is 0"); predictionMarket = _predictionMarket; predictionMarketResolver = _predictionMarketResolver; realitioERC20 = _realitioERC20; } function setBaseURI(string memory _baseURI) public { require(bytes(baseURI()).length == 0, "baseURI can only be initialized once"); _setBaseURI(_baseURI); } function createAchievement( Action action, uint256 occurrences, string memory content ) public returns (uint256) { require(occurrences > 0, "occurrences has to be greater than 0"); uint256 achievementId = achievementIndex; Achievement storage achievement = achievements[achievementId]; achievement.action = action; achievement.occurrences = occurrences; emit LogNewAchievement(achievementId, msg.sender, content); achievementIndex = achievementId + 1; return achievementId; } function hasUserClaimedAchievement(address user, uint256 achievementId) public view returns (bool) { Achievement storage achievement = achievements[achievementId]; return achievement.claims[user]; } function hasUserPlacedPrediction(address user, uint256 marketId) public view returns (bool) { uint256[] memory outcomeShares; (, outcomeShares) = predictionMarket.getUserMarketShares(marketId, user); bool hasPlacedPrediction; for (uint256 i = 0; i < outcomeShares.length; i++) { if (outcomeShares[i] > 0) { hasPlacedPrediction = true; break; } } require(hasPlacedPrediction == true, "user does not hold outcome shares"); return true; } function hasUserAddedLiquidity(address user, uint256 marketId) public view returns (bool) { uint256 liquidityShares; (liquidityShares, ) = predictionMarket.getUserMarketShares(marketId, user); require(liquidityShares > 0, "user does not hold liquidity shares"); return true; } function hasUserPlacedBond( address user, uint256 marketId, bytes32[] memory history_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers ) public view returns (bool) { bytes32 last_history_hash; bytes32 questionId; (, questionId, ) = predictionMarket.getMarketAltData(marketId); (, , , , , , , , last_history_hash, ) = realitioERC20.questions(questionId); bool bonded; uint256 i; for (i = 0; i < history_hashes.length; i++) { require( last_history_hash == keccak256(abi.encodePacked(history_hashes[i], answers[i], bonds[i], addrs[i], false)) ); if (addrs[i] == user) bonded = true; last_history_hash = history_hashes[i]; } require(bonded == true, "user has not placed a bond in market"); return true; } function hasUserClaimedWinnings(address user, uint256 marketId) public view returns (bool) { uint256[] memory outcomeShares; (, outcomeShares) = predictionMarket.getUserMarketShares(marketId, user); PredictionMarketResolver.MarketResolution memory marketResolution = predictionMarketResolver.getMarketResolution( marketId ); uint256 resolvedOutcomeId = marketResolution.outcomeId; require(marketResolution.resolved == true, "market has not been resolved"); require(outcomeShares[resolvedOutcomeId] > 0, "user does not hold winning outcome shares"); return true; } function hasUserCreatedMarket(address user, uint256 marketId) public view returns (bool) { require(user != address(0), "user address is 0x0"); bytes32 questionId; address arbitrator; (, questionId, ) = predictionMarket.getMarketAltData(marketId); (, arbitrator, , , , , , , , ) = realitioERC20.questions(questionId); require(user == arbitrator, "user did not create market"); return true; } function claimAchievement(uint256 achievementId, uint256[] memory marketIds) public returns (uint256) { Achievement storage achievement = achievements[achievementId]; require(achievement.claims[msg.sender] == false, "Achievement already claimed"); require(achievement.action != Action.Bond, "Method not used for bond placement achievements"); require(marketIds.length == achievement.occurrences, "Markets count and occurrences don't match"); for (uint256 i = 0; i < marketIds.length; i++) { uint256 marketId = marketIds[i]; if (achievement.action == Action.Buy) { hasUserPlacedPrediction(msg.sender, marketId); } else if (achievement.action == Action.AddLiquidity) { hasUserAddedLiquidity(msg.sender, marketId); } else if (achievement.action == Action.ClaimWinnings) { hasUserClaimedWinnings(msg.sender, marketId); } else if (achievement.action == Action.CreateMarket) { hasUserCreatedMarket(msg.sender, marketId); } else { revert("Invalid achievement action"); } } mintAchievement(msg.sender, achievementId); } function claimAchievement( uint256 achievementId, uint256[] memory marketIds, uint256[] memory lengths, bytes32[] memory history_hashes, address[] memory addrs, uint256[] memory bonds, bytes32[] memory answers ) public { Achievement storage achievement = achievements[achievementId]; require(achievement.claims[msg.sender] == false, "Achievement already claimed"); require(achievement.action == Action.Bond, "Method only used for bond placement achievements"); require(marketIds.length > 0, "No actions provided"); require(marketIds.length == achievement.occurrences, "Markets count and occurrences don't match"); uint256 qi; for (uint256 i = 0; i < marketIds.length; i++) { uint256 marketId = marketIds[i]; uint256 ln = lengths[i]; 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] = history_hashes[qi]; ad[j] = addrs[qi]; bo[j] = bonds[qi]; an[j] = answers[qi]; qi++; } hasUserPlacedBond(msg.sender, marketId, hh, ad, bo, an); } mintAchievement(msg.sender, achievementId); } function mintAchievement(address user, uint256 achievementId) private returns (uint256) { _tokenIds.increment(); uint256 tokenId = _tokenIds.current(); _mint(user, tokenId); tokens[tokenId] = achievementId; Achievement storage achievement = achievements[achievementId]; achievement.claims[user] = true; return tokenId; } function tokenIndex() public view returns (uint256) { return _tokenIds.current(); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"token","type":"string"},{"internalType":"string","name":"ticker","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"achievementId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"string","name":"content","type":"string"}],"name":"LogNewAchievement","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"achievementIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"achievements","outputs":[{"internalType":"enum Achievements.Action","name":"action","type":"uint8"},{"internalType":"uint256","name":"occurrences","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"achievementId","type":"uint256"},{"internalType":"uint256[]","name":"marketIds","type":"uint256[]"}],"name":"claimAchievement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"achievementId","type":"uint256"},{"internalType":"uint256[]","name":"marketIds","type":"uint256[]"},{"internalType":"uint256[]","name":"lengths","type":"uint256[]"},{"internalType":"bytes32[]","name":"history_hashes","type":"bytes32[]"},{"internalType":"address[]","name":"addrs","type":"address[]"},{"internalType":"uint256[]","name":"bonds","type":"uint256[]"},{"internalType":"bytes32[]","name":"answers","type":"bytes32[]"}],"name":"claimAchievement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Achievements.Action","name":"action","type":"uint8"},{"internalType":"uint256","name":"occurrences","type":"uint256"},{"internalType":"string","name":"content","type":"string"}],"name":"createAchievement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"hasUserAddedLiquidity","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"achievementId","type":"uint256"}],"name":"hasUserClaimedAchievement","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"hasUserClaimedWinnings","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"hasUserCreatedMarket","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"bytes32[]","name":"history_hashes","type":"bytes32[]"},{"internalType":"address[]","name":"addrs","type":"address[]"},{"internalType":"uint256[]","name":"bonds","type":"uint256[]"},{"internalType":"bytes32[]","name":"answers","type":"bytes32[]"}],"name":"hasUserPlacedBond","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"hasUserPlacedPrediction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"predictionMarket","outputs":[{"internalType":"contract PredictionMarketV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"predictionMarketResolver","outputs":[{"internalType":"contract PredictionMarketResolver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"realitioERC20","outputs":[{"internalType":"contract RealitioERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract PredictionMarketV2","name":"_predictionMarket","type":"address"},{"internalType":"contract PredictionMarketResolver","name":"_predictionMarketResolver","type":"address"},{"internalType":"contract RealitioERC20","name":"_realitioERC20","type":"address"}],"name":"setContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526000600e553480156200001657600080fd5b506040516200389438038062003894833981016040819052620000399162000284565b8181620000566301ffc9a760e01b6001600160e01b03620000dd16565b81516200006b90600690602085019062000138565b5080516200008190600790602084019062000138565b506200009d6380ac58cd60e01b6001600160e01b03620000dd16565b620000b8635b5e139f60e01b6001600160e01b03620000dd16565b620000d363780e9d6360e01b6001600160e01b03620000dd16565b5050505062000322565b6001600160e01b03198082161415620001135760405162461bcd60e51b81526004016200010a90620002eb565b60405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200017b57805160ff1916838001178555620001ab565b82800160010185558215620001ab579182015b82811115620001ab5782518255916020019190600101906200018e565b50620001b9929150620001bd565b5090565b620001da91905b80821115620001b95760008155600101620001c4565b90565b600082601f830112620001ee578081fd5b81516001600160401b038082111562000205578283fd5b6040516020601f8401601f191682018101838111838210171562000227578586fd5b806040525081945083825286818588010111156200024457600080fd5b600092505b8383101562000268578583018101518284018201529182019162000249565b838311156200027a5760008185840101525b5050505092915050565b6000806040838503121562000297578182fd5b82516001600160401b0380821115620002ae578384fd5b620002bc86838701620001dd565b93506020850151915080821115620002d2578283fd5b50620002e185828601620001dd565b9150509250929050565b6020808252601c908201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604082015260600190565b61356280620003326000396000f3fe608060405234801561001057600080fd5b50600436106101a15760003560e01c806301ffc9a7146101a657806306fdde03146101cf578063081812fc146101e4578063095ea7b3146102045780630c04f83b1461021957806318160ddd1461022c57806323b872dd1461024157806327aed72e146102545780632f745c591461027557806342842e0e1461028857806342da0beb1461029b578063497e4096146102ae5780634f64b2be146102c15780634f6ccce7146102d457806355f804b3146102e75780636352211e146102fa5780636be5179f1461030d5780636c0360eb146103205780636f64432a1461032857806370a08231146103305780638c8b8f4e14610343578063947f53a21461035657806395d89b4114610369578063a22cb46514610371578063b3066d4914610384578063b88d4fde14610397578063c87b56dd146103aa578063c8c787ae146103bd578063c97c8976146103d0578063c99aea33146103d8578063d55f9273146103e0578063def114b6146103e8578063e7c38730146103f0578063e985e9c514610403578063ecf5f69b14610416575b600080fd5b6101b96101b43660046125ef565b610429565b6040516101c69190612a55565b60405180910390f35b6101d761044c565b6040516101c69190612a81565b6101f76101f2366004612737565b6104e3565b6040516101c69190612a04565b61021761021236600461245d565b61052f565b005b6101b961022736600461245d565b6105c7565b6102346106c1565b6040516101c69190612a60565b61021761024f366004612387565b6106d2565b610267610262366004612737565b61070a565b6040516101c6929190612a69565b61023461028336600461245d565b610729565b610217610296366004612387565b610758565b6101b96102a936600461245d565b610773565b6102346102bc36600461274f565b6107a1565b6102346102cf366004612737565b610924565b6102346102e2366004612737565b610936565b6102176102f53660046126ca565b610952565b6101f7610308366004612737565b610984565b61021761031b366004612833565b6109b2565b6101d7610c71565b6101f7610cd2565b61023461033e366004612333565b610ce1565b6101b9610351366004612488565b610d2a565b6101b961036436600461245d565b610f5a565b6101d76110dc565b61021761037f366004612430565b61113d565b610217610392366004612627565b61120b565b6102176103a53660046123c7565b611337565b6101d76103b8366004612737565b611376565b6102346103cb366004612671565b6114bc565b6101f761155e565b61023461156d565b610234611573565b6101f761157f565b6101b96103fe36600461245d565b61158e565b6101b961041136600461234f565b611643565b6101b961042436600461245d565b611671565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b60068054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104d85780601f106104ad576101008083540402835291602001916104d8565b820191906000526020600020905b8154815290600101906020018083116104bb57829003601f168201915b505050505090505b90565b60006104ee826117db565b6105135760405162461bcd60e51b815260040161050a90612f89565b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b600061053a82610984565b9050806001600160a01b0316836001600160a01b0316141561056e5760405162461bcd60e51b815260040161050a9061314d565b806001600160a01b03166105806117ee565b6001600160a01b0316148061059c575061059c816104116117ee565b6105b85760405162461bcd60e51b815260040161050a90612d70565b6105c283836117f2565b505050565b600c5460405163b31eb89560e01b81526000916060916001600160a01b039091169063b31eb895906105ff90869088906004016133de565b60006040518083038186803b15801561061757600080fd5b505afa15801561062b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106539190810190612793565b915060009050805b825181101561069157600083828151811061067257fe5b602002602001015111156106895760019150610691565b60010161065b565b506001811515146106b45760405162461bcd60e51b815260040161050a90612ba7565b6001925050505b92915050565b60006106cd6002611860565b905090565b6106e36106dd6117ee565b8261186b565b6106ff5760405162461bcd60e51b815260040161050a90613201565b6105c28383836118f0565b600f602052600090815260409020805460019091015460ff9091169082565b6001600160a01b0382166000908152600160205260408120610751908363ffffffff6119fe16565b9392505050565b6105c283838360405180602001604052806000815250611337565b6000908152600f602090815260408083206001600160a01b0394909416835260029093019052205460ff1690565b6000828152600f602090815260408083203384526002810190925282205460ff16156107df5760405162461bcd60e51b815260040161050a90613252565b6002815460ff1660048111156107f157fe5b141561080f5760405162461bcd60e51b815260040161050a9061334b565b80600101548351146108335760405162461bcd60e51b815260040161050a90612b28565b60005b835181101561091157600084828151811061084d57fe5b602002602001015190506000600481111561086457fe5b835460ff16600481111561087457fe5b141561088a5761088433826105c7565b50610908565b6001835460ff16600481111561089c57fe5b14156108ac57610884338261158e565b6003835460ff1660048111156108be57fe5b14156108ce576108843382610f5a565b6004835460ff1660048111156108e057fe5b14156108f0576108843382611671565b60405162461bcd60e51b815260040161050a906130d6565b50600101610836565b5061091c3385611a0a565b505092915050565b60106020526000908152604090205481565b60008061094a60028463ffffffff611a7316565b509392505050565b61095a610c71565b51156109785760405162461bcd60e51b815260040161050a90612c5f565b61098181611a8f565b50565b60006106bb826040518060600160405280602981526020016134e4602991396002919063ffffffff611aa616565b6000878152600f60209081526040808320338452600281019092529091205460ff16156109f15760405162461bcd60e51b815260040161050a90613252565b6002815460ff166004811115610a0357fe5b14610a205760405162461bcd60e51b815260040161050a90612f39565b6000875111610a415760405162461bcd60e51b815260040161050a90612e12565b8060010154875114610a655760405162461bcd60e51b815260040161050a90612b28565b6000805b8851811015610c5a576000898281518110610a8057fe5b602002602001015190506000898381518110610a9857fe5b60200260200101519050606081604051908082528060200260200182016040528015610ace578160200160208202803883390190505b509050606082604051908082528060200260200182016040528015610afd578160200160208202803883390190505b509050606083604051908082528060200260200182016040528015610b2c578160200160208202803883390190505b509050606084604051908082528060200260200182016040528015610b5b578160200160208202803883390190505b50905060005b85811015610c38578d8981518110610b7557fe5b6020026020010151858281518110610b8957fe5b6020026020010181815250508c8981518110610ba157fe5b6020026020010151848281518110610bb557fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508b8981518110610be157fe5b6020026020010151838281518110610bf557fe5b6020026020010181815250508a8981518110610c0d57fe5b6020026020010151828281518110610c2157fe5b602090810291909101015260019889019801610b61565b610c46338887878787610d2a565b505060019096019550610a69945050505050565b50610c65338a611a0a565b50505050505050505050565b60098054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104d85780601f106104ad576101008083540402835291602001916104d8565b600d546001600160a01b031681565b60006001600160a01b038216610d095760405162461bcd60e51b815260040161050a90612dc8565b6001600160a01b03821660009081526001602052604090206106bb90611860565b600c54604051630ebc905560e11b8152600091829182916001600160a01b031690631d7920aa90610d5f908b90600401612a60565b60606040518083038186803b158015610d7757600080fd5b505afa158015610d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610daf919081019061292b565b50600b5460405163095addb960e41b81529193506001600160a01b031691506395addb9090610de2908490600401612a60565b6101406040518083038186803b158015610dfb57600080fd5b505afa158015610e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e339190810190612549565b509950600097508796505050505050505b8851811015610f2757888181518110610e5957fe5b6020026020010151868281518110610e6d57fe5b6020026020010151888381518110610e8157fe5b60200260200101518a8481518110610e9557fe5b60200260200101516000604051602001610eb3959493929190612984565b604051602081830303815290604052805190602001208414610ed457600080fd5b8a6001600160a01b0316888281518110610eea57fe5b60200260200101516001600160a01b03161415610f0657600191505b888181518110610f1257fe5b60209081029190910101519350600101610e44565b600182151514610f495760405162461bcd60e51b815260040161050a906132be565b5060019a9950505050505050505050565b600c5460405163b31eb89560e01b81526000916060916001600160a01b039091169063b31eb89590610f9290869088906004016133de565b60006040518083038186803b158015610faa57600080fd5b505afa158015610fbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fe69190810190612793565b9150610ff2905061213c565b600d5460405163232e45d760e01b81526001600160a01b039091169063232e45d790611022908790600401612a60565b604080518083038186803b15801561103957600080fd5b505afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061107191908101906126fc565b6020810151815191925090151560011461109d5760405162461bcd60e51b815260040161050a90612eb6565b60008382815181106110ab57fe5b6020026020010151116110d05760405162461bcd60e51b815260040161050a90613302565b50600195945050505050565b60078054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104d85780601f106104ad576101008083540402835291602001916104d8565b6111456117ee565b6001600160a01b0316826001600160a01b031614156111765760405162461bcd60e51b815260040161050a90612c2c565b80600560006111836117ee565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff1916921515929092179091556111c76117ee565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516111ff9190612a55565b60405180910390a35050565b600c546001600160a01b0316156112345760405162461bcd60e51b815260040161050a90612eec565b600d546001600160a01b03161561125d5760405162461bcd60e51b815260040161050a90612eec565b600b546001600160a01b0316156112865760405162461bcd60e51b815260040161050a90612d26565b6001600160a01b0383166112ac5760405162461bcd60e51b815260040161050a90612cef565b6001600160a01b0382166112d25760405162461bcd60e51b815260040161050a9061318e565b6001600160a01b0381166112f85760405162461bcd60e51b815260040161050a906130a1565b600c80546001600160a01b039485166001600160a01b031991821617909155600d805493851693821693909317909255600b8054919093169116179055565b6113486113426117ee565b8361186b565b6113645760405162461bcd60e51b815260040161050a90613201565b61137084848484611ab3565b50505050565b6060611381826117db565b61139d5760405162461bcd60e51b815260040161050a9061301e565b60008281526008602090815260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156114325780601f1061140757610100808354040283529160200191611432565b820191906000526020600020905b81548152906001019060200180831161141557829003601f168201915b505050505090506060611443610c71565b905080516000141561145757509050610447565b8151156114895780826040516020016114719291906129d6565b60405160208183030381529060405292505050610447565b8061149385611ae6565b6040516020016114a49291906129d6565b60405160208183030381529060405292505050919050565b60008083116114dd5760405162461bcd60e51b815260040161050a9061339a565b600e546000818152600f6020526040902080548690829060ff1916600183600481111561150657fe5b021790555060018101859055604051339083907ff12dd2cec284c7695fa5ff87a683b64add6d47d7a74e190171798ee5e70a744c90611546908890612a81565b60405180910390a35060018101600e55949350505050565b600b546001600160a01b031681565b600e5481565b60006106cd600a611baa565b600c546001600160a01b031681565b600c5460405163b31eb89560e01b815260009182916001600160a01b039091169063b31eb895906115c590869088906004016133de565b60006040518083038186803b1580156115dd57600080fd5b505afa1580156115f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116199190810190612793565b509050806116395760405162461bcd60e51b815260040161050a9061310a565b5060019392505050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60006001600160a01b0383166116995760405162461bcd60e51b815260040161050a906131d4565b600c54604051630ebc905560e11b815260009182916001600160a01b0390911690631d7920aa906116ce908790600401612a60565b60606040518083038186803b1580156116e657600080fd5b505afa1580156116fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061171e919081019061292b565b50600b5460405163095addb960e41b81529194506001600160a01b031691506395addb9090611751908590600401612a60565b6101406040518083038186803b15801561176a57600080fd5b505afa15801561177e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117a29190810190612549565b509698505050506001600160a01b038a81169087161494506106b493505050505760405162461bcd60e51b815260040161050a9061306d565b60006106bb60028363ffffffff611bae16565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061182782610984565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006106bb82611baa565b6000611876826117db565b6118925760405162461bcd60e51b815260040161050a90612ca3565b600061189d83610984565b9050806001600160a01b0316846001600160a01b031614806118d85750836001600160a01b03166118cd846104e3565b6001600160a01b0316145b806118e857506118e88185611643565b949350505050565b826001600160a01b031661190382610984565b6001600160a01b0316146119295760405162461bcd60e51b815260040161050a90612fd5565b6001600160a01b03821661194f5760405162461bcd60e51b815260040161050a90612be8565b61195a8383836105c2565b6119656000826117f2565b6001600160a01b038316600090815260016020526040902061198d908263ffffffff611bba16565b506001600160a01b03821660009081526001602052604090206119b6908263ffffffff611bc616565b506119c96002828463ffffffff611bd216565b5080826001600160a01b0316846001600160a01b031660008051602061350d83398151915260405160405180910390a4505050565b60006107518383611be8565b6000611a16600a611c2d565b6000611a22600a611baa565b9050611a2e8482611c36565b6000818152601060209081526040808320869055858352600f82528083206001600160a01b03881684526002019091529020805460ff19166001179055905092915050565b6000808080611a828686611cf4565b9097909650945050505050565b8051611aa2906009906020840190612153565b5050565b60006118e8848484611d50565b611abe8484846118f0565b611aca84848484611daf565b6113705760405162461bcd60e51b815260040161050a90612ad6565b606081611b0b57506040805180820190915260018152600360fc1b6020820152610447565b8160005b8115611b2357600101600a82049150611b0f565b6060816040519080825280601f01601f191660200182016040528015611b50576020820181803883390190505b50859350905060001982015b8315611ba157600a840660300160f81b82828060019003935081518110611b7f57fe5b60200101906001600160f81b031916908160001a905350600a84049350611b5c565b50949350505050565b5490565b60006107518383611e94565b60006107518383611eac565b60006107518383611f72565b60006118e884846001600160a01b038516611fbc565b81546000908210611c0b5760405162461bcd60e51b815260040161050a90612a94565b826000018281548110611c1a57fe5b9060005260206000200154905092915050565b80546001019055565b6001600160a01b038216611c5c5760405162461bcd60e51b815260040161050a90612e81565b611c65816117db565b15611c825760405162461bcd60e51b815260040161050a90612b71565b611c8e600083836105c2565b6001600160a01b0382166000908152600160205260409020611cb6908263ffffffff611bc616565b50611cc96002828463ffffffff611bd216565b5060405181906001600160a01b0384169060009060008051602061350d833981519152908290a45050565b815460009081908310611d195760405162461bcd60e51b815260040161050a90612e3f565b6000846000018481548110611d2a57fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b60008281526001840160205260408120548281611d805760405162461bcd60e51b815260040161050a9190612a81565b50846000016001820381548110611d9357fe5b9060005260206000209060020201600101549150509392505050565b6000611dc3846001600160a01b0316612053565b611dcf575060016118e8565b6060611e5d630a85bd0160e11b611de46117ee565b888787604051602401611dfa9493929190612a18565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518060600160405280603281526020016134b2603291396001600160a01b038816919063ffffffff61205916565b9050600081806020019051611e75919081019061260b565b6001600160e01b031916630a85bd0160e11b1492505050949350505050565b60009081526001919091016020526040902054151590565b60008181526001830160205260408120548015611f685783546000198083019190810190600090879083908110611edf57fe5b9060005260206000200154905080876000018481548110611efc57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080611f2c57fe5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506106bb565b60009150506106bb565b6000611f7e8383611e94565b611fb4575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106bb565b5060006106bb565b600082815260018401602052604081205480612021575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055610751565b8285600001600183038154811061203457fe5b9060005260206000209060020201600101819055506000915050610751565b3b151590565b60606118e884846000858561206d85612053565b6120895760405162461bcd60e51b815260040161050a90613287565b60006060866001600160a01b031685876040516120a691906129ba565b60006040518083038185875af1925050503d80600081146120e3576040519150601f19603f3d011682016040523d82523d6000602084013e6120e8565b606091505b50915091506120f8828286612103565b979650505050505050565b60608315612112575081610751565b8251156121225782518084602001fd5b8160405162461bcd60e51b815260040161050a9190612a81565b604080518082019091526000808252602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061219457805160ff19168380011785556121c1565b828001600101855582156121c1579182015b828111156121c15782518255916020019190600101906121a6565b506121cd9291506121d1565b5090565b6104e091905b808211156121cd57600081556001016121d7565b80356106bb81613466565b600082601f830112612206578081fd5b81356122196122148261341b565b6133f5565b81815291506020808301908481018184028601820187101561223a57600080fd5b60005b8481101561226257813561225081613466565b8452928201929082019060010161223d565b505050505092915050565b600082601f83011261227d578081fd5b813561228b6122148261341b565b8181529150602080830190848101818402860182018710156122ac57600080fd5b60005b84811015612262578135845292820192908201906001016122af565b600082601f8301126122db578081fd5b81356001600160401b038111156122f0578182fd5b612303601f8201601f19166020016133f5565b915080825283602082850101111561231a57600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215612344578081fd5b813561075181613466565b60008060408385031215612361578081fd5b823561236c81613466565b9150602083013561237c81613466565b809150509250929050565b60008060006060848603121561239b578081fd5b83356123a681613466565b925060208401356123b681613466565b929592945050506040919091013590565b600080600080608085870312156123dc578182fd5b84356123e781613466565b935060208501356123f781613466565b92506040850135915060608501356001600160401b03811115612418578182fd5b612424878288016122cb565b91505092959194509250565b60008060408385031215612442578182fd5b823561244d81613466565b9150602083013561237c8161347b565b6000806040838503121561246f578182fd5b823561247a81613466565b946020939093013593505050565b60008060008060008060c087890312156124a0578384fd5b6124aa88886121eb565b95506020870135945060408701356001600160401b03808211156124cc578586fd5b6124d88a838b0161226d565b955060608901359150808211156124ed578384fd5b6124f98a838b016121f6565b9450608089013591508082111561250e578384fd5b61251a8a838b0161226d565b935060a089013591508082111561252f578283fd5b5061253c89828a0161226d565b9150509295509295509295565b6000806000806000806000806000806101408b8d031215612568578788fd5b8a51995060208b015161257a81613466565b60408c015190995061258b8161349f565b60608c015190985061259c8161349f565b60808c01519097506125ad8161349f565b60a08c01519096506125be8161347b565b8095505060c08b0151935060e08b015192506101008b015191506101208b015190509295989b9194979a5092959850565b600060208284031215612600578081fd5b813561075181613489565b60006020828403121561261c578081fd5b815161075181613489565b60008060006060848603121561263b578081fd5b833561264681613466565b9250602084013561265681613466565b9150604084013561266681613466565b809150509250925092565b600080600060608486031215612685578081fd5b833560058110612693578182fd5b92506020840135915060408401356001600160401b038111156126b4578182fd5b6126c0868287016122cb565b9150509250925092565b6000602082840312156126db578081fd5b81356001600160401b038111156126f0578182fd5b6118e8848285016122cb565b60006040828403121561270d578081fd5b61271760406133f5565b82516127228161347b565b81526020928301519281019290925250919050565b600060208284031215612748578081fd5b5035919050565b60008060408385031215612761578182fd5b8235915060208301356001600160401b0381111561277d578182fd5b6127898582860161226d565b9150509250929050565b600080604083850312156127a5578182fd5b8251602080850151919350906001600160401b038111156127c4578283fd5b80850186601f8201126127d5578384fd5b805191506127e56122148361341b565b82815283810190828501858502840186018a1015612801578687fd5b8693505b84841015612823578051835260019390930192918501918501612805565b5080955050505050509250929050565b600080600080600080600060e0888a03121561284d578081fd5b8735965060208801356001600160401b038082111561286a578283fd5b6128768b838c0161226d565b975060408a013591508082111561288b578283fd5b6128978b838c0161226d565b965060608a01359150808211156128ac578283fd5b6128b88b838c0161226d565b955060808a01359150808211156128cd578283fd5b6128d98b838c016121f6565b945060a08a01359150808211156128ee578283fd5b6128fa8b838c0161226d565b935060c08a013591508082111561290f578283fd5b5061291c8a828b0161226d565b91505092959891949750929550565b60008060006060848603121561293f578081fd5b8351925060208401519150604084015190509250925092565b6000815180845261297081602086016020860161343a565b601f01601f19169290920160200192915050565b94855260208501939093526040840191909152606090811b6001600160601b03191690830152151560f81b607482015260750190565b600082516129cc81846020870161343a565b9190910192915050565b600083516129e881846020880161343a565b83519083016129fb82826020880161343a565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612a4b90830184612958565b9695505050505050565b901515815260200190565b90815260200190565b6040810160058410612a7757fe5b9281526020015290565b6000602082526107516020830184612958565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526029908201527f4d61726b65747320636f756e7420616e64206f6363757272656e63657320646f6040820152680dc4ee840dac2e8c6d60bb1b606082015260800190565b6020808252601c908201527b115490cdcc8c4e881d1bdad95b88185b1c9958591e481b5a5b9d195960221b604082015260600190565b60208082526021908201527f7573657220646f6573206e6f7420686f6c64206f7574636f6d652073686172656040820152607360f81b606082015260800190565b60208082526024908201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526019908201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b604082015260600190565b60208082526024908201527f626173655552492063616e206f6e6c7920626520696e697469616c697a6564206040820152636f6e636560e01b606082015260800190565b6020808252602c908201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252601e908201527f5f70726564696374696f6e4d61726b6574206164647265737320697320300000604082015260600190565b6020808252602a908201527f7265616c6974696f45524332302063616e206f6e6c7920626520696e697469616040820152696c697a6564206f6e636560b01b606082015260800190565b60208082526038908201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776040820152771b995c881b9bdc88185c1c1c9bdd995908199bdc88185b1b60421b606082015260800190565b6020808252602a908201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604082015269726f206164647265737360b01b606082015260800190565b602080825260139082015272139bc81858dd1a5bdb9cc81c1c9bdd9a591959606a1b604082015260600190565b60208082526022908201527f456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252818101527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604082015260600190565b6020808252601c908201527b1b585c9ad95d081a185cc81b9bdd081899595b881c995cdbdb1d995960221b604082015260600190565b6020808252602d908201527f70726564696374696f6e4d61726b65742063616e206f6e6c7920626520696e6960408201526c7469616c697a6564206f6e636560981b606082015260800190565b60208082526030908201527f4d6574686f64206f6e6c79207573656420666f7220626f6e6420706c6163656d60408201526f656e7420616368696576656d656e747360801b606082015260800190565b6020808252602c908201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b60208082526029908201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960408201526839903737ba1037bbb760b91b606082015260800190565b6020808252602f908201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b6020808252601a90820152791d5cd95c88191a59081b9bdd0818dc99585d19481b585c9ad95d60321b604082015260600190565b6020808252601b908201527a05f7265616c6974696f45524332302061646472657373206973203602c1b604082015260600190565b6020808252601a908201527924b73b30b634b21030b1b434b2bb32b6b2b73a1030b1ba34b7b760311b604082015260600190565b60208082526023908201527f7573657220646f6573206e6f7420686f6c64206c69717569646974792073686160408201526272657360e81b606082015260800190565b60208082526021908201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656040820152603960f91b606082015260800190565b60208082526026908201527f5f70726564696374696f6e4d61726b65745265736f6c7665722061646472657360408201526507320697320360d41b606082015260800190565b60208082526013908201527207573657220616464726573732069732030783606c1b604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601b908201527a1058da1a595d995b595b9d08185b1c9958591e4818db185a5b5959602a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526024908201527f7573657220686173206e6f7420706c61636564206120626f6e6420696e206d616040820152631c9ad95d60e21b606082015260800190565b60208082526029908201527f7573657220646f6573206e6f7420686f6c642077696e6e696e67206f7574636f6040820152686d652073686172657360b81b606082015260800190565b6020808252602f908201527f4d6574686f64206e6f74207573656420666f7220626f6e6420706c6163656d6560408201526e6e7420616368696576656d656e747360881b606082015260800190565b60208082526024908201527f6f6363757272656e6365732068617320746f20626520677265617465722074686040820152630616e20360e41b606082015260800190565b9182526001600160a01b0316602082015260400190565b6040518181016001600160401b038111828210171561341357600080fd5b604052919050565b60006001600160401b03821115613430578081fd5b5060209081020190565b60005b8381101561345557818101518382015260200161343d565b838111156113705750506000910152565b6001600160a01b038116811461098157600080fd5b801515811461098157600080fd5b6001600160e01b03198116811461098157600080fd5b63ffffffff8116811461098157600080fdfe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220e731d2d277243cb26ce67dd65f8de00b43380526a9a0457ad6a480b5a9a8b17364736f6c6343000602003300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a49464c205469746c657300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000449464c5400000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a15760003560e01c806301ffc9a7146101a657806306fdde03146101cf578063081812fc146101e4578063095ea7b3146102045780630c04f83b1461021957806318160ddd1461022c57806323b872dd1461024157806327aed72e146102545780632f745c591461027557806342842e0e1461028857806342da0beb1461029b578063497e4096146102ae5780634f64b2be146102c15780634f6ccce7146102d457806355f804b3146102e75780636352211e146102fa5780636be5179f1461030d5780636c0360eb146103205780636f64432a1461032857806370a08231146103305780638c8b8f4e14610343578063947f53a21461035657806395d89b4114610369578063a22cb46514610371578063b3066d4914610384578063b88d4fde14610397578063c87b56dd146103aa578063c8c787ae146103bd578063c97c8976146103d0578063c99aea33146103d8578063d55f9273146103e0578063def114b6146103e8578063e7c38730146103f0578063e985e9c514610403578063ecf5f69b14610416575b600080fd5b6101b96101b43660046125ef565b610429565b6040516101c69190612a55565b60405180910390f35b6101d761044c565b6040516101c69190612a81565b6101f76101f2366004612737565b6104e3565b6040516101c69190612a04565b61021761021236600461245d565b61052f565b005b6101b961022736600461245d565b6105c7565b6102346106c1565b6040516101c69190612a60565b61021761024f366004612387565b6106d2565b610267610262366004612737565b61070a565b6040516101c6929190612a69565b61023461028336600461245d565b610729565b610217610296366004612387565b610758565b6101b96102a936600461245d565b610773565b6102346102bc36600461274f565b6107a1565b6102346102cf366004612737565b610924565b6102346102e2366004612737565b610936565b6102176102f53660046126ca565b610952565b6101f7610308366004612737565b610984565b61021761031b366004612833565b6109b2565b6101d7610c71565b6101f7610cd2565b61023461033e366004612333565b610ce1565b6101b9610351366004612488565b610d2a565b6101b961036436600461245d565b610f5a565b6101d76110dc565b61021761037f366004612430565b61113d565b610217610392366004612627565b61120b565b6102176103a53660046123c7565b611337565b6101d76103b8366004612737565b611376565b6102346103cb366004612671565b6114bc565b6101f761155e565b61023461156d565b610234611573565b6101f761157f565b6101b96103fe36600461245d565b61158e565b6101b961041136600461234f565b611643565b6101b961042436600461245d565b611671565b6001600160e01b0319811660009081526020819052604090205460ff165b919050565b60068054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104d85780601f106104ad576101008083540402835291602001916104d8565b820191906000526020600020905b8154815290600101906020018083116104bb57829003601f168201915b505050505090505b90565b60006104ee826117db565b6105135760405162461bcd60e51b815260040161050a90612f89565b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b600061053a82610984565b9050806001600160a01b0316836001600160a01b0316141561056e5760405162461bcd60e51b815260040161050a9061314d565b806001600160a01b03166105806117ee565b6001600160a01b0316148061059c575061059c816104116117ee565b6105b85760405162461bcd60e51b815260040161050a90612d70565b6105c283836117f2565b505050565b600c5460405163b31eb89560e01b81526000916060916001600160a01b039091169063b31eb895906105ff90869088906004016133de565b60006040518083038186803b15801561061757600080fd5b505afa15801561062b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106539190810190612793565b915060009050805b825181101561069157600083828151811061067257fe5b602002602001015111156106895760019150610691565b60010161065b565b506001811515146106b45760405162461bcd60e51b815260040161050a90612ba7565b6001925050505b92915050565b60006106cd6002611860565b905090565b6106e36106dd6117ee565b8261186b565b6106ff5760405162461bcd60e51b815260040161050a90613201565b6105c28383836118f0565b600f602052600090815260409020805460019091015460ff9091169082565b6001600160a01b0382166000908152600160205260408120610751908363ffffffff6119fe16565b9392505050565b6105c283838360405180602001604052806000815250611337565b6000908152600f602090815260408083206001600160a01b0394909416835260029093019052205460ff1690565b6000828152600f602090815260408083203384526002810190925282205460ff16156107df5760405162461bcd60e51b815260040161050a90613252565b6002815460ff1660048111156107f157fe5b141561080f5760405162461bcd60e51b815260040161050a9061334b565b80600101548351146108335760405162461bcd60e51b815260040161050a90612b28565b60005b835181101561091157600084828151811061084d57fe5b602002602001015190506000600481111561086457fe5b835460ff16600481111561087457fe5b141561088a5761088433826105c7565b50610908565b6001835460ff16600481111561089c57fe5b14156108ac57610884338261158e565b6003835460ff1660048111156108be57fe5b14156108ce576108843382610f5a565b6004835460ff1660048111156108e057fe5b14156108f0576108843382611671565b60405162461bcd60e51b815260040161050a906130d6565b50600101610836565b5061091c3385611a0a565b505092915050565b60106020526000908152604090205481565b60008061094a60028463ffffffff611a7316565b509392505050565b61095a610c71565b51156109785760405162461bcd60e51b815260040161050a90612c5f565b61098181611a8f565b50565b60006106bb826040518060600160405280602981526020016134e4602991396002919063ffffffff611aa616565b6000878152600f60209081526040808320338452600281019092529091205460ff16156109f15760405162461bcd60e51b815260040161050a90613252565b6002815460ff166004811115610a0357fe5b14610a205760405162461bcd60e51b815260040161050a90612f39565b6000875111610a415760405162461bcd60e51b815260040161050a90612e12565b8060010154875114610a655760405162461bcd60e51b815260040161050a90612b28565b6000805b8851811015610c5a576000898281518110610a8057fe5b602002602001015190506000898381518110610a9857fe5b60200260200101519050606081604051908082528060200260200182016040528015610ace578160200160208202803883390190505b509050606082604051908082528060200260200182016040528015610afd578160200160208202803883390190505b509050606083604051908082528060200260200182016040528015610b2c578160200160208202803883390190505b509050606084604051908082528060200260200182016040528015610b5b578160200160208202803883390190505b50905060005b85811015610c38578d8981518110610b7557fe5b6020026020010151858281518110610b8957fe5b6020026020010181815250508c8981518110610ba157fe5b6020026020010151848281518110610bb557fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508b8981518110610be157fe5b6020026020010151838281518110610bf557fe5b6020026020010181815250508a8981518110610c0d57fe5b6020026020010151828281518110610c2157fe5b602090810291909101015260019889019801610b61565b610c46338887878787610d2a565b505060019096019550610a69945050505050565b50610c65338a611a0a565b50505050505050505050565b60098054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104d85780601f106104ad576101008083540402835291602001916104d8565b600d546001600160a01b031681565b60006001600160a01b038216610d095760405162461bcd60e51b815260040161050a90612dc8565b6001600160a01b03821660009081526001602052604090206106bb90611860565b600c54604051630ebc905560e11b8152600091829182916001600160a01b031690631d7920aa90610d5f908b90600401612a60565b60606040518083038186803b158015610d7757600080fd5b505afa158015610d8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610daf919081019061292b565b50600b5460405163095addb960e41b81529193506001600160a01b031691506395addb9090610de2908490600401612a60565b6101406040518083038186803b158015610dfb57600080fd5b505afa158015610e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e339190810190612549565b509950600097508796505050505050505b8851811015610f2757888181518110610e5957fe5b6020026020010151868281518110610e6d57fe5b6020026020010151888381518110610e8157fe5b60200260200101518a8481518110610e9557fe5b60200260200101516000604051602001610eb3959493929190612984565b604051602081830303815290604052805190602001208414610ed457600080fd5b8a6001600160a01b0316888281518110610eea57fe5b60200260200101516001600160a01b03161415610f0657600191505b888181518110610f1257fe5b60209081029190910101519350600101610e44565b600182151514610f495760405162461bcd60e51b815260040161050a906132be565b5060019a9950505050505050505050565b600c5460405163b31eb89560e01b81526000916060916001600160a01b039091169063b31eb89590610f9290869088906004016133de565b60006040518083038186803b158015610faa57600080fd5b505afa158015610fbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fe69190810190612793565b9150610ff2905061213c565b600d5460405163232e45d760e01b81526001600160a01b039091169063232e45d790611022908790600401612a60565b604080518083038186803b15801561103957600080fd5b505afa15801561104d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061107191908101906126fc565b6020810151815191925090151560011461109d5760405162461bcd60e51b815260040161050a90612eb6565b60008382815181106110ab57fe5b6020026020010151116110d05760405162461bcd60e51b815260040161050a90613302565b50600195945050505050565b60078054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104d85780601f106104ad576101008083540402835291602001916104d8565b6111456117ee565b6001600160a01b0316826001600160a01b031614156111765760405162461bcd60e51b815260040161050a90612c2c565b80600560006111836117ee565b6001600160a01b03908116825260208083019390935260409182016000908120918716808252919093529120805460ff1916921515929092179091556111c76117ee565b6001600160a01b03167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516111ff9190612a55565b60405180910390a35050565b600c546001600160a01b0316156112345760405162461bcd60e51b815260040161050a90612eec565b600d546001600160a01b03161561125d5760405162461bcd60e51b815260040161050a90612eec565b600b546001600160a01b0316156112865760405162461bcd60e51b815260040161050a90612d26565b6001600160a01b0383166112ac5760405162461bcd60e51b815260040161050a90612cef565b6001600160a01b0382166112d25760405162461bcd60e51b815260040161050a9061318e565b6001600160a01b0381166112f85760405162461bcd60e51b815260040161050a906130a1565b600c80546001600160a01b039485166001600160a01b031991821617909155600d805493851693821693909317909255600b8054919093169116179055565b6113486113426117ee565b8361186b565b6113645760405162461bcd60e51b815260040161050a90613201565b61137084848484611ab3565b50505050565b6060611381826117db565b61139d5760405162461bcd60e51b815260040161050a9061301e565b60008281526008602090815260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156114325780601f1061140757610100808354040283529160200191611432565b820191906000526020600020905b81548152906001019060200180831161141557829003601f168201915b505050505090506060611443610c71565b905080516000141561145757509050610447565b8151156114895780826040516020016114719291906129d6565b60405160208183030381529060405292505050610447565b8061149385611ae6565b6040516020016114a49291906129d6565b60405160208183030381529060405292505050919050565b60008083116114dd5760405162461bcd60e51b815260040161050a9061339a565b600e546000818152600f6020526040902080548690829060ff1916600183600481111561150657fe5b021790555060018101859055604051339083907ff12dd2cec284c7695fa5ff87a683b64add6d47d7a74e190171798ee5e70a744c90611546908890612a81565b60405180910390a35060018101600e55949350505050565b600b546001600160a01b031681565b600e5481565b60006106cd600a611baa565b600c546001600160a01b031681565b600c5460405163b31eb89560e01b815260009182916001600160a01b039091169063b31eb895906115c590869088906004016133de565b60006040518083038186803b1580156115dd57600080fd5b505afa1580156115f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116199190810190612793565b509050806116395760405162461bcd60e51b815260040161050a9061310a565b5060019392505050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60006001600160a01b0383166116995760405162461bcd60e51b815260040161050a906131d4565b600c54604051630ebc905560e11b815260009182916001600160a01b0390911690631d7920aa906116ce908790600401612a60565b60606040518083038186803b1580156116e657600080fd5b505afa1580156116fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061171e919081019061292b565b50600b5460405163095addb960e41b81529194506001600160a01b031691506395addb9090611751908590600401612a60565b6101406040518083038186803b15801561176a57600080fd5b505afa15801561177e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506117a29190810190612549565b509698505050506001600160a01b038a81169087161494506106b493505050505760405162461bcd60e51b815260040161050a9061306d565b60006106bb60028363ffffffff611bae16565b3390565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061182782610984565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006106bb82611baa565b6000611876826117db565b6118925760405162461bcd60e51b815260040161050a90612ca3565b600061189d83610984565b9050806001600160a01b0316846001600160a01b031614806118d85750836001600160a01b03166118cd846104e3565b6001600160a01b0316145b806118e857506118e88185611643565b949350505050565b826001600160a01b031661190382610984565b6001600160a01b0316146119295760405162461bcd60e51b815260040161050a90612fd5565b6001600160a01b03821661194f5760405162461bcd60e51b815260040161050a90612be8565b61195a8383836105c2565b6119656000826117f2565b6001600160a01b038316600090815260016020526040902061198d908263ffffffff611bba16565b506001600160a01b03821660009081526001602052604090206119b6908263ffffffff611bc616565b506119c96002828463ffffffff611bd216565b5080826001600160a01b0316846001600160a01b031660008051602061350d83398151915260405160405180910390a4505050565b60006107518383611be8565b6000611a16600a611c2d565b6000611a22600a611baa565b9050611a2e8482611c36565b6000818152601060209081526040808320869055858352600f82528083206001600160a01b03881684526002019091529020805460ff19166001179055905092915050565b6000808080611a828686611cf4565b9097909650945050505050565b8051611aa2906009906020840190612153565b5050565b60006118e8848484611d50565b611abe8484846118f0565b611aca84848484611daf565b6113705760405162461bcd60e51b815260040161050a90612ad6565b606081611b0b57506040805180820190915260018152600360fc1b6020820152610447565b8160005b8115611b2357600101600a82049150611b0f565b6060816040519080825280601f01601f191660200182016040528015611b50576020820181803883390190505b50859350905060001982015b8315611ba157600a840660300160f81b82828060019003935081518110611b7f57fe5b60200101906001600160f81b031916908160001a905350600a84049350611b5c565b50949350505050565b5490565b60006107518383611e94565b60006107518383611eac565b60006107518383611f72565b60006118e884846001600160a01b038516611fbc565b81546000908210611c0b5760405162461bcd60e51b815260040161050a90612a94565b826000018281548110611c1a57fe5b9060005260206000200154905092915050565b80546001019055565b6001600160a01b038216611c5c5760405162461bcd60e51b815260040161050a90612e81565b611c65816117db565b15611c825760405162461bcd60e51b815260040161050a90612b71565b611c8e600083836105c2565b6001600160a01b0382166000908152600160205260409020611cb6908263ffffffff611bc616565b50611cc96002828463ffffffff611bd216565b5060405181906001600160a01b0384169060009060008051602061350d833981519152908290a45050565b815460009081908310611d195760405162461bcd60e51b815260040161050a90612e3f565b6000846000018481548110611d2a57fe5b906000526020600020906002020190508060000154816001015492509250509250929050565b60008281526001840160205260408120548281611d805760405162461bcd60e51b815260040161050a9190612a81565b50846000016001820381548110611d9357fe5b9060005260206000209060020201600101549150509392505050565b6000611dc3846001600160a01b0316612053565b611dcf575060016118e8565b6060611e5d630a85bd0160e11b611de46117ee565b888787604051602401611dfa9493929190612a18565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050506040518060600160405280603281526020016134b2603291396001600160a01b038816919063ffffffff61205916565b9050600081806020019051611e75919081019061260b565b6001600160e01b031916630a85bd0160e11b1492505050949350505050565b60009081526001919091016020526040902054151590565b60008181526001830160205260408120548015611f685783546000198083019190810190600090879083908110611edf57fe5b9060005260206000200154905080876000018481548110611efc57fe5b600091825260208083209091019290925582815260018981019092526040902090840190558654879080611f2c57fe5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506106bb565b60009150506106bb565b6000611f7e8383611e94565b611fb4575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106bb565b5060006106bb565b600082815260018401602052604081205480612021575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055610751565b8285600001600183038154811061203457fe5b9060005260206000209060020201600101819055506000915050610751565b3b151590565b60606118e884846000858561206d85612053565b6120895760405162461bcd60e51b815260040161050a90613287565b60006060866001600160a01b031685876040516120a691906129ba565b60006040518083038185875af1925050503d80600081146120e3576040519150601f19603f3d011682016040523d82523d6000602084013e6120e8565b606091505b50915091506120f8828286612103565b979650505050505050565b60608315612112575081610751565b8251156121225782518084602001fd5b8160405162461bcd60e51b815260040161050a9190612a81565b604080518082019091526000808252602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061219457805160ff19168380011785556121c1565b828001600101855582156121c1579182015b828111156121c15782518255916020019190600101906121a6565b506121cd9291506121d1565b5090565b6104e091905b808211156121cd57600081556001016121d7565b80356106bb81613466565b600082601f830112612206578081fd5b81356122196122148261341b565b6133f5565b81815291506020808301908481018184028601820187101561223a57600080fd5b60005b8481101561226257813561225081613466565b8452928201929082019060010161223d565b505050505092915050565b600082601f83011261227d578081fd5b813561228b6122148261341b565b8181529150602080830190848101818402860182018710156122ac57600080fd5b60005b84811015612262578135845292820192908201906001016122af565b600082601f8301126122db578081fd5b81356001600160401b038111156122f0578182fd5b612303601f8201601f19166020016133f5565b915080825283602082850101111561231a57600080fd5b8060208401602084013760009082016020015292915050565b600060208284031215612344578081fd5b813561075181613466565b60008060408385031215612361578081fd5b823561236c81613466565b9150602083013561237c81613466565b809150509250929050565b60008060006060848603121561239b578081fd5b83356123a681613466565b925060208401356123b681613466565b929592945050506040919091013590565b600080600080608085870312156123dc578182fd5b84356123e781613466565b935060208501356123f781613466565b92506040850135915060608501356001600160401b03811115612418578182fd5b612424878288016122cb565b91505092959194509250565b60008060408385031215612442578182fd5b823561244d81613466565b9150602083013561237c8161347b565b6000806040838503121561246f578182fd5b823561247a81613466565b946020939093013593505050565b60008060008060008060c087890312156124a0578384fd5b6124aa88886121eb565b95506020870135945060408701356001600160401b03808211156124cc578586fd5b6124d88a838b0161226d565b955060608901359150808211156124ed578384fd5b6124f98a838b016121f6565b9450608089013591508082111561250e578384fd5b61251a8a838b0161226d565b935060a089013591508082111561252f578283fd5b5061253c89828a0161226d565b9150509295509295509295565b6000806000806000806000806000806101408b8d031215612568578788fd5b8a51995060208b015161257a81613466565b60408c015190995061258b8161349f565b60608c015190985061259c8161349f565b60808c01519097506125ad8161349f565b60a08c01519096506125be8161347b565b8095505060c08b0151935060e08b015192506101008b015191506101208b015190509295989b9194979a5092959850565b600060208284031215612600578081fd5b813561075181613489565b60006020828403121561261c578081fd5b815161075181613489565b60008060006060848603121561263b578081fd5b833561264681613466565b9250602084013561265681613466565b9150604084013561266681613466565b809150509250925092565b600080600060608486031215612685578081fd5b833560058110612693578182fd5b92506020840135915060408401356001600160401b038111156126b4578182fd5b6126c0868287016122cb565b9150509250925092565b6000602082840312156126db578081fd5b81356001600160401b038111156126f0578182fd5b6118e8848285016122cb565b60006040828403121561270d578081fd5b61271760406133f5565b82516127228161347b565b81526020928301519281019290925250919050565b600060208284031215612748578081fd5b5035919050565b60008060408385031215612761578182fd5b8235915060208301356001600160401b0381111561277d578182fd5b6127898582860161226d565b9150509250929050565b600080604083850312156127a5578182fd5b8251602080850151919350906001600160401b038111156127c4578283fd5b80850186601f8201126127d5578384fd5b805191506127e56122148361341b565b82815283810190828501858502840186018a1015612801578687fd5b8693505b84841015612823578051835260019390930192918501918501612805565b5080955050505050509250929050565b600080600080600080600060e0888a03121561284d578081fd5b8735965060208801356001600160401b038082111561286a578283fd5b6128768b838c0161226d565b975060408a013591508082111561288b578283fd5b6128978b838c0161226d565b965060608a01359150808211156128ac578283fd5b6128b88b838c0161226d565b955060808a01359150808211156128cd578283fd5b6128d98b838c016121f6565b945060a08a01359150808211156128ee578283fd5b6128fa8b838c0161226d565b935060c08a013591508082111561290f578283fd5b5061291c8a828b0161226d565b91505092959891949750929550565b60008060006060848603121561293f578081fd5b8351925060208401519150604084015190509250925092565b6000815180845261297081602086016020860161343a565b601f01601f19169290920160200192915050565b94855260208501939093526040840191909152606090811b6001600160601b03191690830152151560f81b607482015260750190565b600082516129cc81846020870161343a565b9190910192915050565b600083516129e881846020880161343a565b83519083016129fb82826020880161343a565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612a4b90830184612958565b9695505050505050565b901515815260200190565b90815260200190565b6040810160058410612a7757fe5b9281526020015290565b6000602082526107516020830184612958565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526029908201527f4d61726b65747320636f756e7420616e64206f6363757272656e63657320646f6040820152680dc4ee840dac2e8c6d60bb1b606082015260800190565b6020808252601c908201527b115490cdcc8c4e881d1bdad95b88185b1c9958591e481b5a5b9d195960221b604082015260600190565b60208082526021908201527f7573657220646f6573206e6f7420686f6c64206f7574636f6d652073686172656040820152607360f81b606082015260800190565b60208082526024908201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526019908201527822a9219b99189d1030b8383937bb32903a379031b0b63632b960391b604082015260600190565b60208082526024908201527f626173655552492063616e206f6e6c7920626520696e697469616c697a6564206040820152636f6e636560e01b606082015260800190565b6020808252602c908201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b6020808252601e908201527f5f70726564696374696f6e4d61726b6574206164647265737320697320300000604082015260600190565b6020808252602a908201527f7265616c6974696f45524332302063616e206f6e6c7920626520696e697469616040820152696c697a6564206f6e636560b01b606082015260800190565b60208082526038908201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f776040820152771b995c881b9bdc88185c1c1c9bdd995908199bdc88185b1b60421b606082015260800190565b6020808252602a908201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604082015269726f206164647265737360b01b606082015260800190565b602080825260139082015272139bc81858dd1a5bdb9cc81c1c9bdd9a591959606a1b604082015260600190565b60208082526022908201527f456e756d657261626c654d61703a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b6020808252818101527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604082015260600190565b6020808252601c908201527b1b585c9ad95d081a185cc81b9bdd081899595b881c995cdbdb1d995960221b604082015260600190565b6020808252602d908201527f70726564696374696f6e4d61726b65742063616e206f6e6c7920626520696e6960408201526c7469616c697a6564206f6e636560981b606082015260800190565b60208082526030908201527f4d6574686f64206f6e6c79207573656420666f7220626f6e6420706c6163656d60408201526f656e7420616368696576656d656e747360801b606082015260800190565b6020808252602c908201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860408201526b34b9ba32b73a103a37b5b2b760a11b606082015260800190565b60208082526029908201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960408201526839903737ba1037bbb760b91b606082015260800190565b6020808252602f908201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60408201526e3732bc34b9ba32b73a103a37b5b2b760891b606082015260800190565b6020808252601a90820152791d5cd95c88191a59081b9bdd0818dc99585d19481b585c9ad95d60321b604082015260600190565b6020808252601b908201527a05f7265616c6974696f45524332302061646472657373206973203602c1b604082015260600190565b6020808252601a908201527924b73b30b634b21030b1b434b2bb32b6b2b73a1030b1ba34b7b760311b604082015260600190565b60208082526023908201527f7573657220646f6573206e6f7420686f6c64206c69717569646974792073686160408201526272657360e81b606082015260800190565b60208082526021908201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656040820152603960f91b606082015260800190565b60208082526026908201527f5f70726564696374696f6e4d61726b65745265736f6c7665722061646472657360408201526507320697320360d41b606082015260800190565b60208082526013908201527207573657220616464726573732069732030783606c1b604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601b908201527a1058da1a595d995b595b9d08185b1c9958591e4818db185a5b5959602a1b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526024908201527f7573657220686173206e6f7420706c61636564206120626f6e6420696e206d616040820152631c9ad95d60e21b606082015260800190565b60208082526029908201527f7573657220646f6573206e6f7420686f6c642077696e6e696e67206f7574636f6040820152686d652073686172657360b81b606082015260800190565b6020808252602f908201527f4d6574686f64206e6f74207573656420666f7220626f6e6420706c6163656d6560408201526e6e7420616368696576656d656e747360881b606082015260800190565b60208082526024908201527f6f6363757272656e6365732068617320746f20626520677265617465722074686040820152630616e20360e41b606082015260800190565b9182526001600160a01b0316602082015260400190565b6040518181016001600160401b038111828210171561341357600080fd5b604052919050565b60006001600160401b03821115613430578081fd5b5060209081020190565b60005b8381101561345557818101518382015260200161343d565b838111156113705750506000910152565b6001600160a01b038116811461098157600080fd5b801515811461098157600080fd5b6001600160e01b03198116811461098157600080fd5b63ffffffff8116811461098157600080fdfe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e7465724552433732313a206f776e657220717565727920666f72206e6f6e6578697374656e7420746f6b656eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220e731d2d277243cb26ce67dd65f8de00b43380526a9a0457ad6a480b5a9a8b17364736f6c63430006020033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000a49464c205469746c657300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000449464c5400000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : token (string): IFL Titles
Arg [1] : ticker (string): IFLT
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [3] : 49464c205469746c657300000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [5] : 49464c5400000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
178245:8933:0:-:0;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;178245:8933:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;147371:150;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;163555:100;;;:::i;:::-;;;;;;;;166341:221;;;;;;;;;:::i;:::-;;;;;;;;165871:404;;;;;;;;;:::i;:::-;;181443:513;;;;;;;;;:::i;165349:211::-;;;:::i;:::-;;;;;;;;167231:305;;;;;;;;;:::i;179361:51::-;;;;;;;;;:::i;:::-;;;;;;;;;165111:162;;;;;;;;;:::i;167607:151::-;;;;;;;;;:::i;181224:213::-;;;;;;;;;:::i;184206:1151::-;;;;;;;;;:::i;179417:41::-;;;;;;;;;:::i;165637:172::-;;;;;;;;;:::i;180503:171::-;;;;;;;;;:::i;163311:177::-;;;;;;;;;:::i;185363:1345::-;;;;;;;;;:::i;164930:97::-;;;:::i;178504:56::-;;;:::i;163028:221::-;;;;;;;;;:::i;182271:864::-;;;;;;;;;:::i;183141:619::-;;;;;;;;;:::i;163724:104::-;;;:::i;166634:295::-;;;;;;;;;:::i;179585:912::-;;;;;;;;;:::i;167829:285::-;;;;;;;;;:::i;163899:792::-;;;;;;;;;:::i;180680:538::-;;;;;;;;;:::i;178418:34::-;;;:::i;179321:35::-;;;:::i;187084:91::-;;;:::i;178457:42::-;;;:::i;181962:303::-;;;;;;;;;:::i;167000:164::-;;;;;;;;;:::i;183766:434::-;;;;;;;;;:::i;147371:150::-;-1:-1:-1;;;;;;147480:33:0;;147456:4;147480:33;;;;;;;;;;;;;147371:150;;;;:::o;163555:100::-;163642:5;163635:12;;;;;;;;-1:-1:-1;;163635:12:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;163609:13;;163635:12;;163642:5;;163635:12;;163642:5;163635:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;163555:100;;:::o;166341:221::-;166417:7;166445:16;166453:7;166445;:16::i;:::-;166437:73;;;;-1:-1:-1;;;166437:73:0;;;;;;;;;;;;;;;;;-1:-1:-1;166530:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;166530:24:0;;166341:221::o;165871:404::-;165952:13;165968:23;165983:7;165968:14;:23::i;:::-;165952:39;;166016:5;-1:-1:-1;;;;;166010:11:0;:2;-1:-1:-1;;;;;166010:11:0;;;166002:57;;;;-1:-1:-1;;;166002:57:0;;;;;;;;;166096:5;-1:-1:-1;;;;;166080:21:0;:12;:10;:12::i;:::-;-1:-1:-1;;;;;166080:21:0;;:69;;;;166105:44;166129:5;166136:12;:10;:12::i;166105:44::-;166072:161;;;;-1:-1:-1;;;166072:161:0;;;;;;;;;166246:21;166255:2;166259:7;166246:8;:21::i;:::-;165871:404;;;:::o;181443:513::-;181599:16;;:52;;-1:-1:-1;;;181599:52:0;;181529:4;;181542:30;;-1:-1:-1;;;;;181599:16:0;;;;:36;;:52;;181636:8;;181646:4;;181599:52;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;181599:52:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;181599:52:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;181599:52:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;181599:52:0;;;;;;;;;181579:72;-1:-1:-1;181660:24:0;;-1:-1:-1;181660:24:0;181693:156;181717:13;:20;181713:1;:24;181693:156;;;181776:1;181757:13;181771:1;181757:16;;;;;;;;;;;;;;:20;181753:89;;;181812:4;181790:26;;181827:5;;181753:89;181739:3;;181693:156;;;-1:-1:-1;181888:4:0;181865:27;;;;181857:73;;;;-1:-1:-1;;;181857:73:0;;;;;;;;;181946:4;181939:11;;;;181443:513;;;;;:::o;165349:211::-;165410:7;165531:21;:12;:19;:21::i;:::-;165524:28;;165349:211;:::o;167231:305::-;167392:41;167411:12;:10;:12::i;:::-;167425:7;167392:18;:41::i;:::-;167384:103;;;;-1:-1:-1;;;167384:103:0;;;;;;;;;167500:28;167510:4;167516:2;167520:7;167500:9;:28::i;179361:51::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;165111:162::-;-1:-1:-1;;;;;165235:20:0;;165208:7;165235:20;;;:13;:20;;;;;:30;;165259:5;165235:30;:23;:30;:::i;:::-;165228:37;165111:162;-1:-1:-1;;;165111:162:0:o;167607:151::-;167711:39;167728:4;167734:2;167738:7;167711:39;;;;;;;;;;;;:16;:39::i;181224:213::-;181317:4;181364:27;;;:12;:27;;;;;;;;-1:-1:-1;;;;;181407:24:0;;;;;;:18;;;;:24;;;;;;;181224:213::o;184206:1151::-;184299:7;184349:27;;;:12;:27;;;;;;;;184412:10;184393:30;;:18;;;:30;;;;;;;;:39;184385:79;;;;-1:-1:-1;;;184385:79:0;;;;;;;;;184501:11;184479:18;;;;:33;;;;;;;;;;184471:93;;;;-1:-1:-1;;;184471:93:0;;;;;;;;;184599:11;:23;;;184579:9;:16;:43;184571:97;;;;-1:-1:-1;;;184571:97:0;;;;;;;;;184682:9;184677:624;184701:9;:16;184697:1;:20;184677:624;;;184733:16;184752:9;184762:1;184752:12;;;;;;;;;;;;;;184733:31;;184801:10;184779:32;;;;;;;;:18;;;;:32;;;;;;;;;184775:519;;;184824:45;184848:10;184860:8;184824:23;:45::i;:::-;;184775:519;;;184911:19;184889:18;;;;:41;;;;;;;;;184885:409;;;184943:43;184965:10;184977:8;184943:21;:43::i;184885:409::-;185028:20;185006:18;;;;:42;;;;;;;;;185002:292;;;185061:44;185084:10;185096:8;185061:22;:44::i;185002:292::-;185147:19;185125:18;;;;:41;;;;;;;;;185121:173;;;185179:42;185200:10;185212:8;185179:20;:42::i;185121:173::-;185248:36;;-1:-1:-1;;;185248:36:0;;;;;;;;185121:173;-1:-1:-1;184719:3:0;;184677:624;;;;185309:42;185325:10;185337:13;185309:15;:42::i;:::-;;184206:1151;;;;;:::o;179417:41::-;;;;;;;;;;;;;:::o;165637:172::-;165712:7;;165754:22;:12;165770:5;165754:22;:15;:22;:::i;:::-;-1:-1:-1;165732:44:0;165637:172;-1:-1:-1;;;165637:172:0:o;180503:171::-;180575:9;:7;:9::i;:::-;180569:23;:28;180561:77;;;;-1:-1:-1;;;180561:77:0;;;;;;;;;180647:21;180659:8;180647:11;:21::i;:::-;180503:171;:::o;163311:177::-;163383:7;163410:70;163427:7;163410:70;;;;;;;;;;;;;;;;;:12;;:70;;:16;:70;:::i;185363:1345::-;185627:31;185661:27;;;:12;:27;;;;;;;;185724:10;185705:30;;:18;;;:30;;;;;;;;;:39;185697:79;;;;-1:-1:-1;;;185697:79:0;;;;;;;;;185813:11;185791:18;;;;:33;;;;;;;;;185783:94;;;;-1:-1:-1;;;185783:94:0;;;;;;;;;185911:1;185892:9;:16;:20;185884:52;;;;-1:-1:-1;;;185884:52:0;;;;;;;;;185971:11;:23;;;185951:9;:16;:43;185943:97;;;;-1:-1:-1;;;185943:97:0;;;;;;;;;186049:10;;186068:584;186092:9;:16;186088:1;:20;186068:584;;;186124:16;186143:9;186153:1;186143:12;;;;;;;;;;;;;;186124:31;;186166:10;186179:7;186187:1;186179:10;;;;;;;;;;;;;;186166:23;;186198:19;186234:2;186220:17;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;186220:17:0;;186198:39;;186246:19;186282:2;186268:17;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;186268:17:0;;186246:39;;186294:19;186330:2;186316:17;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;186316:17:0;;186294:39;;186342:19;186378:2;186364:17;;;;;;;;;;;;;;;;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;186364:17:0;-1:-1:-1;186342:39:0;-1:-1:-1;186390:9:0;186408:173;186424:2;186420:1;:6;186408:173;;;186452:14;186467:2;186452:18;;;;;;;;;;;;;;186444:2;186447:1;186444:5;;;;;;;;;;;;;:26;;;;;186489:5;186495:2;186489:9;;;;;;;;;;;;;;186481:2;186484:1;186481:5;;;;;;;;;;;;;:17;-1:-1:-1;;;;;186481:17:0;;;-1:-1:-1;;;;;186481:17:0;;;;;186517:5;186523:2;186517:9;;;;;;;;;;;;;;186509:2;186512:1;186509:5;;;;;;;;;;;;;:17;;;;;186545:7;186553:2;186545:11;;;;;;;;;;;;;;186537:2;186540:1;186537:5;;;;;;;;;;;;;;;;;:19;186567:4;;;;;186428:3;186408:173;;;186589:55;186607:10;186619:8;186629:2;186633;186637;186641;186589:17;:55::i;:::-;-1:-1:-1;;186110:3:0;;;;;-1:-1:-1;186068:584:0;;-1:-1:-1;;;;;186068:584:0;;;186660:42;186676:10;186688:13;186660:15;:42::i;:::-;;185363:1345;;;;;;;;;:::o;164930:97::-;165011:8;165004:15;;;;;;;;-1:-1:-1;;165004:15:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;164978:13;;165004:15;;165011:8;;165004:15;;165011:8;165004:15;;;;;;;;;;;;;;;;;;;;;;;;178504:56;;;-1:-1:-1;;;;;178504:56:0;;:::o;163028:221::-;163100:7;-1:-1:-1;;;;;163128:19:0;;163120:74;;;;-1:-1:-1;;;163120:74:0;;;;;;;;;-1:-1:-1;;;;;163212:20:0;;;;;;:13;:20;;;;;:29;;:27;:29::i;182271:864::-;182582:16;;:43;;-1:-1:-1;;;182582:43:0;;182493:4;;;;;;-1:-1:-1;;;;;182582:16:0;;:33;;:43;;182616:8;;182582:43;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;182582:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;182582:43: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;182582:43:0;;;;;;;;;-1:-1:-1;182672:13:0;;:35;;-1:-1:-1;;;182672:35:0;;182563:62;;-1:-1:-1;;;;;;182672:13:0;;-1:-1:-1;182672:23:0;;:35;;182563:62;;182672:35;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;182672:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;182672:35: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;182672:35:0;;;;;;;;;-1:-1:-1;182632:75:0;-1:-1:-1;182714:11:0;;-1:-1:-1;182714:11:0;;-1:-1:-1;;;;;;;182750:288:0;182766:14;:21;182762:1;:25;182750:288;;;182869:14;182884:1;182869:17;;;;;;;;;;;;;;182888:7;182896:1;182888:10;;;;;;;;;;;;;;182900:5;182906:1;182900:8;;;;;;;;;;;;;;182910:5;182916:1;182910:8;;;;;;;;;;;;;;182920:5;182852:74;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;182852:74:0;;;182842:85;;;;;;182821:17;:106;182803:133;;;;;;182963:4;-1:-1:-1;;;;;182951:16:0;:5;182957:1;182951:8;;;;;;;;;;;;;;-1:-1:-1;;;;;182951:16:0;;182947:35;;;182978:4;182969:13;;182947:35;183013:14;183028:1;183013:17;;;;;;;;;;;;;;;;;;;-1:-1:-1;182789:3:0;;182750:288;;;183064:4;183054:14;;;;183046:63;;;;-1:-1:-1;;;183046:63:0;;;;;;;;;-1:-1:-1;183125:4:0;;182271:864;-1:-1:-1;;;;;;;;;;182271:864:0:o;183141:619::-;183296:16;;:52;;-1:-1:-1;;;183296:52:0;;183226:4;;183239:30;;-1:-1:-1;;;;;183296:16:0;;;;:36;;:52;;183333:8;;183343:4;;183296:52;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;183296:52:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;183296:52:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;183296:52:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;183296:52:0;;;;;;;;;183276:72;-1:-1:-1;183355:65:0;;-1:-1:-1;183355:65:0;:::i;:::-;183423:24;;:68;;-1:-1:-1;;;183423:68:0;;-1:-1:-1;;;;;183423:24:0;;;;:44;;:68;;183476:8;;183423:68;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;183423:68:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;183423:68: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;183423:68:0;;;;;;;;;183528:26;;;;183571:25;;183528:26;;-1:-1:-1;183528:26:0;183571:33;;183600:4;183571:33;183563:74;;;;-1:-1:-1;;;183563:74:0;;;;;;;;;183687:1;183652:13;183666:17;183652:32;;;;;;;;;;;;;;:36;183644:90;;;;-1:-1:-1;;;183644:90:0;;;;;;;;;-1:-1:-1;183750:4:0;;183141:619;-1:-1:-1;;;;;183141:619:0:o;163724:104::-;163813:7;163806:14;;;;;;;;-1:-1:-1;;163806:14:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;163780:13;;163806:14;;163813:7;;163806:14;;163813:7;163806:14;;;;;;;;;;;;;;;;;;;;;;;;166634:295;166749:12;:10;:12::i;:::-;-1:-1:-1;;;;;166737:24:0;:8;-1:-1:-1;;;;;166737:24:0;;;166729:62;;;;-1:-1:-1;;;166729:62:0;;;;;;;;;166849:8;166804:18;:32;166823:12;:10;:12::i;:::-;-1:-1:-1;;;;;166804:32:0;;;;;;;;;;;;;;;;;-1:-1:-1;166804:32:0;;;:42;;;;;;;;;;;;:53;;-1:-1:-1;;166804:53:0;;;;;;;;;;;166888:12;:10;:12::i;:::-;-1:-1:-1;;;;;166873:48:0;;166912:8;166873:48;;;;;;;;;;;;;;;166634:295;;:::o;179585:912::-;179777:16;;-1:-1:-1;;;;;179777:16:0;179769:39;179761:97;;;;-1:-1:-1;;;179761:97:0;;;;;;;;;179881:24;;-1:-1:-1;;;;;179881:24:0;179873:47;179865:105;;;;-1:-1:-1;;;179865:105:0;;;;;;;;;179993:13;;-1:-1:-1;;;;;179993:13:0;179985:36;179977:91;;;;-1:-1:-1;;;179977:91:0;;;;;;;;;-1:-1:-1;;;;;180085:40:0;;180077:83;;;;-1:-1:-1;;;180077:83:0;;;;;;;;;-1:-1:-1;;;;;180175:48:0;;180167:99;;;;-1:-1:-1;;;180167:99:0;;;;;;;;;-1:-1:-1;;;;;180281:37:0;;180273:77;;;;-1:-1:-1;;;180273:77:0;;;;;;;;;180359:16;:36;;-1:-1:-1;;;;;180359:36:0;;;-1:-1:-1;;;;;;180359:36:0;;;;;;;180402:24;:52;;;;;;;;;;;;;;;180461:13;:30;;;;;;;;;;;179585:912::o;167829:285::-;167961:41;167980:12;:10;:12::i;:::-;167994:7;167961:18;:41::i;:::-;167953:103;;;;-1:-1:-1;;;167953:103:0;;;;;;;;;168067:39;168081:4;168087:2;168091:7;168100:5;168067:13;:39::i;:::-;167829:285;;;;:::o;163899:792::-;163972:13;164006:16;164014:7;164006;:16::i;:::-;163998:76;;;;-1:-1:-1;;;163998:76:0;;;;;;;;;164113:19;;;;:10;:19;;;;;;;;;164087:45;;;;;;-1:-1:-1;;164087:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:23;;:45;;;164113:19;164087:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;164143:18;164164:9;:7;:9::i;:::-;164143:30;;164255:4;164249:18;164271:1;164249:23;164245:72;;;-1:-1:-1;164296:9:0;-1:-1:-1;164289:16:0;;164245:72;164421:23;;:27;164417:108;;164496:4;164502:9;164479:33;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;164479:33:0;;;164465:48;;;;;;164417:108;164657:4;164663:18;:7;:16;:18::i;:::-;164640:42;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;164640:42:0;;;164626:57;;;;163899:792;;;:::o;180680:538::-;180802:7;180840:1;180826:11;:15;180818:64;;;;-1:-1:-1;;;180818:64:0;;;;;;;;;180913:16;;180889:21;180970:27;;;:12;:27;;;;;181006;;181027:6;;180970:27;;-1:-1:-1;;181006:27:0;;181027:6;181006:27;;;;;;;;;;;;-1:-1:-1;181040:23:0;;;:37;;;181089:53;;181122:10;;181107:13;;181089:53;;;;181134:7;;181089:53;;;;;;;;;;-1:-1:-1;181184:1:0;181168:17;;181149:16;:36;181168:17;180680:538;-1:-1:-1;;;;180680:538:0:o;178418:34::-;;;-1:-1:-1;;;;;178418:34:0;;:::o;179321:35::-;;;;:::o;187084:91::-;187127:7;187150:19;:9;:17;:19::i;178457:42::-;;;-1:-1:-1;;;;;178457:42:0;;:::o;181962:303::-;182111:16;;:52;;-1:-1:-1;;;182111:52:0;;182046:4;;;;-1:-1:-1;;;;;182111:16:0;;;;:36;;:52;;182148:8;;182158:4;;182111:52;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;182111:52:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;182111:52:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;182111:52:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;182111:52:0;;;;;;;;;-1:-1:-1;182089:74:0;-1:-1:-1;182180:19:0;182172:67;;;;-1:-1:-1;;;182172:67:0;;;;;;;;;-1:-1:-1;182255:4:0;;181962:303;-1:-1:-1;;;181962:303:0:o;167000:164::-;-1:-1:-1;;;;;167121:25:0;;;167097:4;167121:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;167000:164::o;183766:434::-;183849:4;-1:-1:-1;;;;;183870:18:0;;183862:50;;;;-1:-1:-1;;;183862:50:0;;;;;;;;;183990:16;;:43;;-1:-1:-1;;;183990:43:0;;183921:18;;;;-1:-1:-1;;;;;183990:16:0;;;;:33;;:43;;184024:8;;183990:43;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;183990:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;183990:43: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;183990:43:0;;;;;;;;;-1:-1:-1;184073:13:0;;:35;;-1:-1:-1;;;184073:35:0;;183971:62;;-1:-1:-1;;;;;;184073:13:0;;-1:-1:-1;184073:23:0;;:35;;183971:62;;184073:35;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;184073:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;184073:35: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;184073:35:0;;;;;;;;;-1:-1:-1;184040:68:0;;-1:-1:-1;;;;;;;;;184125:18:0;;;;;;;;-1:-1:-1;184117:57:0;;-1:-1:-1;;;;184117:57:0;;;-1:-1:-1;;;184117:57:0;;;;;;;;169581:127;169646:4;169670:30;:12;169692:7;169670:30;:21;:30;:::i;101687:106::-;101775:10;101687:106;:::o;175599:192::-;175674:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;175674:29:0;-1:-1:-1;;;;;175674:29:0;;;;;;;;:24;;175728:23;175674:24;175728:14;:23::i;:::-;-1:-1:-1;;;;;175719:46:0;;;;;;;;;;;175599:192;;:::o;156232:123::-;156301:7;156328:19;156336:3;156328:7;:19::i;169875:355::-;169968:4;169993:16;170001:7;169993;:16::i;:::-;169985:73;;;;-1:-1:-1;;;169985:73:0;;;;;;;;;170069:13;170085:23;170100:7;170085:14;:23::i;:::-;170069:39;;170138:5;-1:-1:-1;;;;;170127:16:0;:7;-1:-1:-1;;;;;170127:16:0;;:51;;;;170171:7;-1:-1:-1;;;;;170147:31:0;:20;170159:7;170147:11;:20::i;:::-;-1:-1:-1;;;;;170147:31:0;;170127:51;:94;;;;170182:39;170206:5;170213:7;170182:23;:39::i;:::-;170119:103;169875:355;-1:-1:-1;;;;169875:355:0:o;173011:599::-;173136:4;-1:-1:-1;;;;;173109:31:0;:23;173124:7;173109:14;:23::i;:::-;-1:-1:-1;;;;;173109:31:0;;173101:85;;;;-1:-1:-1;;;173101:85:0;;;;;;;;;-1:-1:-1;;;;;173223:16:0;;173215:65;;;;-1:-1:-1;;;173215:65:0;;;;;;;;;173293:39;173314:4;173320:2;173324:7;173293:20;:39::i;:::-;173397:29;173414:1;173418:7;173397:8;:29::i;:::-;-1:-1:-1;;;;;173439:19:0;;;;;;:13;:19;;;;;:35;;173466:7;173439:35;:26;:35;:::i;:::-;-1:-1:-1;;;;;;173485:17:0;;;;;;:13;:17;;;;;:30;;173507:7;173485:30;:21;:30;:::i;:::-;-1:-1:-1;173528:29:0;:12;173545:7;173554:2;173528:29;:16;:29;:::i;:::-;;173594:7;173590:2;-1:-1:-1;;;;;173575:27:0;173584:4;-1:-1:-1;;;;;173575:27:0;-1:-1:-1;;;;;;;;;;;173575:27:0;;;;;;;;;173011:599;;;:::o;92812:137::-;92883:7;92918:22;92922:3;92934:5;92918:3;:22::i;186714:364::-;186793:7;186809:21;:9;:19;:21::i;:::-;186839:15;186857:19;:9;:17;:19::i;:::-;186839:37;;186883:20;186889:4;186895:7;186883:5;:20::i;:::-;186910:15;;;;:6;:15;;;;;;;;:31;;;186984:27;;;:12;:27;;;;;-1:-1:-1;;;;;187018:24:0;;;;:18;;:24;;;;;:31;;-1:-1:-1;;187018:31:0;187045:4;187018:31;;;186917:7;-1:-1:-1;186714:364:0;;;;:::o;156694:236::-;156774:7;;;;156834:22;156838:3;156850:5;156834:3;:22::i;:::-;156803:53;;;;-1:-1:-1;156694:236:0;-1:-1:-1;;;;;156694:236:0:o;174211:100::-;174284:19;;;;:8;;:19;;;;;:::i;:::-;;174211:100;:::o;157980:213::-;158087:7;158138:44;158143:3;158163;158169:12;158138:4;:44::i;168996:272::-;169110:28;169120:4;169126:2;169130:7;169110:9;:28::i;:::-;169157:48;169180:4;169186:2;169190:7;169199:5;169157:22;:48::i;:::-;169149:111;;;;-1:-1:-1;;;169149:111:0;;;;;;;;158475:746;158531:13;158752:10;158748:53;;-1:-1:-1;158779:10:0;;;;;;;;;;;;-1:-1:-1;;;158779:10:0;;;;;;158748:53;158826:5;158811:12;158867:78;158874:9;;158867:78;;158900:8;;158931:2;158923:10;;;;158867:78;;;158955:19;158987:6;158977:17;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;158977:17:0;87:34:-1;135:17;;-1:-1;158977:17:0;-1:-1:-1;159049:5:0;;-1:-1:-1;158955:39:0;-1:-1:-1;;;159021:10:0;;159065:117;159072:9;;159065:117;;159141:2;159134:4;:9;159129:2;:14;159116:29;;159098:6;159105:7;;;;;;;159098:15;;;;;;;;;;;:47;-1:-1:-1;;;;;159098:47:0;;;;;;;;-1:-1:-1;159168:2:0;159160:10;;;;159065:117;;;-1:-1:-1;159206:6:0;158475:746;-1:-1:-1;;;;158475:746:0:o;177660:114::-;177752:14;;177660:114::o;155993:151::-;156077:4;156101:35;156111:3;156131;156101:9;:35::i;91899:137::-;91969:4;91993:35;92001:3;92021:5;91993:7;:35::i;91592:131::-;91659:4;91683:32;91688:3;91708:5;91683:4;:32::i;155416:185::-;155505:4;155529:64;155534:3;155554;-1:-1:-1;;;;;155568:23:0;;155529:4;:64::i;87850:204::-;87945:18;;87917:7;;87945:26;-1:-1:-1;87937:73:0;;;;-1:-1:-1;;;87937:73:0;;;;;;;;;88028:3;:11;;88040:5;88028:18;;;;;;;;;;;;;;;;88021:25;;87850:204;;;;:::o;177782:181::-;177936:19;;177954:1;177936:19;;;177782:181::o;171496:404::-;-1:-1:-1;;;;;171576:16:0;;171568:61;;;;-1:-1:-1;;;171568:61:0;;;;;;;;;171649:16;171657:7;171649;:16::i;:::-;171648:17;171640:58;;;;-1:-1:-1;;;171640:58:0;;;;;;;;;171711:45;171740:1;171744:2;171748:7;171711:20;:45::i;:::-;-1:-1:-1;;;;;171769:17:0;;;;;;:13;:17;;;;;:30;;171791:7;171769:30;:21;:30;:::i;:::-;-1:-1:-1;171812:29:0;:12;171829:7;171838:2;171812:29;:16;:29;:::i;:::-;-1:-1:-1;171859:33:0;;171884:7;;-1:-1:-1;;;;;171859:33:0;;;171876:1;;-1:-1:-1;;;;;;;;;;;171859:33:0;171876:1;;171859:33;171496:404;;:::o;153276:279::-;153380:19;;153343:7;;;;153380:27;-1:-1:-1;153372:74:0;;;;-1:-1:-1;;;153372:74:0;;;;;;;;;153459:22;153484:3;:12;;153497:5;153484:19;;;;;;;;;;;;;;;;;;153459:44;;153522:5;:10;;;153534:5;:12;;;153514:33;;;;;153276:279;;;;;:::o;154773:319::-;154867:7;154906:17;;;:12;;;:17;;;;;;154957:12;154942:13;154934:36;;;;-1:-1:-1;;;154934:36:0;;;;;;;;;;;155024:3;:12;;155048:1;155037:8;:12;155024:26;;;;;;;;;;;;;;;;;;:33;;;155017:40;;;154773:319;;;;;:::o;174876:604::-;174997:4;175024:15;:2;-1:-1:-1;;;;;175024:13:0;;:15::i;:::-;175019:60;;-1:-1:-1;175063:4:0;175056:11;;175019:60;175089:23;175115:252;-1:-1:-1;;;175228:12:0;:10;:12::i;:::-;175255:4;175274:7;175296:5;175131:181;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;175131:181:0;;;;-1:-1:-1;;;;;175131:181:0;;38:4:-1;29:7;25:18;67:10;61:17;-1:-1;;;;;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;175131:181:0;175115:252;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;175115:15:0;;;:252;;:15;:252;:::i;:::-;175089:278;;175378:13;175405:10;175394:32;;;;;;;;;;;;;;-1:-1:-1;;;;;;175445:26:0;-1:-1:-1;;;175445:26:0;;-1:-1:-1;;;174876:604:0;;;;;;:::o;152591:125::-;152662:4;152686:17;;;:12;;;;;:17;;;;;;:22;;;152591:125::o;85552:1544::-;85618:4;85757:19;;;:12;;;:19;;;;;;85793:15;;85789:1300;;86228:18;;-1:-1:-1;;86179:14:0;;;;86228:22;;;;86155:21;;86228:3;;:22;;86515;;;;;;;;;;;;;;86495:42;;86661:9;86632:3;:11;;86644:13;86632:26;;;;;;;;;;;;;;;;;;;:38;;;;86738:23;;;86780:1;86738:12;;;:23;;;;;;86764:17;;;86738:43;;86890:17;;86738:3;;86890:17;;;;;;;;;;;;;;;;;;;;;;86985:3;:12;;:19;86998:5;86985:19;;;;;;;;;;;86978:26;;;87028:4;87021:11;;;;;;;;85789:1300;87072:5;87065:12;;;;;84962:414;85025:4;85047:21;85057:3;85062:5;85047:9;:21::i;:::-;85042:327;;-1:-1:-1;27:10;;39:1;23:18;;;45:23;;85085:11:0;:23;;;;;;;;;;;;;85268:18;;85246:19;;;:12;;;:19;;;;;;:40;;;;85301:11;;85042:327;-1:-1:-1;85352:5:0;85345:12;;150091:692;150167:4;150302:17;;;:12;;;:17;;;;;;150336:13;150332:444;;-1:-1:-1;;150421:38:0;;;;;;;;;;;;;;;;;;27:10:-1;;39:1;23:18;;;45:23;;150403:12:0;:57;;;;;;;;;;;;;;;;;;;;;;;;150618:19;;150598:17;;;:12;;;:17;;;;;;;:39;150652:11;;150332:444;150732:5;150696:3;:12;;150720:1;150709:8;:12;150696:26;;;;;;;;;;;;;;;;;;:33;;:41;;;;150759:5;150752:12;;;;;93761:422;94128:20;94167:8;;;93761:422::o;96679:195::-;96782:12;96814:52;96836:6;96844:4;96850:1;96853:12;96782;97983:18;97994:6;97983:10;:18::i;:::-;97975:60;;;;-1:-1:-1;;;97975:60:0;;;;;;;;;98109:12;98123:23;98150:6;-1:-1:-1;;;;;98150:11:0;98170:5;98178:4;98150:33;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;98108:75:0;;;;98201:52;98219:7;98228:10;98240:12;98201:17;:52::i;:::-;98194:59;97731:530;-1:-1:-1;;;;;;;97731:530:0:o;100271:742::-;100386:12;100415:7;100411:595;;;-1:-1:-1;100446:10:0;100439:17;;100411:595;100560:17;;:21;100556:439;;100823:10;100817:17;100884:15;100871:10;100867:2;100863:19;100856:44;100771:148;100966:12;100959:20;;-1:-1:-1;;;100959:20:0;;;;;;;;;178245:8933;;;;;;;;;;-1:-1:-1;178245:8933:0;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;178245:8933:0;;;-1:-1:-1;178245:8933:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;5:130:-1;72:20;;97:33;72:20;97:33;;301:707;;418:3;411:4;403:6;399:17;395:27;385:2;;-1:-1;;426:12;385:2;473:6;460:20;495:80;510:64;567:6;510:64;;;495:80;;;603:21;;;486:89;-1:-1;647:4;660:14;;;;635:17;;;749;;;740:27;;;;737:36;-1:-1;734:2;;;786:1;;776:12;734:2;811:1;796:206;821:6;818:1;815:13;796:206;;;85:6;72:20;97:33;124:5;97:33;;;889:50;;953:14;;;;981;;;;843:1;836:9;796:206;;;800:14;;;;;378:630;;;;;1034:707;;1151:3;1144:4;1136:6;1132:17;1128:27;1118:2;;-1:-1;;1159:12;1118:2;1206:6;1193:20;1228:80;1243:64;1300:6;1243:64;;1228:80;1336:21;;;1219:89;-1:-1;1380:4;1393:14;;;;1368:17;;;1482;;;1473:27;;;;1470:36;-1:-1;1467:2;;;1519:1;;1509:12;1467:2;1544:1;1529:206;1554:6;1551:1;1548:13;1529:206;;;3563:20;;1622:50;;1686:14;;;;1714;;;;1576:1;1569:9;1529:206;;4049:440;;4150:3;4143:4;4135:6;4131:17;4127:27;4117:2;;-1:-1;;4158:12;4117:2;4192:20;;-1:-1;;;;;56906:30;;56903:2;;;-1:-1;;56939:12;56903:2;4227:64;57012:9;56993:17;;-1:-1;;56989:33;57080:4;57070:15;4227:64;;;4218:73;;4311:6;4304:5;4297:21;4415:3;57080:4;4406:6;4339;4397:16;;4394:25;4391:2;;;4432:1;;4422:12;4391:2;60873:6;57080:4;4339:6;4335:17;57080:4;4373:5;4369:16;60850:30;60929:1;60911:16;;;57080:4;60911:16;60904:27;4373:5;4110:379;-1:-1;;4110:379;6678:241;;6782:2;6770:9;6761:7;6757:23;6753:32;6750:2;;;-1:-1;;6788:12;6750:2;85:6;72:20;97:33;124:5;97:33;;6926:366;;;7047:2;7035:9;7026:7;7022:23;7018:32;7015:2;;;-1:-1;;7053:12;7015:2;85:6;72:20;97:33;124:5;97:33;;;7105:63;-1:-1;7205:2;7244:22;;72:20;97:33;72:20;97:33;;;7213:63;;;;7009:283;;;;;;7299:491;;;;7437:2;7425:9;7416:7;7412:23;7408:32;7405:2;;;-1:-1;;7443:12;7405:2;85:6;72:20;97:33;124:5;97:33;;;7495:63;-1:-1;7595:2;7634:22;;72:20;97:33;72:20;97:33;;;7399:391;;7603:63;;-1:-1;;;7703:2;7742:22;;;;6328:20;;7399:391;7797:721;;;;;7961:3;7949:9;7940:7;7936:23;7932:33;7929:2;;;-1:-1;;7968:12;7929:2;85:6;72:20;97:33;124:5;97:33;;;8020:63;-1:-1;8120:2;8159:22;;72:20;97:33;72:20;97:33;;;8128:63;-1:-1;8228:2;8267:22;;6328:20;;-1:-1;8364:2;8349:18;;8336:32;-1:-1;;;;;8377:30;;8374:2;;;-1:-1;;8410:12;8374:2;8440:62;8494:7;8485:6;8474:9;8470:22;8440:62;;;8430:72;;;7923:595;;;;;;;;8525:360;;;8643:2;8631:9;8622:7;8618:23;8614:32;8611:2;;;-1:-1;;8649:12;8611:2;85:6;72:20;97:33;124:5;97:33;;;8701:63;-1:-1;8801:2;8837:22;;3294:20;3319:30;3294:20;3319:30;;8892:366;;;9013:2;9001:9;8992:7;8988:23;8984:32;8981:2;;;-1:-1;;9019:12;8981:2;85:6;72:20;97:33;124:5;97:33;;;9071:63;9171:2;9210:22;;;;6328:20;;-1:-1;;;8975:283;9265:1413;;;;;;;9554:3;9542:9;9533:7;9529:23;9525:33;9522:2;;;-1:-1;;9561:12;9522:2;9623:53;9668:7;9644:22;9623:53;;;9613:63;-1:-1;9713:2;9752:22;;6328:20;;-1:-1;9849:2;9834:18;;9821:32;-1:-1;;;;;9862:30;;;9859:2;;;-1:-1;;9895:12;9859:2;9925:78;9995:7;9986:6;9975:9;9971:22;9925:78;;;9915:88;;10068:2;10057:9;10053:18;10040:32;10026:46;;9873:18;10084:6;10081:30;10078:2;;;-1:-1;;10114:12;10078:2;10144:78;10214:7;10205:6;10194:9;10190:22;10144:78;;;10134:88;;10287:3;10276:9;10272:19;10259:33;10245:47;;9873:18;10304:6;10301:30;10298:2;;;-1:-1;;10334:12;10298:2;10364:78;10434:7;10425:6;10414:9;10410:22;10364:78;;;10354:88;;10507:3;10496:9;10492:19;10479:33;10465:47;;9873:18;10524:6;10521:30;10518:2;;;-1:-1;;10554:12;10518:2;;10584:78;10654:7;10645:6;10634:9;10630:22;10584:78;;;10574:88;;;9516:1162;;;;;;;;;10685:1482;;;;;;;;;;;10947:3;10935:9;10926:7;10922:23;10918:33;10915:2;;;-1:-1;;10954:12;10915:2;3717:6;3711:13;11006:74;;11117:2;11171:9;11167:22;220:13;238:33;265:5;238:33;;;11236:2;11285:22;;6616:13;11125:74;;-1:-1;6634:32;6616:13;6634:32;;;11354:2;11403:22;;6616:13;11244:73;;-1:-1;6634:32;6616:13;6634:32;;;11472:3;11522:22;;6616:13;11362:73;;-1:-1;6634:32;6616:13;6634:32;;;11591:3;11639:22;;3436:13;11481:73;;-1:-1;3454:30;3436:13;3454:30;;;11600:71;;;;11708:3;11763:9;11759:22;6476:13;11717:74;;11828:3;11883:9;11879:22;3711:13;11837:74;;11948:3;12003:9;11999:22;3711:13;11957:74;;12068:3;12123:9;12119:22;6476:13;12077:74;;10909:1258;;;;;;;;;;;;;;12174:239;;12277:2;12265:9;12256:7;12252:23;12248:32;12245:2;;;-1:-1;;12283:12;12245:2;3853:6;3840:20;3865:32;3891:5;3865:32;;12420:261;;12534:2;12522:9;12513:7;12509:23;12505:32;12502:2;;;-1:-1;;12540:12;12502:2;3992:6;3986:13;4004:32;4030:5;4004:32;;12688:655;;;;12908:2;12896:9;12887:7;12883:23;12879:32;12876:2;;;-1:-1;;12914:12;12876:2;4807:6;4794:20;4819:60;4873:5;4819:60;;;12966:90;-1:-1;13093:2;13165:22;;4597:20;4622:66;4597:20;4622:66;;;13101:96;-1:-1;13234:2;13295:22;;4980:20;5005:55;4980:20;5005:55;;;13242:85;;;;12870:473;;;;;;13350:621;;;;13510:2;13498:9;13489:7;13485:23;13481:32;13478:2;;;-1:-1;;13516:12;13478:2;5164:6;5151:20;63300:1;63293:5;63290:12;63280:2;;-1:-1;;63306:12;63280:2;13568:75;-1:-1;13680:2;13719:22;;6328:20;;-1:-1;13816:2;13801:18;;13788:32;-1:-1;;;;;13829:30;;13826:2;;;-1:-1;;13862:12;13826:2;13892:63;13947:7;13938:6;13927:9;13923:22;13892:63;;;13882:73;;;13472:499;;;;;;13978:347;;14092:2;14080:9;14071:7;14067:23;14063:32;14060:2;;;-1:-1;;14098:12;14060:2;14143:31;;-1:-1;;;;;14183:30;;14180:2;;;-1:-1;;14216:12;14180:2;14246:63;14301:7;14292:6;14281:9;14277:22;14246:63;;14332:331;;14481:2;14469:9;14460:7;14456:23;14452:32;14449:2;;;-1:-1;;14487:12;14449:2;5909:20;14481:2;5909:20;;;3442:6;3436:13;3454:30;3478:5;3454:30;;;5990:83;;6139:2;6204:22;;;6476:13;6154:16;;;6147:86;;;;-1:-1;5997:16;14443:220;-1:-1;14443:220;14670:241;;14774:2;14762:9;14753:7;14749:23;14745:32;14742:2;;;-1:-1;;14780:12;14742:2;-1:-1;6328:20;;14736:175;-1:-1;14736:175;14918:502;;;15064:2;15052:9;15043:7;15039:23;15035:32;15032:2;;;-1:-1;;15070:12;15032:2;6328:20;;;-1:-1;15250:2;15235:18;;15222:32;-1:-1;;;;;15263:30;;15260:2;;;-1:-1;;15296:12;15260:2;15326:78;15396:7;15387:6;15376:9;15372:22;15326:78;;;15316:88;;;15026:394;;;;;;15427:528;;;15584:2;15572:9;15563:7;15559:23;15555:32;15552:2;;;-1:-1;;15590:12;15552:2;6476:13;;15774:2;15759:18;;;15753:25;6476:13;;-1:-1;15774:2;-1:-1;;;;;15787:30;;15784:2;;;-1:-1;;15820:12;15784:2;15922:6;15911:9;15907:22;2628:3;2621:4;2613:6;2609:17;2605:27;2595:2;;-1:-1;;2636:12;2595:2;2676:6;2670:13;2656:27;;2698:80;2713:64;2770:6;2713:64;;2698:80;2806:21;;;2863:14;;;;2838:17;;;2952;;;2943:27;;;;2940:36;-1:-1;2937:2;;;-1:-1;;2979:12;2937:2;-1:-1;3005:10;;2999:217;3024:6;3021:1;3018:13;2999:217;;;6476:13;;3092:61;;3046:1;3039:9;;;;;3167:14;;;;3195;;2999:217;;;3003:14;15840:99;;;;;;;;15546:409;;;;;;15962:1811;;;;;;;;16318:3;16306:9;16297:7;16293:23;16289:33;16286:2;;;-1:-1;;16325:12;16286:2;6328:20;;;-1:-1;16505:2;16490:18;;16477:32;-1:-1;;;;;16518:30;;;16515:2;;;-1:-1;;16551:12;16515:2;16581:78;16651:7;16642:6;16631:9;16627:22;16581:78;;;16571:88;;16724:2;16713:9;16709:18;16696:32;16682:46;;16529:18;16740:6;16737:30;16734:2;;;-1:-1;;16770:12;16734:2;16800:78;16870:7;16861:6;16850:9;16846:22;16800:78;;;16790:88;;16943:2;16932:9;16928:18;16915:32;16901:46;;16529:18;16959:6;16956:30;16953:2;;;-1:-1;;16989:12;16953:2;17019:78;17089:7;17080:6;17069:9;17065:22;17019:78;;;17009:88;;17162:3;17151:9;17147:19;17134:33;17120:47;;16529:18;17179:6;17176:30;17173:2;;;-1:-1;;17209:12;17173:2;17239:78;17309:7;17300:6;17289:9;17285:22;17239:78;;;17229:88;;17382:3;17371:9;17367:19;17354:33;17340:47;;16529:18;17399:6;17396:30;17393:2;;;-1:-1;;17429:12;17393:2;17459:78;17529:7;17520:6;17509:9;17505:22;17459:78;;;17449:88;;17602:3;17591:9;17587:19;17574:33;17560:47;;16529:18;17619:6;17616:30;17613:2;;;-1:-1;;17649:12;17613:2;;17679:78;17749:7;17740:6;17729:9;17725:22;17679:78;;;17669:88;;;16280:1493;;;;;;;;;;;17780:535;;;;17929:2;17917:9;17908:7;17904:23;17900:32;17897:2;;;-1:-1;;17935:12;17897:2;6482:6;6476:13;17987:74;;18098:2;18152:9;18148:22;3711:13;18106:74;;18217:2;18271:9;18267:22;6476:13;18225:74;;17891:424;;;;;;19282:343;;19424:5;57518:12;57803:6;57798:3;57791:19;19517:52;19562:6;57840:4;57835:3;57831:14;57840:4;19543:5;19539:16;19517:52;;;57012:9;61842:14;-1:-1;;61838:28;19581:39;;;;57840:4;19581:39;;19372:253;-1:-1;;19372:253;35411:787;19074:37;;;35733:2;35724:12;;19074:37;;;;35835:12;;;19074:37;;;;62053:14;;;;-1:-1;;;;;;62053:14;35946:12;;;18675:58;58608:13;58601:21;61954:3;61950:15;36057:12;;;18939:52;36162:11;;;35624:574;36205:262;;19792:5;57518:12;19903:52;19948:6;19943:3;19936:4;19929:5;19925:16;19903:52;;;19967:16;;;;;36330:137;-1:-1;;36330:137;36474:427;;19792:5;57518:12;19903:52;19948:6;19943:3;19936:4;19929:5;19925:16;19903:52;;;57518:12;;;19967:16;;19903:52;57518:12;19967:16;19936:4;19925:16;;19903:52;;;19967:16;;36649:252;-1:-1;;;;36649:252;36908:213;-1:-1;;;;;59439:54;;;;18409:45;;37026:2;37011:18;;36997:124;37128:663;-1:-1;;;;;59439:54;;;18409:45;;59439:54;;37545:2;37530:18;;18409:45;37628:2;37613:18;;19074:37;;;37364:3;37665:2;37650:18;;37643:48;;;37128:663;;37705:76;;37349:19;;37767:6;37705:76;;;37697:84;37335:456;-1:-1;;;;;;37335:456;37798:201;58608:13;;58601:21;18810:34;;37910:2;37895:18;;37881:118;38006:213;19074:37;;;38124:2;38109:18;;38095:124;39050:344;39206:2;39191:18;;62166:1;62156:12;;62146:2;;62172:9;62146:2;20639:60;;;39380:2;39365:18;19074:37;39177:217;;39401:301;;39539:2;39560:17;39553:47;39614:78;39539:2;39528:9;39524:18;39678:6;39614:78;;39709:407;39900:2;39914:47;;;21657:2;39885:18;;;57791:19;21693:34;57831:14;;;21673:55;-1:-1;;;21748:12;;;21741:26;21786:12;;;39871:245;40123:407;40314:2;40328:47;;;22037:2;40299:18;;;57791:19;22073:34;57831:14;;;22053:55;-1:-1;;;22128:12;;;22121:42;22182:12;;;40285:245;40537:407;40728:2;40742:47;;;22433:2;40713:18;;;57791:19;22469:34;57831:14;;;22449:55;-1:-1;;;22524:12;;;22517:33;22569:12;;;40699:245;40951:407;41142:2;41156:47;;;22820:2;41127:18;;;57791:19;-1:-1;;;57831:14;;;22836:51;22906:12;;;41113:245;41365:407;41556:2;41570:47;;;23157:2;41541:18;;;57791:19;23193:34;57831:14;;;23173:55;-1:-1;;;23248:12;;;23241:25;23285:12;;;41527:245;41779:407;41970:2;41984:47;;;23536:2;41955:18;;;57791:19;23572:34;57831:14;;;23552:55;-1:-1;;;23627:12;;;23620:28;23667:12;;;41941:245;42193:407;42384:2;42398:47;;;23918:2;42369:18;;;57791:19;-1:-1;;;57831:14;;;23934:48;24001:12;;;42355:245;42607:407;42798:2;42812:47;;;24252:2;42783:18;;;57791:19;24288:34;57831:14;;;24268:55;-1:-1;;;24343:12;;;24336:28;24383:12;;;42769:245;43435:407;43626:2;43640:47;;;25018:2;43611:18;;;57791:19;25054:34;57831:14;;;25034:55;-1:-1;;;25109:12;;;25102:36;25157:12;;;43597:245;43849:407;44040:2;44054:47;;;25408:2;44025:18;;;57791:19;25444:32;57831:14;;;25424:53;25496:12;;;44011:245;44263:407;44454:2;44468:47;;;25747:2;44439:18;;;57791:19;25783:34;57831:14;;;25763:55;-1:-1;;;25838:12;;;25831:34;25884:12;;;44425:245;44677:407;44868:2;44882:47;;;26135:2;44853:18;;;57791:19;26171:34;57831:14;;;26151:55;-1:-1;;;26226:12;;;26219:48;26286:12;;;44839:245;45091:407;45282:2;45296:47;;;26537:2;45267:18;;;57791:19;26573:34;57831:14;;;26553:55;-1:-1;;;26628:12;;;26621:34;26674:12;;;45253:245;45505:407;45696:2;45710:47;;;26925:2;45681:18;;;57791:19;-1:-1;;;57831:14;;;26941:42;27002:12;;;45667:245;45919:407;46110:2;46124:47;;;27253:2;46095:18;;;57791:19;27289:34;57831:14;;;27269:55;-1:-1;;;27344:12;;;27337:26;27382:12;;;46081:245;46333:407;46524:2;46538:47;;;46509:18;;;57791:19;27669:34;57831:14;;;27649:55;27723:12;;;46495:245;46747:407;46938:2;46952:47;;;27974:2;46923:18;;;57791:19;-1:-1;;;57831:14;;;27990:51;28060:12;;;46909:245;47161:407;47352:2;47366:47;;;28311:2;47337:18;;;57791:19;28347:34;57831:14;;;28327:55;-1:-1;;;28402:12;;;28395:37;28451:12;;;47323:245;47575:407;47766:2;47780:47;;;28702:2;47751:18;;;57791:19;28738:34;57831:14;;;28718:55;-1:-1;;;28793:12;;;28786:40;28845:12;;;47737:245;47989:407;48180:2;48194:47;;;29096:2;48165:18;;;57791:19;29132:34;57831:14;;;29112:55;-1:-1;;;29187:12;;;29180:36;29235:12;;;48151:245;48403:407;48594:2;48608:47;;;29486:2;48579:18;;;57791:19;29522:34;57831:14;;;29502:55;-1:-1;;;29577:12;;;29570:33;29622:12;;;48565:245;48817:407;49008:2;49022:47;;;29873:2;48993:18;;;57791:19;29909:34;57831:14;;;29889:55;-1:-1;;;29964:12;;;29957:39;30015:12;;;48979:245;49231:407;49422:2;49436:47;;;30266:2;49407:18;;;57791:19;-1:-1;;;57831:14;;;30282:49;30350:12;;;49393:245;49645:407;49836:2;49850:47;;;30601:2;49821:18;;;57791:19;-1:-1;;;57831:14;;;30617:50;30686:12;;;49807:245;50059:407;50250:2;50264:47;;;30937:2;50235:18;;;57791:19;-1:-1;;;57831:14;;;30953:49;31021:12;;;50221:245;50473:407;50664:2;50678:47;;;31272:2;50649:18;;;57791:19;31308:34;57831:14;;;31288:55;-1:-1;;;31363:12;;;31356:27;31402:12;;;50635:245;50887:407;51078:2;51092:47;;;31653:2;51063:18;;;57791:19;31689:34;57831:14;;;31669:55;-1:-1;;;31744:12;;;31737:25;31781:12;;;51049:245;51301:407;51492:2;51506:47;;;32032:2;51477:18;;;57791:19;32068:34;57831:14;;;32048:55;-1:-1;;;32123:12;;;32116:30;32165:12;;;51463:245;51715:407;51906:2;51920:47;;;32416:2;51891:18;;;57791:19;-1:-1;;;57831:14;;;32432:42;32493:12;;;51877:245;52129:407;52320:2;52334:47;;;32744:2;52305:18;;;57791:19;32780:34;57831:14;;;32760:55;-1:-1;;;32835:12;;;32828:41;32888:12;;;52291:245;52543:407;52734:2;52748:47;;;33139:2;52719:18;;;57791:19;-1:-1;;;57831:14;;;33155:50;33224:12;;;52705:245;52957:407;53148:2;53162:47;;;33475:2;53133:18;;;57791:19;33511:31;57831:14;;;33491:52;33562:12;;;53119:245;53371:407;53562:2;53576:47;;;33813:2;53547:18;;;57791:19;33849:34;57831:14;;;33829:55;-1:-1;;;33904:12;;;33897:28;33944:12;;;53533:245;53785:407;53976:2;53990:47;;;34195:2;53961:18;;;57791:19;34231:34;57831:14;;;34211:55;-1:-1;;;34286:12;;;34279:33;34331:12;;;53947:245;54199:407;54390:2;54404:47;;;34582:2;54375:18;;;57791:19;34618:34;57831:14;;;34598:55;-1:-1;;;34673:12;;;34666:39;34724:12;;;54361:245;54613:407;54804:2;54818:47;;;34975:2;54789:18;;;57791:19;35011:34;57831:14;;;34991:55;-1:-1;;;35066:12;;;35059:28;35106:12;;;54775:245;55247:324;19074:37;;;-1:-1;;;;;59439:54;55557:2;55542:18;;18409:45;55393:2;55378:18;;55364:207;55578:256;55640:2;55634:9;55666:17;;;-1:-1;;;;;55726:34;;55762:22;;;55723:62;55720:2;;;55798:1;;55788:12;55720:2;55640;55807:22;55618:216;;-1:-1;55618:216;55841:304;;-1:-1;;;;;55989:30;;55986:2;;;-1:-1;;56022:12;55986:2;-1:-1;56067:4;56055:17;;;56120:15;;55923:222;60946:268;61011:1;61018:101;61032:6;61029:1;61026:13;61018:101;;;61099:11;;;61093:18;61080:11;;;61073:39;61054:2;61047:10;61018:101;;;61134:6;61131:1;61128:13;61125:2;;;-1:-1;;61011:1;61181:16;;61174:27;60995:219;62195:117;-1:-1;;;;;59439:54;;62254:35;;62244:2;;62303:1;;62293:12;62319:111;62400:5;58608:13;58601:21;62378:5;62375:32;62365:2;;62421:1;;62411:12;62561:115;-1:-1;;;;;;58774:78;;62619:34;;62609:2;;62667:1;;62657:12;63456:115;59656:10;63541:5;59645:22;63517:5;63514:34;63504:2;;63562:1;;63552:12
Swarm Source
ipfs://e731d2d277243cb26ce67dd65f8de00b43380526a9a0457ad6a480b5a9a8b173
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.