ETH Price: $2,051.04 (-1.92%)

Transaction Decoder

Block:
11470915 at Dec-17-2020 01:27:03 PM +UTC
Transaction Fee:
0.0760385 ETH $155.96
Gas Used:
304,154 Gas / 250 Gwei

Emitted Events:

1 TellorMaster.0x0e4e65dc389613b6884b7f8c615e54fd3b894fbbbc534c990037744eea942000( 0x0e4e65dc389613b6884b7f8c615e54fd3b894fbbbc534c990037744eea942000, 0x00000000000000000000000034b4cf63e98b4649a96a2a488d731acc30e3e746, 0xe94c0a0f27a77c0146ef65521a0b69328d4fedf9903daa6874a873c6ca91c139, 0000000000000000000000000000000000000000000000000000000000000160, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000032, 0000000000000000000000000000000000000000000000000000000000000003, 0000000000000000000000000000000000000000000000000000000000000002, 000000000000000000000000000000000000000000000000000000000000000a, 000000000000000000000000000000000000000000000000000000002780c330, 0000000000000000000000000000000000000000000000000000000001847d20, 0000000000000000000000000000000000000000000000000000000001da8c60, 00000000000000000000000000000000000000000000000000000005636b1a80, 00000000000000000000000000000000000000000000000000000000000f4463, 000000000000000000000000000000000000000000000000000000000000001b, 6438343830323739306234366634313030303237363545304531340000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x0Ba45A8b...F9C95a2e5
0x34b4Cf63...c30E3E746
1.543570196927762057 Eth
Nonce: 3988
1.467531696927762057 Eth
Nonce: 3989
0.0760385
(Spark Pool)
111.583657644903118807 Eth111.659696144903118807 Eth0.0760385

Execution Trace

TellorMaster.4350283e( )
  • Tellor.submitMiningSolution( _nonce=d84802790b46f410002765E0E14, _requestId=[1, 50, 3, 2, 10], _value=[662750000, 25460000, 31100000, 23142800000, 1000547] )
    • 0xd4cdaa978fdcd627bb2fc08e1b99f87332485d1a.a4bc4067( )
      • Null: 0x000...003.cb518084( )
      • Null: 0x000...002.edbc7e94( )
        submitMiningSolution[Tellor (ln:1680)]
        File 1 of 2: TellorMaster
        pragma solidity ^0.5.0;
        
        
        //Functions for retrieving min and Max in 51 length array (requestQ)
        //Taken partly from: https://github.com/modular-network/ethereum-libraries-array-utils/blob/master/contracts/Array256Lib.sol
        
        library Utilities{
        
            /**
            * @dev Returns the minimum value in an array.
            */
            function getMax(uint[51] memory data) internal pure returns(uint256 max,uint256 maxIndex) {
                max = data[1];
                maxIndex;
                for(uint i=1;i < data.length;i++){
                    if(data[i] > max){
                        max = data[i];
                        maxIndex = i;
                        }
                }
            }
        
            /**
            * @dev Returns the minimum value in an array.
            */
            function getMin(uint[51] memory data) internal pure returns(uint256 min,uint256 minIndex) {
                minIndex = data.length - 1;
                min = data[minIndex];
                for(uint i = data.length-1;i > 0;i--) {
                    if(data[i] < min) {
                        min = data[i];
                        minIndex = i;
                    }
                }
          }
        
        
        
        
          // /// @dev Returns the minimum value and position in an array.
          // //@note IT IGNORES THE 0 INDEX
          //   function getMin(uint[51] memory arr) internal pure returns (uint256 min, uint256 minIndex) {
          //     assembly {
          //         minIndex := 50
          //         min := mload(add(arr, mul(minIndex , 0x20)))
          //         for {let i := 49 } gt(i,0) { i := sub(i, 1) } {
          //             let item := mload(add(arr, mul(i, 0x20)))
          //             if lt(item,min){
          //                 min := item
          //                 minIndex := i
          //             }
          //         }
          //     }
          //   }
        
        
          
          // function getMax(uint256[51] memory arr) internal pure returns (uint256 max, uint256 maxIndex) {
          //     assembly {
          //         for { let i := 0 } lt(i,51) { i := add(i, 1) } {
          //             let item := mload(add(arr, mul(i, 0x20)))
          //             if lt(max, item) {
          //                 max := item
          //                 maxIndex := i
          //             }
          //         }
          //     }
          //   }
        
        
        
        
        
          }
        
        
        /**
        * @title Tellor Getters Library
        * @dev This is the getter library for all variables in the Tellor Tributes system. TellorGetters references this 
        * libary for the getters logic
        */
        library TellorGettersLibrary{
            using SafeMath for uint256;
        
            event NewTellorAddress(address _newTellor); //emmited when a proposed fork is voted true
        
            /*Functions*/
        
            //The next two functions are onlyOwner functions.  For Tellor to be truly decentralized, we will need to transfer the Deity to the 0 address.
            //Only needs to be in library
            /**
            * @dev This function allows us to set a new Deity (or remove it) 
            * @param _newDeity address of the new Deity of the tellor system 
            */
            function changeDeity(TellorStorage.TellorStorageStruct storage self, address _newDeity) internal{
                require(self.addressVars[keccak256("_deity")] == msg.sender);
                self.addressVars[keccak256("_deity")] =_newDeity;
            }
        
        
            //Only needs to be in library
            /**
            * @dev This function allows the deity to upgrade the Tellor System
            * @param _tellorContract address of new updated TellorCore contract
            */
            function changeTellorContract(TellorStorage.TellorStorageStruct storage self,address _tellorContract) internal{
                require(self.addressVars[keccak256("_deity")] == msg.sender);
                self.addressVars[keccak256("tellorContract")]= _tellorContract;
                emit NewTellorAddress(_tellorContract);
            }
        
        
            /*Tellor Getters*/
        
            /**
            * @dev This function tells you if a given challenge has been completed by a given miner
            * @param _challenge the challenge to search for
            * @param _miner address that you want to know if they solved the challenge
            * @return true if the _miner address provided solved the 
            */
            function didMine(TellorStorage.TellorStorageStruct storage self, bytes32 _challenge,address _miner) internal view returns(bool){
                return self.minersByChallenge[_challenge][_miner];
            }
            
        
            /**
            * @dev Checks if an address voted in a dispute
            * @param _disputeId to look up
            * @param _address of voting party to look up
            * @return bool of whether or not party voted
            */
            function didVote(TellorStorage.TellorStorageStruct storage self,uint _disputeId, address _address) internal view returns(bool){
                return self.disputesById[_disputeId].voted[_address];
            }
        
        
            /**
            * @dev allows Tellor to read data from the addressVars mapping
            * @param _data is the keccak256("variable_name") of the variable that is being accessed. 
            * These are examples of how the variables are saved within other functions:
            * addressVars[keccak256("_owner")]
            * addressVars[keccak256("tellorContract")]
            */
            function getAddressVars(TellorStorage.TellorStorageStruct storage self, bytes32 _data) view internal returns(address){
                return self.addressVars[_data];
            }
        
        
            /**
            * @dev Gets all dispute variables
            * @param _disputeId to look up
            * @return bytes32 hash of dispute 
            * @return bool executed where true if it has been voted on
            * @return bool disputeVotePassed
            * @return bool isPropFork true if the dispute is a proposed fork
            * @return address of reportedMiner
            * @return address of reportingParty
            * @return address of proposedForkAddress
            * @return uint of requestId
            * @return uint of timestamp
            * @return uint of value
            * @return uint of minExecutionDate
            * @return uint of numberOfVotes
            * @return uint of blocknumber
            * @return uint of minerSlot
            * @return uint of quorum
            * @return uint of fee
            * @return int count of the current tally
            */
            function getAllDisputeVars(TellorStorage.TellorStorageStruct storage self,uint _disputeId) internal view returns(bytes32, bool, bool, bool, address, address, address,uint[9] memory, int){
                TellorStorage.Dispute storage disp = self.disputesById[_disputeId];
                return(disp.hash,disp.executed, disp.disputeVotePassed, disp.isPropFork, disp.reportedMiner, disp.reportingParty,disp.proposedForkAddress,[disp.disputeUintVars[keccak256("requestId")], disp.disputeUintVars[keccak256("timestamp")], disp.disputeUintVars[keccak256("value")], disp.disputeUintVars[keccak256("minExecutionDate")], disp.disputeUintVars[keccak256("numberOfVotes")], disp.disputeUintVars[keccak256("blockNumber")], disp.disputeUintVars[keccak256("minerSlot")], disp.disputeUintVars[keccak256("quorum")],disp.disputeUintVars[keccak256("fee")]],disp.tally);
            }
        
        
            /**
            * @dev Getter function for variables for the requestId being currently mined(currentRequestId)
            * @return current challenge, curretnRequestId, level of difficulty, api/query string, and granularity(number of decimals requested), total tip for the request 
            */
            function getCurrentVariables(TellorStorage.TellorStorageStruct storage self) internal view returns(bytes32, uint, uint,string memory,uint,uint){    
                return (self.currentChallenge,self.uintVars[keccak256("currentRequestId")],self.uintVars[keccak256("difficulty")],self.requestDetails[self.uintVars[keccak256("currentRequestId")]].queryString,self.requestDetails[self.uintVars[keccak256("currentRequestId")]].apiUintVars[keccak256("granularity")],self.requestDetails[self.uintVars[keccak256("currentRequestId")]].apiUintVars[keccak256("totalTip")]);
            }
        
        
            /**
            * @dev Checks if a given hash of miner,requestId has been disputed
            * @param _hash is the sha256(abi.encodePacked(_miners[2],_requestId));
            * @return uint disputeId
            */
            function getDisputeIdByDisputeHash(TellorStorage.TellorStorageStruct storage self,bytes32 _hash) internal view returns(uint){
                return  self.disputeIdByDisputeHash[_hash];
            }
        
        
            /**
            * @dev Checks for uint variables in the disputeUintVars mapping based on the disuputeId
            * @param _disputeId is the dispute id;
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is 
            * the variables/strings used to save the data in the mapping. The variables names are  
            * commented out under the disputeUintVars under the Dispute struct
            * @return uint value for the bytes32 data submitted
            */
            function getDisputeUintVars(TellorStorage.TellorStorageStruct storage self,uint _disputeId,bytes32 _data) internal view returns(uint){
                return self.disputesById[_disputeId].disputeUintVars[_data];
            }
        
            
            /**
            * @dev Gets the a value for the latest timestamp available
            * @return value for timestamp of last proof of work submited
            * @return true if the is a timestamp for the lastNewValue
            */
            function getLastNewValue(TellorStorage.TellorStorageStruct storage self) internal view returns(uint,bool){
                return (retrieveData(self,self.requestIdByTimestamp[self.uintVars[keccak256("timeOfLastNewValue")]], self.uintVars[keccak256("timeOfLastNewValue")]),true);
            }
        
        
            /**
            * @dev Gets the a value for the latest timestamp available
            * @param _requestId being requested
            * @return value for timestamp of last proof of work submited and if true if it exist or 0 and false if it doesn't
            */
            function getLastNewValueById(TellorStorage.TellorStorageStruct storage self,uint _requestId) internal view returns(uint,bool){
                TellorStorage.Request storage _request = self.requestDetails[_requestId]; 
                if(_request.requestTimestamps.length > 0){
                    return (retrieveData(self,_requestId,_request.requestTimestamps[_request.requestTimestamps.length - 1]),true);
                }
                else{
                    return (0,false);
                }
            }
        
        
            /**
            * @dev Gets blocknumber for mined timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up blocknumber
            * @return uint of the blocknumber which the dispute was mined
            */
            function getMinedBlockNum(TellorStorage.TellorStorageStruct storage self,uint _requestId, uint _timestamp) internal view returns(uint){
                return self.requestDetails[_requestId].minedBlockNum[_timestamp];
            }
        
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up miners for
            * @return the 5 miners' addresses
            */
            function getMinersByRequestIdAndTimestamp(TellorStorage.TellorStorageStruct storage self, uint _requestId, uint _timestamp) internal view returns(address[5] memory){
                return self.requestDetails[_requestId].minersByValue[_timestamp];
            }
        
        
            /**
            * @dev Get the name of the token
            * @return string of the token name
            */
            function getName(TellorStorage.TellorStorageStruct storage self) internal pure returns(string memory){
                return "Tellor Tributes";
            }
        
        
            /**
            * @dev Counts the number of values that have been submited for the request 
            * if called for the currentRequest being mined it can tell you how many miners have submitted a value for that
            * request so far
            * @param _requestId the requestId to look up
            * @return uint count of the number of values received for the requestId
            */
            function getNewValueCountbyRequestId(TellorStorage.TellorStorageStruct storage self, uint _requestId) internal view returns(uint){
                return self.requestDetails[_requestId].requestTimestamps.length;
            }
        
        
            /**
            * @dev Getter function for the specified requestQ index
            * @param _index to look up in the requestQ array
            * @return uint of reqeuestId
            */
            function getRequestIdByRequestQIndex(TellorStorage.TellorStorageStruct storage self, uint _index) internal view returns(uint){
                require(_index <= 50);
                return self.requestIdByRequestQIndex[_index];
            }
        
        
            /**
            * @dev Getter function for requestId based on timestamp 
            * @param _timestamp to check requestId
            * @return uint of reqeuestId
            */
            function getRequestIdByTimestamp(TellorStorage.TellorStorageStruct storage self, uint _timestamp) internal view returns(uint){    
                return self.requestIdByTimestamp[_timestamp];
            }
        
        
            /**
            * @dev Getter function for requestId based on the qeuaryHash
            * @param _queryHash hash(of string api and granularity) to check if a request already exists
            * @return uint requestId
            */
            function getRequestIdByQueryHash(TellorStorage.TellorStorageStruct storage self, bytes32 _queryHash) internal view returns(uint){    
                return self.requestIdByQueryHash[_queryHash];
            }
        
        
            /**
            * @dev Getter function for the requestQ array
            * @return the requestQ arrray
            */
            function getRequestQ(TellorStorage.TellorStorageStruct storage self) view internal returns(uint[51] memory){
                return self.requestQ;
            }
        
        
            /**
            * @dev Allowes access to the uint variables saved in the apiUintVars under the requestDetails struct
            * for the requestId specified
            * @param _requestId to look up
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is 
            * the variables/strings used to save the data in the mapping. The variables names are  
            * commented out under the apiUintVars under the requestDetails struct
            * @return uint value of the apiUintVars specified in _data for the requestId specified
            */
            function getRequestUintVars(TellorStorage.TellorStorageStruct storage self,uint _requestId,bytes32 _data) internal view returns(uint){
                return self.requestDetails[_requestId].apiUintVars[_data];
            }
        
        
            /**
            * @dev Gets the API struct variables that are not mappings
            * @param _requestId to look up
            * @return string of api to query
            * @return string of symbol of api to query
            * @return bytes32 hash of string
            * @return bytes32 of the granularity(decimal places) requested
            * @return uint of index in requestQ array
            * @return uint of current payout/tip for this requestId
            */
            function getRequestVars(TellorStorage.TellorStorageStruct storage self,uint _requestId) internal view returns(string memory,string memory, bytes32,uint, uint, uint) {
                TellorStorage.Request storage _request = self.requestDetails[_requestId]; 
                return (_request.queryString,_request.dataSymbol,_request.queryHash, _request.apiUintVars[keccak256("granularity")],_request.apiUintVars[keccak256("requestQPosition")],_request.apiUintVars[keccak256("totalTip")]);
            }
        
        
            /**
            * @dev This function allows users to retireve all information about a staker
            * @param _staker address of staker inquiring about
            * @return uint current state of staker
            * @return uint startDate of staking
            */
            function getStakerInfo(TellorStorage.TellorStorageStruct storage self,address _staker) internal view returns(uint,uint){
                return (self.stakerDetails[_staker].currentStatus,self.stakerDetails[_staker].startDate);
            }
        
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestampt to look up miners for
            * @return address[5] array of 5 addresses ofminers that mined the requestId
            */
            function getSubmissionsByTimestamp(TellorStorage.TellorStorageStruct storage self, uint _requestId, uint _timestamp) internal view returns(uint[5] memory){
                return self.requestDetails[_requestId].valuesByTimestamp[_timestamp];
            }
        
            /**
            * @dev Get the symbol of the token
            * @return string of the token symbol
            */
            function getSymbol(TellorStorage.TellorStorageStruct storage self) internal pure returns(string memory){
                return "TT";
            } 
        
        
            /**
            * @dev Gets the timestamp for the value based on their index
            * @param _requestID is the requestId to look up
            * @param _index is the value index to look up
            * @return uint timestamp
            */
            function getTimestampbyRequestIDandIndex(TellorStorage.TellorStorageStruct storage self,uint _requestID, uint _index) internal view returns(uint){
                return self.requestDetails[_requestID].requestTimestamps[_index];
            }
        
        
            /**
            * @dev Getter for the variables saved under the TellorStorageStruct uintVars variable
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is 
            * the variables/strings used to save the data in the mapping. The variables names are  
            * commented out under the uintVars under the TellorStorageStruct struct
            * This is an example of how data is saved into the mapping within other functions: 
            * self.uintVars[keccak256("stakerCount")]
            * @return uint of specified variable  
            */ 
            function getUintVar(TellorStorage.TellorStorageStruct storage self,bytes32 _data) view internal returns(uint){
                return self.uintVars[_data];
            }
        
        
            /**
            * @dev Getter function for next requestId on queue/request with highest payout at time the function is called
            * @return onDeck/info on request with highest payout-- RequestId, Totaltips, and API query string
            */
            function getVariablesOnDeck(TellorStorage.TellorStorageStruct storage self) internal view returns(uint, uint,string memory){ 
                uint newRequestId = getTopRequestID(self);
                return (newRequestId,self.requestDetails[newRequestId].apiUintVars[keccak256("totalTip")],self.requestDetails[newRequestId].queryString);
            }
        
        
            /**
            * @dev Getter function for the request with highest payout. This function is used within the getVariablesOnDeck function
            * @return uint _requestId of request with highest payout at the time the function is called
            */
            function getTopRequestID(TellorStorage.TellorStorageStruct storage self) internal view returns(uint _requestId){
                    uint _max;
                    uint _index;
                    (_max,_index) = Utilities.getMax(self.requestQ);
                     _requestId = self.requestIdByRequestQIndex[_index];
            }
        
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up miners for
            * @return bool true if requestId/timestamp is under dispute
            */
            function isInDispute(TellorStorage.TellorStorageStruct storage self, uint _requestId, uint _timestamp) internal view returns(bool){
                return self.requestDetails[_requestId].inDispute[_timestamp];
            }
        
        
            /**
            * @dev Retreive value from oracle based on requestId/timestamp
            * @param _requestId being requested
            * @param _timestamp to retreive data/value from
            * @return uint value for requestId/timestamp submitted
            */
            function retrieveData(TellorStorage.TellorStorageStruct storage self, uint _requestId, uint _timestamp) internal view returns (uint) {
                return self.requestDetails[_requestId].finalValues[_timestamp];
            }
        
        
            /**
            * @dev Getter for the total_supply of oracle tokens
            * @return uint total supply
            */
            function totalSupply(TellorStorage.TellorStorageStruct storage self) internal view returns (uint) {
               return self.uintVars[keccak256("total_supply")];
            }
        
        }
        
        
        
        
        
        
        
        pragma solidity ^0.5.0;
        
        //Slightly modified SafeMath library - includes a min and max function, removes useless div function
        library SafeMath {
        
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            assert(c >= a);
            return c;
          }
        
          function add(int256 a, int256 b) internal pure returns (int256 c) {
            if(b > 0){
              c = a + b;
              assert(c >= a);
            }
            else{
              c = a + b;
              assert(c <= a);
            }
        
          }
        
          function max(uint a, uint b) internal pure returns (uint256) {
            return a > b ? a : b;
          }
        
          function max(int256 a, int256 b) internal pure returns (uint256) {
            return a > b ? uint(a) : uint(b);
          }
        
          function min(uint a, uint b) internal pure returns (uint256) {
            return a < b ? a : b;
          }
          
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a * b;
            assert(a == 0 || c / a == b);
            return c;
          }
        
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            assert(b <= a);
            return a - b;
          }
        
          function sub(int256 a, int256 b) internal pure returns (int256 c) {
            if(b > 0){
              c = a - b;
              assert(c <= a);
            }
            else{
              c = a - b;
              assert(c >= a);
            }
        
          }
        
        }
        
        
        
        /**
         * @title Tellor Oracle Storage Library
         * @dev Contains all the variables/structs used by Tellor
         */
        
        library TellorStorage {
            //Internal struct for use in proof-of-work submission
            struct Details {
                uint value;
                address miner;
            }
        
            struct Dispute {
                bytes32 hash;//unique hash of dispute: keccak256(_miner,_requestId,_timestamp)
                int tally;//current tally of votes for - against measure
                bool executed;//is the dispute settled
                bool disputeVotePassed;//did the vote pass?
                bool isPropFork; //true for fork proposal NEW
                address reportedMiner; //miner who alledgedly submitted the 'bad value' will get disputeFee if dispute vote fails
                address reportingParty;//miner reporting the 'bad value'-pay disputeFee will get reportedMiner's stake if dispute vote passes
                address proposedForkAddress;//new fork address (if fork proposal)
                mapping(bytes32 => uint) disputeUintVars;
                //Each of the variables below is saved in the mapping disputeUintVars for each disputeID
                //e.g. TellorStorageStruct.DisputeById[disputeID].disputeUintVars[keccak256("requestId")]
                //These are the variables saved in this mapping:
                    // uint keccak256("requestId");//apiID of disputed value
                    // uint keccak256("timestamp");//timestamp of distputed value
                    // uint keccak256("value"); //the value being disputed
                    // uint keccak256("minExecutionDate");//7 days from when dispute initialized
                    // uint keccak256("numberOfVotes");//the number of parties who have voted on the measure
                    // uint keccak256("blockNumber");// the blocknumber for which votes will be calculated from
                    // uint keccak256("minerSlot"); //index in dispute array
                    // uint keccak256("quorum"); //quorum for dispute vote NEW
                    // uint keccak256("fee"); //fee paid corresponding to dispute
                mapping (address => bool) voted; //mapping of address to whether or not they voted
            }
        
            struct StakeInfo {
                uint currentStatus;//0-not Staked, 1=Staked, 2=LockedForWithdraw 3= OnDispute
                uint startDate; //stake start date
            }
        
            //Internal struct to allow balances to be queried by blocknumber for voting purposes
            struct  Checkpoint {
                uint128 fromBlock;// fromBlock is the block number that the value was generated from
                uint128 value;// value is the amount of tokens at a specific block number
            }
        
            struct Request {
                string queryString;//id to string api
                string dataSymbol;//short name for api request
                bytes32 queryHash;//hash of api string and granularity e.g. keccak256(abi.encodePacked(_sapi,_granularity))
                uint[]  requestTimestamps; //array of all newValueTimestamps requested
                mapping(bytes32 => uint) apiUintVars;
                //Each of the variables below is saved in the mapping apiUintVars for each api request
                //e.g. requestDetails[_requestId].apiUintVars[keccak256("totalTip")]
                //These are the variables saved in this mapping:
                    // uint keccak256("granularity"); //multiplier for miners
                    // uint keccak256("requestQPosition"); //index in requestQ
                    // uint keccak256("totalTip");//bonus portion of payout
                mapping(uint => uint) minedBlockNum;//[apiId][minedTimestamp]=>block.number
                mapping(uint => uint) finalValues;//This the time series of finalValues stored by the contract where uint UNIX timestamp is mapped to value
                mapping(uint => bool) inDispute;//checks if API id is in dispute or finalized.
                mapping(uint => address[5]) minersByValue;
                mapping(uint => uint[5])valuesByTimestamp;
            }
        
            struct TellorStorageStruct {
                bytes32 currentChallenge; //current challenge to be solved
                uint[51]  requestQ; //uint50 array of the top50 requests by payment amount
                uint[]  newValueTimestamps; //array of all timestamps requested
                Details[5]  currentMiners; //This struct is for organizing the five mined values to find the median
                mapping(bytes32 => address) addressVars;
                //Address fields in the Tellor contract are saved the addressVars mapping
                //e.g. addressVars[keccak256("tellorContract")] = address
                //These are the variables saved in this mapping:
                    // address keccak256("tellorContract");//Tellor address
                    // address  keccak256("_owner");//Tellor Owner address
                    // address  keccak256("_deity");//Tellor Owner that can do things at will
                mapping(bytes32 => uint) uintVars; 
                //uint fields in the Tellor contract are saved the uintVars mapping
                //e.g. uintVars[keccak256("decimals")] = uint
                //These are the variables saved in this mapping:
                    // keccak256("decimals");    //18 decimal standard ERC20
                    // keccak256("disputeFee");//cost to dispute a mined value
                    // keccak256("disputeCount");//totalHistoricalDisputes
                    // keccak256("total_supply"); //total_supply of the token in circulation
                    // keccak256("stakeAmount");//stakeAmount for miners (we can cut gas if we just hardcode it in...or should it be variable?)
                    // keccak256("stakerCount"); //number of parties currently staked
                    // keccak256("timeOfLastNewValue"); // time of last challenge solved
                    // keccak256("difficulty"); // Difficulty of current block
                    // keccak256("currentTotalTips"); //value of highest api/timestamp PayoutPool
                    // keccak256("currentRequestId"); //API being mined--updates with the ApiOnQ Id
                    // keccak256("requestCount"); // total number of requests through the system
                    // keccak256("slotProgress");//Number of miners who have mined this value so far
                    // keccak256("miningReward");//Mining Reward in PoWo tokens given to all miners per value
                    // keccak256("timeTarget"); //The time between blocks (mined Oracle values)
                mapping(bytes32 => mapping(address=>bool)) minersByChallenge;//This is a boolean that tells you if a given challenge has been completed by a given miner
                mapping(uint => uint) requestIdByTimestamp;//minedTimestamp to apiId
                mapping(uint => uint) requestIdByRequestQIndex; //link from payoutPoolIndex (position in payout pool array) to apiId
                mapping(uint => Dispute) disputesById;//disputeId=> Dispute details
                mapping (address => Checkpoint[]) balances; //balances of a party given blocks
                mapping(address => mapping (address => uint)) allowed; //allowance for a given party and approver
                mapping(address => StakeInfo)  stakerDetails;//mapping from a persons address to their staking info
                mapping(uint => Request) requestDetails;//mapping of apiID to details
                mapping(bytes32 => uint) requestIdByQueryHash;// api bytes32 gets an id = to count of requests array
                mapping(bytes32 => uint) disputeIdByDisputeHash;//maps a hash to an ID for each dispute
            }
        }
        
        
        /**
        * @title Tellor Transfer
        * @dev Contais the methods related to transfers and ERC20. Tellor.sol and TellorGetters.sol
        * reference this library for function's logic.
        */
        library TellorTransfer {
            using SafeMath for uint256;
        
            event Approval(address indexed _owner, address indexed _spender, uint256 _value);//ERC20 Approval event
            event Transfer(address indexed _from, address indexed _to, uint256 _value);//ERC20 Transfer Event
        
            /*Functions*/
            
            /**
            * @dev Allows for a transfer of tokens to _to
            * @param _to The address to send tokens to
            * @param _amount The amount of tokens to send
            * @return true if transfer is successful
            */
            function transfer(TellorStorage.TellorStorageStruct storage self, address _to, uint256 _amount) public returns (bool success) {
                doTransfer(self,msg.sender, _to, _amount);
                return true;
            }
        
        
            /**
            * @notice Send _amount tokens to _to from _from on the condition it
            * is approved by _from
            * @param _from The address holding the tokens being transferred
            * @param _to The address of the recipient
            * @param _amount The amount of tokens to be transferred
            * @return True if the transfer was successful
            */
            function transferFrom(TellorStorage.TellorStorageStruct storage self, address _from, address _to, uint256 _amount) public returns (bool success) {
                require(self.allowed[_from][msg.sender] >= _amount);
                self.allowed[_from][msg.sender] -= _amount;
                doTransfer(self,_from, _to, _amount);
                return true;
            }
        
        
            /**
            * @dev This function approves a _spender an _amount of tokens to use
            * @param _spender address
            * @param _amount amount the spender is being approved for
            * @return true if spender appproved successfully
            */
            function approve(TellorStorage.TellorStorageStruct storage self, address _spender, uint _amount) public returns (bool) {
                require(allowedToTrade(self,msg.sender,_amount));
                require(_spender != address(0));
                self.allowed[msg.sender][_spender] = _amount;
                emit Approval(msg.sender, _spender, _amount);
                return true;
            }
        
        
            /**
            * @param _user address of party with the balance
            * @param _spender address of spender of parties said balance
            * @return Returns the remaining allowance of tokens granted to the _spender from the _user
            */
            function allowance(TellorStorage.TellorStorageStruct storage self,address _user, address _spender) public view returns (uint) {
               return self.allowed[_user][_spender]; 
            }
        
        
            /**
            * @dev Completes POWO transfers by updating the balances on the current block number
            * @param _from address to transfer from
            * @param _to addres to transfer to
            * @param _amount to transfer
            */
            function doTransfer(TellorStorage.TellorStorageStruct storage self, address _from, address _to, uint _amount) public {
                require(_amount > 0);
                require(_to != address(0));
                require(allowedToTrade(self,_from,_amount)); //allowedToTrade checks the stakeAmount is removed from balance if the _user is staked
                uint previousBalance = balanceOfAt(self,_from, block.number);
                updateBalanceAtNow(self.balances[_from], previousBalance - _amount);
                previousBalance = balanceOfAt(self,_to, block.number);
                require(previousBalance + _amount >= previousBalance); // Check for overflow
                updateBalanceAtNow(self.balances[_to], previousBalance + _amount);
                emit Transfer(_from, _to, _amount);
            }
        
        
            /**
            * @dev Gets balance of owner specified
            * @param _user is the owner address used to look up the balance
            * @return Returns the balance associated with the passed in _user
            */
            function balanceOf(TellorStorage.TellorStorageStruct storage self,address _user) public view returns (uint) {
                return balanceOfAt(self,_user, block.number);
            }
        
        
            /**
            * @dev Queries the balance of _user at a specific _blockNumber
            * @param _user The address from which the balance will be retrieved
            * @param _blockNumber The block number when the balance is queried
            * @return The balance at _blockNumber specified
            */
            function balanceOfAt(TellorStorage.TellorStorageStruct storage self,address _user, uint _blockNumber) public view returns (uint) {
                if ((self.balances[_user].length == 0) || (self.balances[_user][0].fromBlock > _blockNumber)) {
                        return 0;
                }
             else {
                return getBalanceAt(self.balances[_user], _blockNumber);
             }
            }
        
        
            /**
            * @dev Getter for balance for owner on the specified _block number
            * @param checkpoints gets the mapping for the balances[owner]
            * @param _block is the block number to search the balance on
            * @return the balance at the checkpoint
            */
            function getBalanceAt(TellorStorage.Checkpoint[] storage checkpoints, uint _block) view public returns (uint) {
                if (checkpoints.length == 0) return 0;
                if (_block >= checkpoints[checkpoints.length-1].fromBlock)
                    return checkpoints[checkpoints.length-1].value;
                if (_block < checkpoints[0].fromBlock) return 0;
                // Binary search of the value in the array
                uint min = 0;
                uint max = checkpoints.length-1;
                while (max > min) {
                    uint mid = (max + min + 1)/ 2;
                    if (checkpoints[mid].fromBlock<=_block) {
                        min = mid;
                    } else {
                        max = mid-1;
                    }
                }
                return checkpoints[min].value;
            }
        
        
            /**
            * @dev This function returns whether or not a given user is allowed to trade a given amount 
            * and removing the staked amount from their balance if they are staked
            * @param _user address of user
            * @param _amount to check if the user can spend
            * @return true if they are allowed to spend the amount being checked
            */
            function allowedToTrade(TellorStorage.TellorStorageStruct storage self,address _user,uint _amount) public view returns(bool) {
                if(self.stakerDetails[_user].currentStatus >0){
                    //Removes the stakeAmount from balance if the _user is staked
                    if(balanceOf(self,_user).sub(self.uintVars[keccak256("stakeAmount")]).sub(_amount) >= 0){
                        return true;
                    }
                }
                else if(balanceOf(self,_user).sub(_amount) >= 0){
                        return true;
                }
                return false;
            }
            
        
            /**
            * @dev Updates balance for from and to on the current block number via doTransfer
            * @param checkpoints gets the mapping for the balances[owner]
            * @param _value is the new balance
            */
            function updateBalanceAtNow(TellorStorage.Checkpoint[] storage checkpoints, uint _value) public {
                if ((checkpoints.length == 0) || (checkpoints[checkpoints.length -1].fromBlock < block.number)) {
                       TellorStorage.Checkpoint storage newCheckPoint = checkpoints[ checkpoints.length++ ];
                       newCheckPoint.fromBlock =  uint128(block.number);
                       newCheckPoint.value = uint128(_value);
                } else {
                       TellorStorage.Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1];
                       oldCheckPoint.value = uint128(_value);
                }
            }
        }
        
        
        
        
        //import "./SafeMath.sol";
        
        /**
        * @title Tellor Dispute
        * @dev Contais the methods related to disputes. Tellor.sol references this library for function's logic.
        */
        
        
        library TellorDispute {
            using SafeMath for uint256;
            using SafeMath for int256;
        
            event NewDispute(uint indexed _disputeId, uint indexed _requestId, uint _timestamp, address _miner);//emitted when a new dispute is initialized
            event Voted(uint indexed _disputeID, bool _position, address indexed _voter);//emitted when a new vote happens
            event DisputeVoteTallied(uint indexed _disputeID, int _result,address indexed _reportedMiner,address _reportingParty, bool _active);//emitted upon dispute tally
            event NewTellorAddress(address _newTellor); //emmited when a proposed fork is voted true
        
            /*Functions*/
            
            /**
            * @dev Helps initialize a dispute by assigning it a disputeId
            * when a miner returns a false on the validate array(in Tellor.ProofOfWork) it sends the
            * invalidated value information to POS voting
            * @param _requestId being disputed
            * @param _timestamp being disputed
            * @param _minerIndex the index of the miner that submitted the value being disputed. Since each official value
            * requires 5 miners to submit a value.
            */
            function beginDispute(TellorStorage.TellorStorageStruct storage self,uint _requestId, uint _timestamp,uint _minerIndex) public {
                TellorStorage.Request storage _request = self.requestDetails[_requestId];
                //require that no more than a day( (24 hours * 60 minutes)/10minutes=144 blocks) has gone by since the value was "mined"
                require(block.number- _request.minedBlockNum[_timestamp]<= 144);
                require(_request.minedBlockNum[_timestamp] > 0);
                require(_minerIndex < 5);
                
                //_miner is the miner being disputed. For every mined value 5 miners are saved in an array and the _minerIndex
                //provided by the party initiating the dispute
                address _miner = _request.minersByValue[_timestamp][_minerIndex];
                bytes32 _hash = keccak256(abi.encodePacked(_miner,_requestId,_timestamp));
                
                //Ensures that a dispute is not already open for the that miner, requestId and timestamp
                require(self.disputeIdByDisputeHash[_hash] == 0);
                TellorTransfer.doTransfer(self, msg.sender,address(this), self.uintVars[keccak256("disputeFee")]);
                
                //Increase the dispute count by 1
                self.uintVars[keccak256("disputeCount")] =  self.uintVars[keccak256("disputeCount")] + 1;
                
                //Sets the new disputeCount as the disputeId
                uint disputeId = self.uintVars[keccak256("disputeCount")];
                
                //maps the dispute hash to the disputeId
                self.disputeIdByDisputeHash[_hash] = disputeId;
                //maps the dispute to the Dispute struct
                self.disputesById[disputeId] = TellorStorage.Dispute({
                    hash:_hash,
                    isPropFork: false,
                    reportedMiner: _miner,
                    reportingParty: msg.sender,
                    proposedForkAddress:address(0),
                    executed: false,
                    disputeVotePassed: false,
                    tally: 0
                    });
                
                //Saves all the dispute variables for the disputeId
                self.disputesById[disputeId].disputeUintVars[keccak256("requestId")] = _requestId;
                self.disputesById[disputeId].disputeUintVars[keccak256("timestamp")] = _timestamp;
                self.disputesById[disputeId].disputeUintVars[keccak256("value")] = _request.valuesByTimestamp[_timestamp][_minerIndex];
                self.disputesById[disputeId].disputeUintVars[keccak256("minExecutionDate")] = now + 7 days;
                self.disputesById[disputeId].disputeUintVars[keccak256("blockNumber")] = block.number;
                self.disputesById[disputeId].disputeUintVars[keccak256("minerSlot")] = _minerIndex;
                self.disputesById[disputeId].disputeUintVars[keccak256("fee")]  = self.uintVars[keccak256("disputeFee")];
                
                //Values are sorted as they come in and the official value is the median of the first five
                //So the "official value" miner is always minerIndex==2. If the official value is being 
                //disputed, it sets its status to inDispute(currentStatus = 3) so that users are made aware it is under dispute
                if(_minerIndex == 2){
                    self.requestDetails[_requestId].inDispute[_timestamp] = true;
                }
                self.stakerDetails[_miner].currentStatus = 3;
                emit NewDispute(disputeId,_requestId,_timestamp,_miner);
            }
        
        
            /**
            * @dev Allows token holders to vote
            * @param _disputeId is the dispute id
            * @param _supportsDispute is the vote (true=the dispute has basis false = vote against dispute)
            */
            function vote(TellorStorage.TellorStorageStruct storage self, uint _disputeId, bool _supportsDispute) public {
                TellorStorage.Dispute storage disp = self.disputesById[_disputeId];
                
                //Get the voteWeight or the balance of the user at the time/blockNumber the disupte began
                uint voteWeight = TellorTransfer.balanceOfAt(self,msg.sender,disp.disputeUintVars[keccak256("blockNumber")]);
                
                //Require that the msg.sender has not voted
                require(disp.voted[msg.sender] != true);
                
                //Requre that the user had a balance >0 at time/blockNumber the disupte began
                require(voteWeight > 0);
                
                //ensures miners that are under dispute cannot vote
                require(self.stakerDetails[msg.sender].currentStatus != 3);
                
                //Update user voting status to true
                disp.voted[msg.sender] = true;
                
                //Update the number of votes for the dispute
                disp.disputeUintVars[keccak256("numberOfVotes")] += 1;
                
                //Update the quorum by adding the voteWeight
                disp.disputeUintVars[keccak256("quorum")] += voteWeight; 
                
                //If the user supports the dispute increase the tally for the dispute by the voteWeight
                //otherwise decrease it
                if (_supportsDispute) {
                    disp.tally = disp.tally.add(int(voteWeight));
                } else {
                    disp.tally = disp.tally.sub(int(voteWeight));
                }
                
                //Let the network know the user has voted on the dispute and their casted vote
                emit Voted(_disputeId,_supportsDispute,msg.sender);
            }
        
        
            /**
            * @dev tallies the votes.
            * @param _disputeId is the dispute id
            */
            function tallyVotes(TellorStorage.TellorStorageStruct storage self, uint _disputeId) public {
                TellorStorage.Dispute storage disp = self.disputesById[_disputeId];
                TellorStorage.Request storage _request = self.requestDetails[disp.disputeUintVars[keccak256("requestId")]];
        
                //Ensure this has not already been executed/tallied
                require(disp.executed == false);
        
                //Ensure the time for voting has elapsed
                require(now > disp.disputeUintVars[keccak256("minExecutionDate")]);  
        
                //If the vote is not a proposed fork 
                if (disp.isPropFork== false){
                TellorStorage.StakeInfo storage stakes = self.stakerDetails[disp.reportedMiner];  
                    //If the vote for disputing a value is succesful(disp.tally >0) then unstake the reported 
                    // miner and transfer the stakeAmount and dispute fee to the reporting party 
                    if (disp.tally > 0 ) { 
        
                        //Changing the currentStatus and startDate unstakes the reported miner and allows for the
                        //transfer of the stakeAmount
                        stakes.currentStatus = 0;
                        stakes.startDate = now -(now % 86400);
        
                        //Decreases the stakerCount since the miner's stake is being slashed
                        self.uintVars[keccak256("stakerCount")]--;
                        updateDisputeFee(self);
        
                        //Transfers the StakeAmount from the reporded miner to the reporting party
                        TellorTransfer.doTransfer(self, disp.reportedMiner,disp.reportingParty, self.uintVars[keccak256("stakeAmount")]);
                        
                        //Returns the dispute fee to the reportingParty
                        TellorTransfer.doTransfer(self, address(this),disp.reportingParty,disp.disputeUintVars[keccak256("fee")]);
                        
                        //Set the dispute state to passed/true
                        disp.disputeVotePassed = true;
        
                        //If the dispute was succeful(miner found guilty) then update the timestamp value to zero
                        //so that users don't use this datapoint
                        if(_request.inDispute[disp.disputeUintVars[keccak256("timestamp")]] == true){
                            _request.finalValues[disp.disputeUintVars[keccak256("timestamp")]] = 0;
                        }
        
                    //If the vote for disputing a value is unsuccesful then update the miner status from being on 
                    //dispute(currentStatus=3) to staked(currentStatus =1) and tranfer the dispute fee to the miner
                    } else {
                        //Update the miner's current status to staked(currentStatus = 1)
                        stakes.currentStatus = 1;              
                        //tranfer the dispute fee to the miner
                        TellorTransfer.doTransfer(self,address(this),disp.reportedMiner,disp.disputeUintVars[keccak256("fee")]);
                        if(_request.inDispute[disp.disputeUintVars[keccak256("timestamp")]] == true){
                            _request.inDispute[disp.disputeUintVars[keccak256("timestamp")]] = false;
                        }
                    }
                //If the vote is for a proposed fork require a 20% quorum before excecuting the update to the new tellor contract address
                } else {
                    if(disp.tally > 0 ){
                        require(disp.disputeUintVars[keccak256("quorum")] >  (self.uintVars[keccak256("total_supply")] * 20 / 100));
                        self.addressVars[keccak256("tellorContract")] = disp.proposedForkAddress;
                        disp.disputeVotePassed = true;
                        emit NewTellorAddress(disp.proposedForkAddress);
                    }
                }
                
                //update the dispute status to executed
                disp.executed = true;
                emit DisputeVoteTallied(_disputeId,disp.tally,disp.reportedMiner,disp.reportingParty,disp.disputeVotePassed);
            }
        
        
            /**
            * @dev Allows for a fork to be proposed
            * @param _propNewTellorAddress address for new proposed Tellor
            */
            function proposeFork(TellorStorage.TellorStorageStruct storage self, address _propNewTellorAddress) public {
                bytes32 _hash = keccak256(abi.encodePacked(_propNewTellorAddress));
                require(self.disputeIdByDisputeHash[_hash] == 0);
                TellorTransfer.doTransfer(self, msg.sender,address(this), self.uintVars[keccak256("disputeFee")]);//This is the fork fee
                self.uintVars[keccak256("disputeCount")]++;
                uint disputeId = self.uintVars[keccak256("disputeCount")];
                self.disputeIdByDisputeHash[_hash] = disputeId;
                self.disputesById[disputeId] = TellorStorage.Dispute({
                    hash: _hash,
                    isPropFork: true,
                    reportedMiner: msg.sender, 
                    reportingParty: msg.sender, 
                    proposedForkAddress: _propNewTellorAddress,
                    executed: false,
                    disputeVotePassed: false,
                    tally: 0
                    }); 
                self.disputesById[disputeId].disputeUintVars[keccak256("blockNumber")] = block.number;
                self.disputesById[disputeId].disputeUintVars[keccak256("fee")]  = self.uintVars[keccak256("disputeFee")];
                self.disputesById[disputeId].disputeUintVars[keccak256("minExecutionDate")] = now + 7 days;
            }
            
        
            /**
            * @dev this function allows the dispute fee to fluctuate based on the number of miners on the system.
            * The floor for the fee is 15e18.
            */
            function updateDisputeFee(TellorStorage.TellorStorageStruct storage self) public {
                    //if the number of staked miners divided by the target count of staked miners is less than 1
                    if(self.uintVars[keccak256("stakerCount")]*1000/self.uintVars[keccak256("targetMiners")] < 1000){
                        //Set the dispute fee at stakeAmt * (1- stakerCount/targetMiners)
                        //or at the its minimum of 15e18 
                        self.uintVars[keccak256("disputeFee")] = SafeMath.max(15e18,self.uintVars[keccak256("stakeAmount")].mul(1000 - self.uintVars[keccak256("stakerCount")]*1000/self.uintVars[keccak256("targetMiners")])/1000);
                    }
                    else{
                        //otherwise set the dispute fee at 15e18 (the floor/minimum fee allowed)
                        self.uintVars[keccak256("disputeFee")] = 15e18;
                    }
            }
        }
        
        
        /**
        * itle Tellor Dispute
        * @dev Contais the methods related to miners staking and unstaking. Tellor.sol 
        * references this library for function's logic.
        */
        
        library TellorStake {
            event NewStake(address indexed _sender);//Emits upon new staker
            event StakeWithdrawn(address indexed _sender);//Emits when a staker is now no longer staked
            event StakeWithdrawRequested(address indexed _sender);//Emits when a staker begins the 7 day withdraw period
        
            /*Functions*/
            
            /**
            * @dev This function stakes the five initial miners, sets the supply and all the constant variables.
            * This function is called by the constructor function on TellorMaster.sol
            */
            function init(TellorStorage.TellorStorageStruct storage self) public{
                require(self.uintVars[keccak256("decimals")] == 0);
                //Give this contract 6000 Tellor Tributes so that it can stake the initial 6 miners
                TellorTransfer.updateBalanceAtNow(self.balances[address(this)], 2**256-1 - 6000e18);
        
                // //the initial 5 miner addresses are specfied below
                // //changed payable[5] to 6
                address payable[6] memory _initalMiners = [address(0x4c49172A499D18eA3093D59A304eEF63F9754e25),
                address(0xbfc157b09346AC15873160710B00ec8d4d520C5a),
                address(0xa3792188E76c55b1A649fE5Df77DDd4bFD6D03dB),
                address(0xbAF31Bbbba24AF83c8a7a76e16E109d921E4182a),
                address(0x8c9841fEaE5Fc2061F2163033229cE0d9DfAbC71),
                address(0xc31Ef608aDa4003AaD4D2D1ec2Be72232A9E2A86)];
                //Stake each of the 5 miners specified above
                for(uint i=0;i<6;i++){//6th miner to allow for dispute
                    //Miner balance is set at 1000e18 at the block that this function is ran
                    TellorTransfer.updateBalanceAtNow(self.balances[_initalMiners[i]],1000e18);
        
                    newStake(self, _initalMiners[i]);
                }
        
                //update the total suppply
                self.uintVars[keccak256("total_supply")] += 6000e18;//6th miner to allow for dispute
                //set Constants
                self.uintVars[keccak256("decimals")] = 18;
                self.uintVars[keccak256("targetMiners")] = 200;
                self.uintVars[keccak256("stakeAmount")] = 1000e18;
                self.uintVars[keccak256("disputeFee")] = 970e18;
                self.uintVars[keccak256("timeTarget")]= 600;
                self.uintVars[keccak256("timeOfLastNewValue")] = now - now  % self.uintVars[keccak256("timeTarget")];
                self.uintVars[keccak256("difficulty")] = 1;
            }
        
        
            /**
            * @dev This function allows stakers to request to withdraw their stake (no longer stake)
            * once they lock for withdraw(stakes.currentStatus = 2) they are locked for 7 days before they
            * can withdraw the deposit
            */
            function requestStakingWithdraw(TellorStorage.TellorStorageStruct storage self) public {
                TellorStorage.StakeInfo storage stakes = self.stakerDetails[msg.sender];
                //Require that the miner is staked
                require(stakes.currentStatus == 1);
        
                //Change the miner staked to locked to be withdrawStake
                stakes.currentStatus = 2;
        
                //Change the startDate to now since the lock up period begins now
                //and the miner can only withdraw 7 days later from now(check the withdraw function)
                stakes.startDate = now -(now % 86400);
        
                //Reduce the staker count
                self.uintVars[keccak256("stakerCount")] -= 1;
                TellorDispute.updateDisputeFee(self);
                emit StakeWithdrawRequested(msg.sender);
            }
        
        
            /**
            * @dev This function allows users to withdraw their stake after a 7 day waiting period from request 
            */
            function withdrawStake(TellorStorage.TellorStorageStruct storage self) public {
                TellorStorage.StakeInfo storage stakes = self.stakerDetails[msg.sender];
                //Require the staker has locked for withdraw(currentStatus ==2) and that 7 days have 
                //passed by since they locked for withdraw
                require(now - (now % 86400) - stakes.startDate >= 7 days);
                require(stakes.currentStatus == 2);
                stakes.currentStatus = 0;
                emit StakeWithdrawn(msg.sender);
            }
        
        
            /**
            * @dev This function allows miners to deposit their stake.
            */
            function depositStake(TellorStorage.TellorStorageStruct storage self) public {
              newStake(self, msg.sender);
              //self adjusting disputeFee
              TellorDispute.updateDisputeFee(self);
            }
        
            /**
            * @dev This function is used by the init function to succesfully stake the initial 5 miners.
            * The function updates their status/state and status start date so they are locked it so they can't withdraw
            * and updates the number of stakers in the system.
            */
            function newStake(TellorStorage.TellorStorageStruct storage self, address staker) internal {
                require(TellorTransfer.balanceOf(self,staker) >= self.uintVars[keccak256("stakeAmount")]);
                //Ensure they can only stake if they are not currrently staked or if their stake time frame has ended
                //and they are currently locked for witdhraw
                require(self.stakerDetails[staker].currentStatus == 0 || self.stakerDetails[staker].currentStatus == 2);
                self.uintVars[keccak256("stakerCount")] += 1;
                self.stakerDetails[staker] = TellorStorage.StakeInfo({
                    currentStatus: 1,
                    //this resets their stake start date to today
                    startDate: now - (now % 86400)
                });
                emit NewStake(staker);
            }
        }
        
        
        /**
        * @title Tellor Getters
        * @dev Oracle contract with all tellor getter functions. The logic for the functions on this contract 
        * is saved on the TellorGettersLibrary, TellorTransfer, TellorGettersLibrary, and TellorStake
        */
        contract TellorGetters{
            using SafeMath for uint256;
        
            using TellorTransfer for TellorStorage.TellorStorageStruct;
            using TellorGettersLibrary for TellorStorage.TellorStorageStruct;
            using TellorStake for TellorStorage.TellorStorageStruct;
        
            TellorStorage.TellorStorageStruct tellor;
            
            /**
            * @param _user address
            * @param _spender address
            * @return Returns the remaining allowance of tokens granted to the _spender from the _user
            */
            function allowance(address _user, address _spender) external view returns (uint) {
               return tellor.allowance(_user,_spender);
            }
        
            /**
            * @dev This function returns whether or not a given user is allowed to trade a given amount  
            * @param _user address
            * @param _amount uint of amount
            * @return true if the user is alloed to trade the amount specified
            */
            function allowedToTrade(address _user,uint _amount) external view returns(bool){
                return tellor.allowedToTrade(_user,_amount);
            }
        
            /**
            * @dev Gets balance of owner specified
            * @param _user is the owner address used to look up the balance
            * @return Returns the balance associated with the passed in _user
            */
            function balanceOf(address _user) external view returns (uint) { 
                return tellor.balanceOf(_user);
            }
        
            /**
            * @dev Queries the balance of _user at a specific _blockNumber
            * @param _user The address from which the balance will be retrieved
            * @param _blockNumber The block number when the balance is queried
            * @return The balance at _blockNumber
            */
            function balanceOfAt(address _user, uint _blockNumber) external view returns (uint) {
                return tellor.balanceOfAt(_user,_blockNumber);
            }
        
            /**
            * @dev This function tells you if a given challenge has been completed by a given miner
            * @param _challenge the challenge to search for
            * @param _miner address that you want to know if they solved the challenge
            * @return true if the _miner address provided solved the 
            */
            function didMine(bytes32 _challenge, address _miner) external view returns(bool){
                return tellor.didMine(_challenge,_miner);
            }
        
        
            /**
            * @dev Checks if an address voted in a given dispute
            * @param _disputeId to look up
            * @param _address to look up
            * @return bool of whether or not party voted
            */
            function didVote(uint _disputeId, address _address) external view returns(bool){
                return tellor.didVote(_disputeId,_address);
            }
        
        
            /**
            * @dev allows Tellor to read data from the addressVars mapping
            * @param _data is the keccak256("variable_name") of the variable that is being accessed. 
            * These are examples of how the variables are saved within other functions:
            * addressVars[keccak256("_owner")]
            * addressVars[keccak256("tellorContract")]
            */
            function getAddressVars(bytes32 _data) view external returns(address){
                return tellor.getAddressVars(_data);
            }
        
        
            /**
            * @dev Gets all dispute variables
            * @param _disputeId to look up
            * @return bytes32 hash of dispute 
            * @return bool executed where true if it has been voted on
            * @return bool disputeVotePassed
            * @return bool isPropFork true if the dispute is a proposed fork
            * @return address of reportedMiner
            * @return address of reportingParty
            * @return address of proposedForkAddress
            * @return uint of requestId
            * @return uint of timestamp
            * @return uint of value
            * @return uint of minExecutionDate
            * @return uint of numberOfVotes
            * @return uint of blocknumber
            * @return uint of minerSlot
            * @return uint of quorum
            * @return uint of fee
            * @return int count of the current tally
            */
            function getAllDisputeVars(uint _disputeId) public view returns(bytes32, bool, bool, bool, address, address, address,uint[9] memory, int){
                return tellor.getAllDisputeVars(_disputeId);
            }
            
        
            /**
            * @dev Getter function for variables for the requestId being currently mined(currentRequestId)
            * @return current challenge, curretnRequestId, level of difficulty, api/query string, and granularity(number of decimals requested), total tip for the request 
            */
            function getCurrentVariables() external view returns(bytes32, uint, uint,string memory,uint,uint){    
                return tellor.getCurrentVariables();
            }
        
            /**
            * @dev Checks if a given hash of miner,requestId has been disputed
            * @param _hash is the sha256(abi.encodePacked(_miners[2],_requestId));
            * @return uint disputeId
            */
            function getDisputeIdByDisputeHash(bytes32 _hash) external view returns(uint){
                return  tellor.getDisputeIdByDisputeHash(_hash);
            }
            
        
            /**
            * @dev Checks for uint variables in the disputeUintVars mapping based on the disuputeId
            * @param _disputeId is the dispute id;
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is 
            * the variables/strings used to save the data in the mapping. The variables names are  
            * commented out under the disputeUintVars under the Dispute struct
            * @return uint value for the bytes32 data submitted
            */
            function getDisputeUintVars(uint _disputeId,bytes32 _data) external view returns(uint){
                return tellor.getDisputeUintVars(_disputeId,_data);
            }
        
        
            /**
            * @dev Gets the a value for the latest timestamp available
            * @return value for timestamp of last proof of work submited
            * @return true if the is a timestamp for the lastNewValue
            */
            function getLastNewValue() external view returns(uint,bool){
                return tellor.getLastNewValue();
            }
        
        
            /**
            * @dev Gets the a value for the latest timestamp available
            * @param _requestId being requested
            * @return value for timestamp of last proof of work submited and if true if it exist or 0 and false if it doesn't
            */
            function getLastNewValueById(uint _requestId) external view returns(uint,bool){
                return tellor.getLastNewValueById(_requestId);
            }
                
        
            /**
            * @dev Gets blocknumber for mined timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up blocknumber
            * @return uint of the blocknumber which the dispute was mined
            */
            function getMinedBlockNum(uint _requestId, uint _timestamp) external view returns(uint){
                return tellor.getMinedBlockNum(_requestId,_timestamp);
            }
        
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up miners for
            * @return the 5 miners' addresses
            */
            function getMinersByRequestIdAndTimestamp(uint _requestId, uint _timestamp) external view returns(address[5] memory){
                return tellor.getMinersByRequestIdAndTimestamp(_requestId,_timestamp);
            }
        
        
            /**
            * @dev Get the name of the token
            * return string of the token name
            */
            function getName() external view returns(string memory){
                return tellor.getName();
            }
        
        
            /**
            * @dev Counts the number of values that have been submited for the request 
            * if called for the currentRequest being mined it can tell you how many miners have submitted a value for that
            * request so far
            * @param _requestId the requestId to look up
            * @return uint count of the number of values received for the requestId
            */
            function getNewValueCountbyRequestId(uint _requestId) external view returns(uint){
                return tellor.getNewValueCountbyRequestId(_requestId);
            }
        
        
            /**
            * @dev Getter function for the specified requestQ index
            * @param _index to look up in the requestQ array
            * @return uint of reqeuestId
            */
            function getRequestIdByRequestQIndex(uint _index) external view returns(uint){
                return tellor.getRequestIdByRequestQIndex(_index);
            }
        
        
            /**
            * @dev Getter function for requestId based on timestamp 
            * @param _timestamp to check requestId
            * @return uint of reqeuestId
            */
            function getRequestIdByTimestamp(uint _timestamp) external view returns(uint){    
                return tellor.getRequestIdByTimestamp(_timestamp);
            }
        
            /**
            * @dev Getter function for requestId based on the queryHash
            * @param _request is the hash(of string api and granularity) to check if a request already exists
            * @return uint requestId
            */
            function getRequestIdByQueryHash(bytes32 _request) external view returns(uint){    
                return tellor.getRequestIdByQueryHash(_request);
            }
        
        
            /**
            * @dev Getter function for the requestQ array
            * @return the requestQ arrray
            */
            function getRequestQ() view public returns(uint[51] memory){
                return tellor.getRequestQ();
            }
        
        
            /**
            * @dev Allowes access to the uint variables saved in the apiUintVars under the requestDetails struct
            * for the requestId specified
            * @param _requestId to look up
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is 
            * the variables/strings used to save the data in the mapping. The variables names are  
            * commented out under the apiUintVars under the requestDetails struct
            * @return uint value of the apiUintVars specified in _data for the requestId specified
            */
            function getRequestUintVars(uint _requestId,bytes32 _data) external view returns(uint){
                return tellor.getRequestUintVars(_requestId,_data);
            }
        
        
            /**
            * @dev Gets the API struct variables that are not mappings
            * @param _requestId to look up
            * @return string of api to query
            * @return string of symbol of api to query
            * @return bytes32 hash of string
            * @return bytes32 of the granularity(decimal places) requested
            * @return uint of index in requestQ array
            * @return uint of current payout/tip for this requestId
            */
            function getRequestVars(uint _requestId) external view returns(string memory, string memory,bytes32,uint, uint, uint) {
                return tellor.getRequestVars(_requestId);
            }
        
        
            /**
            * @dev This function allows users to retireve all information about a staker
            * @param _staker address of staker inquiring about
            * @return uint current state of staker
            * @return uint startDate of staking
            */
            function getStakerInfo(address _staker) external view returns(uint,uint){
                return tellor.getStakerInfo(_staker);
            }
            
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestampt to look up miners for
            * @return address[5] array of 5 addresses ofminers that mined the requestId
            */    
            function getSubmissionsByTimestamp(uint _requestId, uint _timestamp) external view returns(uint[5] memory){
                return tellor.getSubmissionsByTimestamp(_requestId,_timestamp);
            }
        
            /**
            * @dev Get the symbol of the token
            * return string of the token symbol
            */
            function getSymbol() external view returns(string memory){
                return tellor.getSymbol();
            } 
        
            /**
            * @dev Gets the timestamp for the value based on their index
            * @param _requestID is the requestId to look up
            * @param _index is the value index to look up
            * @return uint timestamp
            */
            function getTimestampbyRequestIDandIndex(uint _requestID, uint _index) external view returns(uint){
                return tellor.getTimestampbyRequestIDandIndex(_requestID,_index);
            }
        
        
            /**
            * @dev Getter for the variables saved under the TellorStorageStruct uintVars variable
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is 
            * the variables/strings used to save the data in the mapping. The variables names are  
            * commented out under the uintVars under the TellorStorageStruct struct
            * This is an example of how data is saved into the mapping within other functions: 
            * self.uintVars[keccak256("stakerCount")]
            * @return uint of specified variable  
            */ 
            function getUintVar(bytes32 _data) view public returns(uint){
                return tellor.getUintVar(_data);
            }
        
        
            /**
            * @dev Getter function for next requestId on queue/request with highest payout at time the function is called
            * @return onDeck/info on request with highest payout-- RequestId, Totaltips, and API query string
            */
            function getVariablesOnDeck() external view returns(uint, uint,string memory){    
                return tellor.getVariablesOnDeck();
            }
        
            
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up miners for
            * @return bool true if requestId/timestamp is under dispute
            */
            function isInDispute(uint _requestId, uint _timestamp) external view returns(bool){
                return tellor.isInDispute(_requestId,_timestamp);
            }
            
        
            /**
            * @dev Retreive value from oracle based on timestamp
            * @param _requestId being requested
            * @param _timestamp to retreive data/value from
            * @return value for timestamp submitted
            */
            function retrieveData(uint _requestId, uint _timestamp) external view returns (uint) {
                return tellor.retrieveData(_requestId,_timestamp);
            }
        
        
            /**
            * @dev Getter for the total_supply of oracle tokens
            * @return uint total supply
            */
            function totalSupply() external view returns (uint) {
               return tellor.totalSupply();
            }
        
        
        }
        
        /**
        * @title Tellor Master
        * @dev This is the Master contract with all tellor getter functions and delegate call to Tellor. 
        * The logic for the functions on this contract is saved on the TellorGettersLibrary, TellorTransfer, 
        * TellorGettersLibrary, and TellorStake
        */
        contract TellorMaster is TellorGetters{
            
            event NewTellorAddress(address _newTellor);
        
            /**
            * @dev The constructor sets the original `tellorStorageOwner` of the contract to the sender
            * account, the tellor contract to the Tellor master address and owner to the Tellor master owner address 
            * @param _tellorContract is the address for the tellor contract
            */
            constructor (address _tellorContract)  public{
                tellor.init();
                tellor.addressVars[keccak256("_owner")] = msg.sender;
                tellor.addressVars[keccak256("_deity")] = msg.sender;
                tellor.addressVars[keccak256("tellorContract")]= _tellorContract;
                emit NewTellorAddress(_tellorContract);
            }
            
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp 
            * @dev Only needs to be in library
            * @param _newDeity the new Deity in the contract
            */
        
            function changeDeity(address _newDeity) external{
                tellor.changeDeity(_newDeity);
            }
        
        
            /**
            * @dev  allows for the deity to make fast upgrades.  Deity should be 0 address if decentralized
            * @param _tellorContract the address of the new Tellor Contract
            */
            function changeTellorContract(address _tellorContract) external{
                tellor.changeTellorContract(_tellorContract);
            }
          
        
            /**
            * @dev This is the fallback function that allows contracts to call the tellor contract at the address stored
            */
            function () external payable {
                address addr = tellor.addressVars[keccak256("tellorContract")];
                bytes memory _calldata = msg.data;
                assembly {
                    let result := delegatecall(not(0), addr, add(_calldata, 0x20), mload(_calldata), 0, 0)
                    let size := returndatasize
                    let ptr := mload(0x40)
                    returndatacopy(ptr, 0, size)
                    // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
                    // if the call returned error data, forward it
                    switch result case 0 { revert(ptr, size) }
                    default { return(ptr, size) }
                }
            }
        }

        File 2 of 2: Tellor
        pragma solidity ^0.5.16;
        
        //Slightly modified SafeMath library - includes a min and max function, removes useless div function
        library SafeMath {
            function add(uint256 a, uint256 b) internal pure returns (uint256) {
                uint256 c = a + b;
                assert(c >= a);
                return c;
            }
        
            function add(int256 a, int256 b) internal pure returns (int256 c) {
                if (b > 0) {
                    c = a + b;
                    assert(c >= a);
                } else {
                    c = a + b;
                    assert(c <= a);
                }
            }
        
            function max(uint256 a, uint256 b) internal pure returns (uint256) {
                return a > b ? a : b;
            }
        
            function max(int256 a, int256 b) internal pure returns (uint256) {
                return a > b ? uint256(a) : uint256(b);
            }
        
            function min(uint256 a, uint256 b) internal pure returns (uint256) {
                return a < b ? a : b;
            }
        
            function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                uint256 c = a * b;
                assert(a == 0 || c / a == b);
                return c;
            }
        
            function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                assert(b <= a);
                return a - b;
            }
        
            function sub(int256 a, int256 b) internal pure returns (int256 c) {
                if (b > 0) {
                    c = a - b;
                    assert(c <= a);
                } else {
                    c = a - b;
                    assert(c >= a);
                }
        
            }
        }
        
        
        pragma solidity ^0.5.0;
        
        /**
         * @title Tellor Oracle Storage Library
         * @dev Contains all the variables/structs used by Tellor
         */
        
        library TellorStorage {
            //Internal struct for use in proof-of-work submission
            struct Details {
                uint256 value;
                address miner;
            }
        
            struct Dispute {
                bytes32 hash; //unique hash of dispute: keccak256(_miner,_requestId,_timestamp)
                int256 tally; //current tally of votes for - against measure
                bool executed; //is the dispute settled
                bool disputeVotePassed; //did the vote pass?
                bool isPropFork; //true for fork proposal NEW
                address reportedMiner; //miner who alledgedly submitted the 'bad value' will get disputeFee if dispute vote fails
                address reportingParty; //miner reporting the 'bad value'-pay disputeFee will get reportedMiner's stake if dispute vote passes
                address proposedForkAddress; //new fork address (if fork proposal)
                mapping(bytes32 => uint256) disputeUintVars;
                //Each of the variables below is saved in the mapping disputeUintVars for each disputeID
                //e.g. TellorStorageStruct.DisputeById[disputeID].disputeUintVars[keccak256("requestId")]
                //These are the variables saved in this mapping:
                // uint keccak256("requestId");//apiID of disputed value
                // uint keccak256("timestamp");//timestamp of distputed value
                // uint keccak256("value"); //the value being disputed
                // uint keccak256("minExecutionDate");//7 days from when dispute initialized
                // uint keccak256("numberOfVotes");//the number of parties who have voted on the measure
                // uint keccak256("blockNumber");// the blocknumber for which votes will be calculated from
                // uint keccak256("minerSlot"); //index in dispute array
                // uint keccak256("fee"); //fee paid corresponding to dispute
                mapping(address => bool) voted; //mapping of address to whether or not they voted
            }
        
            struct StakeInfo {
                uint256 currentStatus; //0-not Staked, 1=Staked, 2=LockedForWithdraw 3= OnDispute 4=ReadyForUnlocking 5=Unlocked
                uint256 startDate; //stake start date
            }
        
            //Internal struct to allow balances to be queried by blocknumber for voting purposes
            struct Checkpoint {
                uint128 fromBlock; // fromBlock is the block number that the value was generated from
                uint128 value; // value is the amount of tokens at a specific block number
            }
        
            struct Request {
                string queryString; //id to string api
                string dataSymbol; //short name for api request
                bytes32 queryHash; //hash of api string and granularity e.g. keccak256(abi.encodePacked(_sapi,_granularity))
                uint256[] requestTimestamps; //array of all newValueTimestamps requested
                mapping(bytes32 => uint256) apiUintVars;
                //Each of the variables below is saved in the mapping apiUintVars for each api request
                //e.g. requestDetails[_requestId].apiUintVars[keccak256("totalTip")]
                //These are the variables saved in this mapping:
                // uint keccak256("granularity"); //multiplier for miners
                // uint keccak256("requestQPosition"); //index in requestQ
                // uint keccak256("totalTip");//bonus portion of payout
                mapping(uint256 => uint256) minedBlockNum; //[apiId][minedTimestamp]=>block.number
                //This the time series of finalValues stored by the contract where uint UNIX timestamp is mapped to value
                mapping(uint256 => uint256) finalValues;
                mapping(uint256 => bool) inDispute; //checks if API id is in dispute or finalized.
                mapping(uint256 => address[5]) minersByValue;
                mapping(uint256 => uint256[5]) valuesByTimestamp;
            }
        
            struct TellorStorageStruct {
                bytes32 currentChallenge; //current challenge to be solved
                uint256[51] requestQ; //uint50 array of the top50 requests by payment amount
                uint256[] newValueTimestamps; //array of all timestamps requested
                Details[5] currentMiners; //This struct is for organizing the five mined values to find the median
                mapping(bytes32 => address) addressVars;
                //Address fields in the Tellor contract are saved the addressVars mapping
                //e.g. addressVars[keccak256("tellorContract")] = address
                //These are the variables saved in this mapping:
                // address keccak256("tellorContract");//Tellor address
                // address  keccak256("_owner");//Tellor Owner address
                // address  keccak256("_deity");//Tellor Owner that can do things at will
                // address  keccak256("pending_owner"); // The proposed new owner
                mapping(bytes32 => uint256) uintVars;
                //uint fields in the Tellor contract are saved the uintVars mapping
                //e.g. uintVars[keccak256("decimals")] = uint
                //These are the variables saved in this mapping:
                // keccak256("decimals");    //18 decimal standard ERC20
                // keccak256("disputeFee");//cost to dispute a mined value
                // keccak256("disputeCount");//totalHistoricalDisputes
                // keccak256("total_supply"); //total_supply of the token in circulation
                // keccak256("stakeAmount");//stakeAmount for miners (we can cut gas if we just hardcode it in...or should it be variable?)
                // keccak256("stakerCount"); //number of parties currently staked
                // keccak256("timeOfLastNewValue"); // time of last challenge solved
                // keccak256("difficulty"); // Difficulty of current block
                // keccak256("currentTotalTips"); //value of highest api/timestamp PayoutPool
                // keccak256("currentRequestId"); //API being mined--updates with the ApiOnQ Id
                // keccak256("requestCount"); // total number of requests through the system
                // keccak256("slotProgress");//Number of miners who have mined this value so far
                // keccak256("miningReward");//Mining Reward in PoWo tokens given to all miners per value
                // keccak256("timeTarget"); //The time between blocks (mined Oracle values)
                // keccak256("_tblock"); //
                // keccak256("runningTips"); // VAriable to track running tips
                // keccak256("currentReward"); // The current reward
                // keccak256("devShare"); // The amount directed towards th devShare
                // keccak256("currentTotalTips"); //
                //This is a boolean that tells you if a given challenge has been completed by a given miner
                mapping(bytes32 => mapping(address => bool)) minersByChallenge;
                mapping(uint256 => uint256) requestIdByTimestamp; //minedTimestamp to apiId
                mapping(uint256 => uint256) requestIdByRequestQIndex; //link from payoutPoolIndex (position in payout pool array) to apiId
                mapping(uint256 => Dispute) disputesById; //disputeId=> Dispute details
                mapping(address => Checkpoint[]) balances; //balances of a party given blocks
                mapping(address => mapping(address => uint256)) allowed; //allowance for a given party and approver
                mapping(address => StakeInfo) stakerDetails; //mapping from a persons address to their staking info
                mapping(uint256 => Request) requestDetails; //mapping of apiID to details
                mapping(bytes32 => uint256) requestIdByQueryHash; // api bytes32 gets an id = to count of requests array
                mapping(bytes32 => uint256) disputeIdByDisputeHash; //maps a hash to an ID for each dispute
            }
        }
        
        
        pragma solidity ^0.5.16;
        
        /**
        * @title Tellor Transfer
        * @dev Contains the methods related to transfers and ERC20. Tellor.sol and TellorGetters.sol
        * reference this library for function's logic.
        */
        library TellorTransfer {
            using SafeMath for uint256;
        
            event Approval(address indexed _owner, address indexed _spender, uint256 _value); //ERC20 Approval event
            event Transfer(address indexed _from, address indexed _to, uint256 _value); //ERC20 Transfer Event
        
            bytes32 public constant stakeAmount = 0x7be108969d31a3f0b261465c71f2b0ba9301cd914d55d9091c3b36a49d4d41b2; //keccak256("stakeAmount")
        
            /*Functions*/
        
            /**
            * @dev Allows for a transfer of tokens to _to
            * @param _to The address to send tokens to
            * @param _amount The amount of tokens to send
            * @return true if transfer is successful
            */
            function transfer(TellorStorage.TellorStorageStruct storage self, address _to, uint256 _amount) public returns (bool success) {
                doTransfer(self, msg.sender, _to, _amount);
                return true;
            }
        
            /**
            * @notice Send _amount tokens to _to from _from on the condition it
            * is approved by _from
            * @param _from The address holding the tokens being transferred
            * @param _to The address of the recipient
            * @param _amount The amount of tokens to be transferred
            * @return True if the transfer was successful
            */
            function transferFrom(TellorStorage.TellorStorageStruct storage self, address _from, address _to, uint256 _amount)
                public
                returns (bool success)
            {
                require(self.allowed[_from][msg.sender] >= _amount, "Allowance is wrong");
                self.allowed[_from][msg.sender] -= _amount;
                doTransfer(self, _from, _to, _amount);
                return true;
            }
        
            /**
            * @dev This function approves a _spender an _amount of tokens to use
            * @param _spender address
            * @param _amount amount the spender is being approved for
            * @return true if spender appproved successfully
            */
            function approve(TellorStorage.TellorStorageStruct storage self, address _spender, uint256 _amount) public returns (bool) {
                require(_spender != address(0), "Spender is 0-address");
                require(self.allowed[msg.sender][_spender] == 0 || _amount == 0, "Spender is already approved");
                self.allowed[msg.sender][_spender] = _amount;
                emit Approval(msg.sender, _spender, _amount);
                return true;
            }
        
            /**
            * @param _user address of party with the balance
            * @param _spender address of spender of parties said balance
            * @return Returns the remaining allowance of tokens granted to the _spender from the _user
            */
            function allowance(TellorStorage.TellorStorageStruct storage self, address _user, address _spender) public view returns (uint256) {
                return self.allowed[_user][_spender];
            }
        
            /**
            * @dev Completes POWO transfers by updating the balances on the current block number
            * @param _from address to transfer from
            * @param _to addres to transfer to
            * @param _amount to transfer
            */
            function doTransfer(TellorStorage.TellorStorageStruct storage self, address _from, address _to, uint256 _amount) public {
                require(_amount != 0, "Tried to send non-positive amount");
                require(_to != address(0), "Receiver is 0 address");
                require(allowedToTrade(self, _from, _amount), "Should have sufficient balance to trade");
                uint256 previousBalance = balanceOf(self, _from);
                updateBalanceAtNow(self.balances[_from], previousBalance - _amount);
                previousBalance = balanceOf(self,_to);
                require(previousBalance + _amount >= previousBalance, "Overflow happened"); // Check for overflow
                updateBalanceAtNow(self.balances[_to], previousBalance + _amount);
                emit Transfer(_from, _to, _amount);
            }
        
            /**
            * @dev Gets balance of owner specified
            * @param _user is the owner address used to look up the balance
            * @return Returns the balance associated with the passed in _user
            */
            function balanceOf(TellorStorage.TellorStorageStruct storage self, address _user) public view returns (uint256) {
                return balanceOfAt(self, _user, block.number);
            }
        
            /**
            * @dev Queries the balance of _user at a specific _blockNumber
            * @param _user The address from which the balance will be retrieved
            * @param _blockNumber The block number when the balance is queried
            * @return The balance at _blockNumber specified
            */
            function balanceOfAt(TellorStorage.TellorStorageStruct storage self, address _user, uint256 _blockNumber) public view returns (uint256) {
                TellorStorage.Checkpoint[] storage checkpoints = self.balances[_user];
                if (checkpoints.length == 0|| checkpoints[0].fromBlock > _blockNumber) {
                    return 0;
                } else {
                    if (_blockNumber >= checkpoints[checkpoints.length - 1].fromBlock) return checkpoints[checkpoints.length - 1].value;
                    // Binary search of the value in the array
                    uint256 min = 0;
                    uint256 max = checkpoints.length - 2;
                    while (max > min) {
                        uint256 mid = (max + min + 1) / 2;
                        if  (checkpoints[mid].fromBlock ==_blockNumber){
                            return checkpoints[mid].value;
                        }else if(checkpoints[mid].fromBlock < _blockNumber) {
                            min = mid;
                        } else {
                            max = mid - 1;
                        }
                    }
                    return checkpoints[min].value;
                }
            }
            /**
            * @dev This function returns whether or not a given user is allowed to trade a given amount
            * and removing the staked amount from their balance if they are staked
            * @param _user address of user
            * @param _amount to check if the user can spend
            * @return true if they are allowed to spend the amount being checked
            */
            function allowedToTrade(TellorStorage.TellorStorageStruct storage self, address _user, uint256 _amount) public view returns (bool) { 
                if (self.stakerDetails[_user].currentStatus != 0 && self.stakerDetails[_user].currentStatus < 5) {
                    //Subtracts the stakeAmount from balance if the _user is staked
                    if (balanceOf(self, _user)- self.uintVars[stakeAmount] >= _amount) {
                        return true;
                    }
                    return false;
                } 
                return (balanceOf(self, _user) >= _amount);
            }
        
            /**
            * @dev Updates balance for from and to on the current block number via doTransfer
            * @param checkpoints gets the mapping for the balances[owner]
            * @param _value is the new balance
            */
            function updateBalanceAtNow(TellorStorage.Checkpoint[] storage checkpoints, uint256 _value) public {
                if (checkpoints.length == 0 || checkpoints[checkpoints.length - 1].fromBlock != block.number) {
                   checkpoints.push(TellorStorage.Checkpoint({
                        fromBlock : uint128(block.number),
                        value : uint128(_value)
                    }));
                } else {
                    TellorStorage.Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length - 1];
                    oldCheckPoint.value = uint128(_value);
                }
            }
        }
        
        
        pragma solidity ^0.5.16;
        
        
        
        /**
        * @title Tellor Dispute
        * @dev Contains the methods related to disputes. Tellor.sol references this library for function's logic.
        */
        
        library TellorDispute {
            using SafeMath for uint256;
            using SafeMath for int256;
        
            //emitted when a new dispute is initialized
            event NewDispute(uint256 indexed _disputeId, uint256 indexed _requestId, uint256 _timestamp, address _miner);
            //emitted when a new vote happens
            event Voted(uint256 indexed _disputeID, bool _position, address indexed _voter, uint256 indexed _voteWeight);
            //emitted upon dispute tally
            event DisputeVoteTallied(uint256 indexed _disputeID, int256 _result, address indexed _reportedMiner, address _reportingParty, bool _active);
            event NewTellorAddress(address _newTellor); //emmited when a proposed fork is voted true
        
            /*Functions*/
        
            /**
            * @dev Helps initialize a dispute by assigning it a disputeId
            * when a miner returns a false on the validate array(in Tellor.ProofOfWork) it sends the
            * invalidated value information to POS voting
            * @param _requestId being disputed
            * @param _timestamp being disputed
            * @param _minerIndex the index of the miner that submitted the value being disputed. Since each official value
            * requires 5 miners to submit a value.
            */
            function beginDispute(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _timestamp, uint256 _minerIndex) public {
                TellorStorage.Request storage _request = self.requestDetails[_requestId];
                require(_request.minedBlockNum[_timestamp] != 0, "Mined block is 0");
                require(_minerIndex < 5, "Miner index is wrong");
        
                //_miner is the miner being disputed. For every mined value 5 miners are saved in an array and the _minerIndex
                //provided by the party initiating the dispute
                address _miner = _request.minersByValue[_timestamp][_minerIndex];
                bytes32 _hash = keccak256(abi.encodePacked(_miner, _requestId, _timestamp));
        
        
        
                //Increase the dispute count by 1
                uint256 disputeId = self.uintVars[keccak256("disputeCount")] + 1;
                self.uintVars[keccak256("disputeCount")] = disputeId;
        
                //Sets the new disputeCount as the disputeId
        
                        //Ensures that a dispute is not already open for the that miner, requestId and timestamp
                uint256 hashId = self.disputeIdByDisputeHash[_hash];
                if(hashId != 0){
                    self.disputesById[disputeId].disputeUintVars[keccak256("origID")] = hashId;
        
                }
                else{
                    self.disputeIdByDisputeHash[_hash] = disputeId;
                    hashId = disputeId;
                }
                uint256 origID = hashId;
                uint256 dispRounds = self.disputesById[origID].disputeUintVars[keccak256("disputeRounds")] + 1;
                self.disputesById[origID].disputeUintVars[keccak256("disputeRounds")] = dispRounds;
                self.disputesById[origID].disputeUintVars[keccak256(abi.encode(dispRounds))] = disputeId;
                if(disputeId != origID){
                    uint256 lastID =  self.disputesById[origID].disputeUintVars[keccak256(abi.encode(dispRounds-1))];
                    require(self.disputesById[lastID].disputeUintVars[keccak256("minExecutionDate")] <= now, "Dispute is already open");
                    if(self.disputesById[lastID].executed){
                        require(now - self.disputesById[lastID].disputeUintVars[keccak256("tallyDate")] <= 1 days, "Time for voting haven't elapsed");
                    }
                }
                uint256 _fee;
                if (_minerIndex == 2) {
                    self.requestDetails[_requestId].apiUintVars[keccak256("disputeCount")] = self.requestDetails[_requestId].apiUintVars[keccak256("disputeCount")] +1;
                    //update dispute fee for this case
                    _fee = self.uintVars[keccak256("stakeAmount")]*self.requestDetails[_requestId].apiUintVars[keccak256("disputeCount")];
                } else {
        
                    _fee = self.uintVars[keccak256("disputeFee")] * dispRounds;
                }
        
                //maps the dispute to the Dispute struct
                self.disputesById[disputeId] = TellorStorage.Dispute({
                    hash: _hash,
                    isPropFork: false,
                    reportedMiner: _miner,
                    reportingParty: msg.sender,
                    proposedForkAddress: address(0),
                    executed: false,
                    disputeVotePassed: false,
                    tally: 0
                });
        
                //Saves all the dispute variables for the disputeId
                self.disputesById[disputeId].disputeUintVars[keccak256("requestId")] = _requestId;
                self.disputesById[disputeId].disputeUintVars[keccak256("timestamp")] = _timestamp;
                self.disputesById[disputeId].disputeUintVars[keccak256("value")] = _request.valuesByTimestamp[_timestamp][_minerIndex];
                self.disputesById[disputeId].disputeUintVars[keccak256("minExecutionDate")] = now + 2 days * dispRounds;
                self.disputesById[disputeId].disputeUintVars[keccak256("blockNumber")] = block.number;
                self.disputesById[disputeId].disputeUintVars[keccak256("minerSlot")] = _minerIndex;
                self.disputesById[disputeId].disputeUintVars[keccak256("fee")] = _fee;
                TellorTransfer.doTransfer(self, msg.sender, address(this),_fee);
        
           
        
                //Values are sorted as they come in and the official value is the median of the first five
                //So the "official value" miner is always minerIndex==2. If the official value is being
                //disputed, it sets its status to inDispute(currentStatus = 3) so that users are made aware it is under dispute
                if (_minerIndex == 2) {
                    _request.inDispute[_timestamp] = true;
                    _request.finalValues[_timestamp] = 0;
                }
                self.stakerDetails[_miner].currentStatus = 3;
                emit NewDispute(disputeId, _requestId, _timestamp, _miner);
            }
        
            /**
            * @dev Allows token holders to vote
            * @param _disputeId is the dispute id
            * @param _supportsDispute is the vote (true=the dispute has basis false = vote against dispute)
            */
            function vote(TellorStorage.TellorStorageStruct storage self, uint256 _disputeId, bool _supportsDispute) public {
                TellorStorage.Dispute storage disp = self.disputesById[_disputeId];
        
                //Get the voteWeight or the balance of the user at the time/blockNumber the disupte began
                uint256 voteWeight = TellorTransfer.balanceOfAt(self, msg.sender, disp.disputeUintVars[keccak256("blockNumber")]);
        
                //Require that the msg.sender has not voted
                require(disp.voted[msg.sender] != true, "Sender has already voted");
        
                //Requre that the user had a balance >0 at time/blockNumber the disupte began
                require(voteWeight != 0, "User balance is 0");
        
                //ensures miners that are under dispute cannot vote
                require(self.stakerDetails[msg.sender].currentStatus != 3, "Miner is under dispute");
        
                //Update user voting status to true
                disp.voted[msg.sender] = true;
        
                //Update the number of votes for the dispute
                disp.disputeUintVars[keccak256("numberOfVotes")] += 1;
        
                //If the user supports the dispute increase the tally for the dispute by the voteWeight
                //otherwise decrease it
                if (_supportsDispute) {
                    disp.tally = disp.tally.add(int256(voteWeight));
                } else {
                    disp.tally = disp.tally.sub(int256(voteWeight));
                }
        
                //Let the network know the user has voted on the dispute and their casted vote
                emit Voted(_disputeId, _supportsDispute, msg.sender, voteWeight);
            }
        
            /**
            * @dev tallies the votes and locks the stake disbursement(currentStatus = 4) if the vote passes
            * @param _disputeId is the dispute id
            */
            function tallyVotes(TellorStorage.TellorStorageStruct storage self, uint256 _disputeId) public {
                TellorStorage.Dispute storage disp = self.disputesById[_disputeId];
        
                //Ensure this has not already been executed/tallied
                require(disp.executed == false, "Dispute has been already executed");
                require(now >= disp.disputeUintVars[keccak256("minExecutionDate")], "Time for voting haven't elapsed");
                require(disp.reportingParty != address(0), "reporting Party is address 0");
                int256  _tally = disp.tally;
                if (_tally > 0) {
                    //Set the dispute state to passed/true
                    disp.disputeVotePassed = true;
                }
                //If the vote is not a proposed fork
                if (disp.isPropFork == false) {
                        //Ensure the time for voting has elapsed
                            TellorStorage.StakeInfo storage stakes = self.stakerDetails[disp.reportedMiner];
                            //If the vote for disputing a value is succesful(disp.tally >0) then unstake the reported
                            // miner and transfer the stakeAmount and dispute fee to the reporting party
                            if(stakes.currentStatus == 3){
                                stakes.currentStatus = 4;
                            }
                } else if (uint(_tally) >= ((self.uintVars[keccak256("total_supply")] * 10) / 100)) {
                    emit NewTellorAddress(disp.proposedForkAddress);
                }
                disp.disputeUintVars[keccak256("tallyDate")] = now;
                disp.executed = true;
                emit DisputeVoteTallied(_disputeId, _tally, disp.reportedMiner, disp.reportingParty, disp.disputeVotePassed);
            }
        
            /**
            * @dev Allows for a fork to be proposed
            * @param _propNewTellorAddress address for new proposed Tellor
            */
            function proposeFork(TellorStorage.TellorStorageStruct storage self, address _propNewTellorAddress) public {
                bytes32 _hash = keccak256(abi.encode(_propNewTellorAddress));
                TellorTransfer.doTransfer(self, msg.sender, address(this), 100e18); //This is the fork fee (just 100 tokens flat, no refunds)
                self.uintVars[keccak256("disputeCount")]++;
                uint256 disputeId = self.uintVars[keccak256("disputeCount")];
                if(self.disputeIdByDisputeHash[_hash] != 0){
                    self.disputesById[disputeId].disputeUintVars[keccak256("origID")] = self.disputeIdByDisputeHash[_hash];
                }
                else{
                    self.disputeIdByDisputeHash[_hash] = disputeId;
                }
                uint256 origID = self.disputeIdByDisputeHash[_hash];
        
                self.disputesById[origID].disputeUintVars[keccak256("disputeRounds")]++;
                uint256 dispRounds = self.disputesById[origID].disputeUintVars[keccak256("disputeRounds")];
                self.disputesById[origID].disputeUintVars[keccak256(abi.encode(dispRounds))] = disputeId;
                if(disputeId != origID){
                    uint256 lastID =  self.disputesById[origID].disputeUintVars[keccak256(abi.encode(dispRounds-1))];
                    require(self.disputesById[lastID].disputeUintVars[keccak256("minExecutionDate")] <= now, "Dispute is already open");
                    if(self.disputesById[lastID].executed){
                        require(now - self.disputesById[lastID].disputeUintVars[keccak256("tallyDate")] <= 1 days, "Time for voting haven't elapsed");
                    }
                }
                self.disputesById[disputeId] = TellorStorage.Dispute({
                    hash: _hash,
                    isPropFork: true,
                    reportedMiner: msg.sender,
                    reportingParty: msg.sender,
                    proposedForkAddress: _propNewTellorAddress,
                    executed: false,
                    disputeVotePassed: false,
                    tally: 0
                });
                self.disputesById[disputeId].disputeUintVars[keccak256("blockNumber")] = block.number;
                self.disputesById[disputeId].disputeUintVars[keccak256("minExecutionDate")] = now + 7 days;
            }
        
            /**
            * @dev Updates the Tellor address after a proposed fork has 
            * passed the vote and day has gone by without a dispute
            * @param _disputeId the disputeId for the proposed fork
            */
            function updateTellor(TellorStorage.TellorStorageStruct storage self, uint _disputeId) public {
                bytes32 _hash = self.disputesById[_disputeId].hash;
                uint256 origID = self.disputeIdByDisputeHash[_hash];
                uint256 lastID =  self.disputesById[origID].disputeUintVars[keccak256(abi.encode(self.disputesById[origID].disputeUintVars[keccak256("disputeRounds")]))];
                TellorStorage.Dispute storage disp = self.disputesById[lastID];
                require(disp.disputeVotePassed == true, "vote needs to pass");
                require(now - disp.disputeUintVars[keccak256("tallyDate")] > 1 days, "Time for voting for further disputes has not passed");
                self.addressVars[keccak256("tellorContract")] = disp.proposedForkAddress;
            }
        
            /**
            * @dev Allows disputer to unlock the dispute fee
            * @param _disputeId to unlock fee from
            */
            function unlockDisputeFee (TellorStorage.TellorStorageStruct storage self, uint _disputeId) public {
                uint256 origID = self.disputeIdByDisputeHash[self.disputesById[_disputeId].hash];
                uint256 lastID =  self.disputesById[origID].disputeUintVars[keccak256(abi.encode(self.disputesById[origID].disputeUintVars[keccak256("disputeRounds")]))];
                if(lastID == 0){
                    lastID = origID;
                }
                TellorStorage.Dispute storage disp = self.disputesById[origID];
                TellorStorage.Dispute storage last = self.disputesById[lastID];
                        //disputeRounds is increased by 1 so that the _id is not a negative number when it is the first time a dispute is initiated
                uint256 dispRounds = disp.disputeUintVars[keccak256("disputeRounds")];
                if(dispRounds == 0){
                  dispRounds = 1;  
                }
                uint256 _id;
                require(disp.disputeUintVars[keccak256("paid")] == 0,"already paid out");
                require(now - last.disputeUintVars[keccak256("tallyDate")] > 1 days, "Time for voting haven't elapsed");
                TellorStorage.StakeInfo storage stakes = self.stakerDetails[disp.reportedMiner];
                disp.disputeUintVars[keccak256("paid")] = 1;
                if (last.disputeVotePassed == true){
                        //Changing the currentStatus and startDate unstakes the reported miner and transfers the stakeAmount
                        stakes.startDate = now - (now % 86400);
        
                        //Reduce the staker count
                        self.uintVars[keccak256("stakerCount")] -= 1;
        
                        //Update the minimum dispute fee that is based on the number of stakers 
                        updateMinDisputeFee(self);
                        //Decreases the stakerCount since the miner's stake is being slashed
                        if(stakes.currentStatus == 4){
                            stakes.currentStatus = 5;
                            TellorTransfer.doTransfer(self,disp.reportedMiner,disp.reportingParty,self.uintVars[keccak256("stakeAmount")]);
                            stakes.currentStatus =0 ;
                        }
                        for(uint i = 0; i < dispRounds;i++){
                            _id = disp.disputeUintVars[keccak256(abi.encode(dispRounds-i))];
                            if(_id == 0){
                                _id = origID;
                            }
                            TellorStorage.Dispute storage disp2 = self.disputesById[_id];
                                //transfer fee adjusted based on number of miners if the minerIndex is not 2(official value)
                            TellorTransfer.doTransfer(self,address(this), disp2.reportingParty, disp2.disputeUintVars[keccak256("fee")]);
                        }
                    }
                    else {
                        stakes.currentStatus = 1;
                        TellorStorage.Request storage _request = self.requestDetails[disp.disputeUintVars[keccak256("requestId")]];
                        if(disp.disputeUintVars[keccak256("minerSlot")] == 2) {
                            //note we still don't put timestamp back into array (is this an issue? (shouldn't be))
                          _request.finalValues[disp.disputeUintVars[keccak256("timestamp")]] = disp.disputeUintVars[keccak256("value")];
                        }
                        if (_request.inDispute[disp.disputeUintVars[keccak256("timestamp")]] == true) {
                            _request.inDispute[disp.disputeUintVars[keccak256("timestamp")]] = false;
                        }
                        for(uint i = 0; i < dispRounds;i++){
                            _id = disp.disputeUintVars[keccak256(abi.encode(dispRounds-i))];
                            if(_id != 0){
                                last = self.disputesById[_id];//handling if happens during an upgrade
                            }
                            TellorTransfer.doTransfer(self,address(this),last.reportedMiner,self.disputesById[_id].disputeUintVars[keccak256("fee")]);
                        }
                    }
        
                    if (disp.disputeUintVars[keccak256("minerSlot")] == 2) {
                        self.requestDetails[disp.disputeUintVars[keccak256("requestId")]].apiUintVars[keccak256("disputeCount")]--;
                    } 
            }
        
            /**
            * @dev This function upates the minimun dispute fee as a function of the amount
            * of staked miners
            */
            function updateMinDisputeFee(TellorStorage.TellorStorageStruct storage self) public {
                uint256 stakeAmount = self.uintVars[keccak256("stakeAmount")];
                uint256 targetMiners = self.uintVars[keccak256("targetMiners")];
                self.uintVars[keccak256("disputeFee")] = SafeMath.max(15e18,
                        (stakeAmount-(stakeAmount*(SafeMath.min(targetMiners,self.uintVars[keccak256("stakerCount")])*1000)/
                        targetMiners)/1000));
            }
        }
        
        
        pragma solidity ^0.5.16;
        
        //Functions for retrieving min and Max in 51 length array (requestQ)
        //Taken partly from: https://github.com/modular-network/ethereum-libraries-array-utils/blob/master/contracts/Array256Lib.sol
        
        library Utilities {
            /**
            * @dev Returns the max value in an array.
            * The zero position here is ignored. It's because 
            * there's no null in solidity and we map each address 
            * to an index in this array. So when we get 51 parties, 
            * and one person is kicked out of the top 50, we 
            * assign them a 0, and when you get mined and pulled 
            * out of the top 50, also a 0. So then lot's of parties 
            * will have zero as the index so we made the array run 
            * from 1-51 with zero as nothing.
            * @param data is the array to calculate max from
            * @return max amount and its index within the array
            */
            function getMax(uint256[51] memory data) internal pure returns (uint256 max, uint256 maxIndex) {
                maxIndex = 1;
                max = data[maxIndex];
                for (uint256 i = 2; i < data.length; i++) {
                    if (data[i] > max) {
                        max = data[i];
                        maxIndex = i;
                    }
                }
            }
        
            /**
            * @dev Returns the minimum value in an array.
            * @param data is the array to calculate min from
            * @return min amount and its index within the array
            */
            function getMin(uint256[51] memory data) internal pure returns (uint256 min, uint256 minIndex) {
                minIndex = data.length - 1;
                min = data[minIndex];
                for (uint256 i = data.length - 2; i > 0; i--) {
                    if (data[i] < min) {
                        min = data[i];
                        minIndex = i;
                    }
                }
            }
        
            /**
            * @dev Returns the 5 requestsId's with the top payouts in an array.
            * @param data is the array to get the top 5 from
            * @return to 5 max amounts and their respective index within the array
            */
            function getMax5(uint256[51] memory data) internal pure returns (uint256[5] memory max, uint256[5] memory maxIndex) {
                uint256 min5 = data[1];
                uint256 minI = 0;
                for(uint256 j=0;j<5;j++){
                    max[j]= data[j+1];//max[0]=data[1]
                    maxIndex[j] = j+1;//maxIndex[0]= 1
                    if(max[j] < min5){
                        min5 = max[j];
                        minI = j;
                    }
                }
                for(uint256 i = 6; i < data.length; i++) {
                    if (data[i] > min5) {
                        max[minI] = data[i];
                        maxIndex[minI] = i;
                        min5 = data[i];
                        for(uint256 j=0;j<5;j++){
                            if(max[j] < min5){
                                min5 = max[j];
                                minI = j;
                            }
                        }
                    }
                }
            }
        }
        
        
        pragma solidity ^0.5.16;
        
        
        /**
        * itle Tellor Stake
        * @dev Contains the methods related to miners staking and unstaking. Tellor.sol
        * references this library for function's logic.
        */
        
        library TellorStake {
            event NewStake(address indexed _sender); //Emits upon new staker
            event StakeWithdrawn(address indexed _sender); //Emits when a staker is now no longer staked
            event StakeWithdrawRequested(address indexed _sender); //Emits when a staker begins the 7 day withdraw period
        
            /*Functions*/
            /**
            * @dev This function allows stakers to request to withdraw their stake (no longer stake)
            * once they lock for withdraw(stakes.currentStatus = 2) they are locked for 7 days before they
            * can withdraw the deposit
            */
            function requestStakingWithdraw(TellorStorage.TellorStorageStruct storage self) public {
                TellorStorage.StakeInfo storage stakes = self.stakerDetails[msg.sender];
                //Require that the miner is staked
                require(stakes.currentStatus == 1, "Miner is not staked");
        
                //Change the miner staked to locked to be withdrawStake
                stakes.currentStatus = 2;
        
                //Change the startDate to now since the lock up period begins now
                //and the miner can only withdraw 7 days later from now(check the withdraw function)
                stakes.startDate = now - (now % 86400);
        
                //Reduce the staker count
                self.uintVars[keccak256("stakerCount")] -= 1;
        
                //Update the minimum dispute fee that is based on the number of stakers 
                TellorDispute.updateMinDisputeFee(self);
                emit StakeWithdrawRequested(msg.sender);
            }
        
            /**
            * @dev This function allows users to withdraw their stake after a 7 day waiting period from request
            */
            function withdrawStake(TellorStorage.TellorStorageStruct storage self) public {
                TellorStorage.StakeInfo storage stakes = self.stakerDetails[msg.sender];
                //Require the staker has locked for withdraw(currentStatus ==2) and that 7 days have
                //passed by since they locked for withdraw
                require(now - (now % 86400) - stakes.startDate >= 7 days, "7 days didn't pass");
                require(stakes.currentStatus == 2, "Miner was not locked for withdrawal");
                stakes.currentStatus = 0;
                emit StakeWithdrawn(msg.sender);
            }
        
            /**
            * @dev This function allows miners to deposit their stake.
            */
            function depositStake(TellorStorage.TellorStorageStruct storage self) public {
                newStake(self, msg.sender);
                //self adjusting disputeFee
                TellorDispute.updateMinDisputeFee(self);
            }
        
            /**
            * @dev This function is used by the init function to succesfully stake the initial 5 miners.
            * The function updates their status/state and status start date so they are locked it so they can't withdraw
            * and updates the number of stakers in the system.
            */
            function newStake(TellorStorage.TellorStorageStruct storage self, address staker) internal {
                require(TellorTransfer.balanceOf(self, staker) >= self.uintVars[keccak256("stakeAmount")], "Balance is lower than stake amount");
                //Ensure they can only stake if they are not currrently staked or if their stake time frame has ended
                //and they are currently locked for witdhraw
                require(self.stakerDetails[staker].currentStatus == 0 || self.stakerDetails[staker].currentStatus == 2, "Miner is in the wrong state");
                self.uintVars[keccak256("stakerCount")] += 1;
                self.stakerDetails[staker] = TellorStorage.StakeInfo({
                    currentStatus: 1, //this resets their stake start date to today
                    startDate: now - (now % 86400)
                });
                emit NewStake(staker);
            }
        
            /**
            * @dev Getter function for the requestId being mined 
            * @return variables for the current minin event: Challenge, 5 RequestId, difficulty and Totaltips
            */
            function getNewCurrentVariables(TellorStorage.TellorStorageStruct storage self) internal view returns(bytes32 _challenge,uint[5] memory _requestIds,uint256 _difficulty, uint256 _tip){
                for(uint i=0;i<5;i++){
                    _requestIds[i] =  self.currentMiners[i].value;
                }
                return (self.currentChallenge,_requestIds,self.uintVars[keccak256("difficulty")],self.uintVars[keccak256("currentTotalTips")]);
            }
        
            /**
            * @dev Getter function for next requestId on queue/request with highest payout at time the function is called
            * @return onDeck/info on top 5 requests(highest payout)-- RequestId, Totaltips
            */
            function getNewVariablesOnDeck(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256[5] memory idsOnDeck, uint256[5] memory tipsOnDeck) {
                idsOnDeck = getTopRequestIDs(self);
                for(uint i = 0;i<5;i++){
                    tipsOnDeck[i] = self.requestDetails[idsOnDeck[i]].apiUintVars[keccak256("totalTip")];
                }
            }
            
            /**
            * @dev Getter function for the top 5 requests with highest payouts. This function is used within the getNewVariablesOnDeck function
            * @return uint256[5] is an array with the top 5(highest payout) _requestIds at the time the function is called
            */
            function getTopRequestIDs(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256[5] memory _requestIds) {
                uint256[5] memory _max;
                uint256[5] memory _index;
                (_max, _index) = Utilities.getMax5(self.requestQ);
                for(uint i=0;i<5;i++){
                    if(_max[i] != 0){
                        _requestIds[i] = self.requestIdByRequestQIndex[_index[i]];
                    }
                    else{
                        _requestIds[i] = self.currentMiners[4-i].value;
                    }
                }
            }
        
        
           
        }
        
        pragma solidity ^0.5.0;
        
        /**
        * @title Tellor Getters Library
        * @dev This is the getter library for all variables in the Tellor Tributes system. TellorGetters references this
        * libary for the getters logic
        */
        library TellorGettersLibrary {
            using SafeMath for uint256;
        
            event NewTellorAddress(address _newTellor); //emmited when a proposed fork is voted true
        
            /*Functions*/
        
            //The next two functions are onlyOwner functions.  For Tellor to be truly decentralized, we will need to transfer the Deity to the 0 address.
            //Only needs to be in library
            /**
            * @dev This function allows us to set a new Deity (or remove it)
            * @param _newDeity address of the new Deity of the tellor system
            */
            function changeDeity(TellorStorage.TellorStorageStruct storage self, address _newDeity) internal {
                require(self.addressVars[keccak256("_deity")] == msg.sender, "Sender is not deity");
                self.addressVars[keccak256("_deity")] = _newDeity;
            }
        
            //Only needs to be in library
            /**
            * @dev This function allows the deity to upgrade the Tellor System
            * @param _tellorContract address of new updated TellorCore contract
            */
            function changeTellorContract(TellorStorage.TellorStorageStruct storage self, address _tellorContract) internal {
                require(self.addressVars[keccak256("_deity")] == msg.sender, "Sender is not deity");
                self.addressVars[keccak256("tellorContract")] = _tellorContract;
                emit NewTellorAddress(_tellorContract);
            }
        
            /*Tellor Getters*/
        
            /**
            * @dev This function tells you if a given challenge has been completed by a given miner
            * @param _challenge the challenge to search for
            * @param _miner address that you want to know if they solved the challenge
            * @return true if the _miner address provided solved the
            */
            function didMine(TellorStorage.TellorStorageStruct storage self, bytes32 _challenge, address _miner) public view returns (bool) {
                return self.minersByChallenge[_challenge][_miner];
            }
        
            /**
            * @dev Checks if an address voted in a dispute
            * @param _disputeId to look up
            * @param _address of voting party to look up
            * @return bool of whether or not party voted
            */
            function didVote(TellorStorage.TellorStorageStruct storage self, uint256 _disputeId, address _address) internal view returns (bool) {
                return self.disputesById[_disputeId].voted[_address];
            }
        
            /**
            * @dev allows Tellor to read data from the addressVars mapping
            * @param _data is the keccak256("variable_name") of the variable that is being accessed.
            * These are examples of how the variables are saved within other functions:
            * addressVars[keccak256("_owner")]
            * addressVars[keccak256("tellorContract")]
            * @return address requested
            */
            function getAddressVars(TellorStorage.TellorStorageStruct storage self, bytes32 _data) internal view returns (address) {
                return self.addressVars[_data];
            }
        
            /**
            * @dev Gets all dispute variables
            * @param _disputeId to look up
            * @return bytes32 hash of dispute
            * @return bool executed where true if it has been voted on
            * @return bool disputeVotePassed
            * @return bool isPropFork true if the dispute is a proposed fork
            * @return address of reportedMiner
            * @return address of reportingParty
            * @return address of proposedForkAddress
            * @return uint of requestId
            * @return uint of timestamp
            * @return uint of value
            * @return uint of minExecutionDate
            * @return uint of numberOfVotes
            * @return uint of blocknumber
            * @return uint of minerSlot
            * @return uint of quorum
            * @return uint of fee
            * @return int count of the current tally
            */
            function getAllDisputeVars(TellorStorage.TellorStorageStruct storage self, uint256 _disputeId)
                internal
                view
                returns (bytes32, bool, bool, bool, address, address, address, uint256[9] memory, int256)
            {
                TellorStorage.Dispute storage disp = self.disputesById[_disputeId];
                return (
                    disp.hash,
                    disp.executed,
                    disp.disputeVotePassed,
                    disp.isPropFork,
                    disp.reportedMiner,
                    disp.reportingParty,
                    disp.proposedForkAddress,
                    [
                        disp.disputeUintVars[keccak256("requestId")],
                        disp.disputeUintVars[keccak256("timestamp")],
                        disp.disputeUintVars[keccak256("value")],
                        disp.disputeUintVars[keccak256("minExecutionDate")],
                        disp.disputeUintVars[keccak256("numberOfVotes")],
                        disp.disputeUintVars[keccak256("blockNumber")],
                        disp.disputeUintVars[keccak256("minerSlot")],
                        disp.disputeUintVars[keccak256("quorum")],
                        disp.disputeUintVars[keccak256("fee")]
                    ],
                    disp.tally
                );
            }
        
            /**
            * @dev Getter function for variables for the requestId being currently mined(currentRequestId)
            * @return current challenge, curretnRequestId, level of difficulty, api/query string, and granularity(number of decimals requested), total tip for the request
            */
            function getCurrentVariables(TellorStorage.TellorStorageStruct storage self)
                internal
                view
                returns (bytes32, uint256, uint256, string memory, uint256, uint256)
            {
                return (
                    self.currentChallenge,
                    self.uintVars[keccak256("currentRequestId")],
                    self.uintVars[keccak256("difficulty")],
                    self.requestDetails[self.uintVars[keccak256("currentRequestId")]].queryString,
                    self.requestDetails[self.uintVars[keccak256("currentRequestId")]].apiUintVars[keccak256("granularity")],
                    self.requestDetails[self.uintVars[keccak256("currentRequestId")]].apiUintVars[keccak256("totalTip")]
                );
            }
        
            /**
            * @dev Checks if a given hash of miner,requestId has been disputed
            * @param _hash is the sha256(abi.encodePacked(_miners[2],_requestId));
            * @return uint disputeId
            */
            function getDisputeIdByDisputeHash(TellorStorage.TellorStorageStruct storage self, bytes32 _hash) internal view returns (uint256) {
                return self.disputeIdByDisputeHash[_hash];
            }
        
            /**
            * @dev Checks for uint variables in the disputeUintVars mapping based on the disuputeId
            * @param _disputeId is the dispute id;
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is
            * the variables/strings used to save the data in the mapping. The variables names are
            * commented out under the disputeUintVars under the Dispute struct
            * @return uint value for the bytes32 data submitted
            */
            function getDisputeUintVars(TellorStorage.TellorStorageStruct storage self, uint256 _disputeId, bytes32 _data)
                internal
                view
                returns (uint256)
            {
                return self.disputesById[_disputeId].disputeUintVars[_data];
            }
        
            /**
            * @dev Gets the a value for the latest timestamp available
            * @return value for timestamp of last proof of work submited
            * @return true if the is a timestamp for the lastNewValue
            */
            function getLastNewValue(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256, bool) {
                return (
                    retrieveData(
                        self,
                        self.requestIdByTimestamp[self.uintVars[keccak256("timeOfLastNewValue")]],
                        self.uintVars[keccak256("timeOfLastNewValue")]
                    ),
                    true
                );
            }
        
            /**
            * @dev Gets the a value for the latest timestamp available
            * @param _requestId being requested
            * @return value for timestamp of last proof of work submited and if true if it exist or 0 and false if it doesn't
            */
            function getLastNewValueById(TellorStorage.TellorStorageStruct storage self, uint256 _requestId) internal view returns (uint256, bool) {
                TellorStorage.Request storage _request = self.requestDetails[_requestId];
                if (_request.requestTimestamps.length != 0) {
                    return (retrieveData(self, _requestId, _request.requestTimestamps[_request.requestTimestamps.length - 1]), true);
                } else {
                    return (0, false);
                }
            }
        
            /**
            * @dev Gets blocknumber for mined timestamp
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up blocknumber
            * @return uint of the blocknumber which the dispute was mined
            */
            function getMinedBlockNum(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _timestamp)
                internal
                view
                returns (uint256)
            {
                return self.requestDetails[_requestId].minedBlockNum[_timestamp];
            }
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp
            * @param _requestId to look up
            * @param _timestamp is the timestamp to look up miners for
            * @return the 5 miners' addresses
            */
            function getMinersByRequestIdAndTimestamp(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _timestamp)
                internal
                view
                returns (address[5] memory)
            {
                return self.requestDetails[_requestId].minersByValue[_timestamp];
            }
        
            /**
            * @dev Counts the number of values that have been submited for the request
            * if called for the currentRequest being mined it can tell you how many miners have submitted a value for that
            * request so far
            * @param _requestId the requestId to look up
            * @return uint count of the number of values received for the requestId
            */
            function getNewValueCountbyRequestId(TellorStorage.TellorStorageStruct storage self, uint256 _requestId) internal view returns (uint256) {
                return self.requestDetails[_requestId].requestTimestamps.length;
            }
        
            /**
            * @dev Getter function for the specified requestQ index
            * @param _index to look up in the requestQ array
            * @return uint of reqeuestId
            */
            function getRequestIdByRequestQIndex(TellorStorage.TellorStorageStruct storage self, uint256 _index) internal view returns (uint256) {
                require(_index <= 50, "RequestQ index is above 50");
                return self.requestIdByRequestQIndex[_index];
            }
        
            /**
            * @dev Getter function for requestId based on timestamp
            * @param _timestamp to check requestId
            * @return uint of reqeuestId
            */
            function getRequestIdByTimestamp(TellorStorage.TellorStorageStruct storage self, uint256 _timestamp) internal view returns (uint256) {
                return self.requestIdByTimestamp[_timestamp];
            }
        
            /**
            * @dev Getter function for requestId based on the qeuaryHash
            * @param _queryHash hash(of string api and granularity) to check if a request already exists
            * @return uint requestId
            */
            function getRequestIdByQueryHash(TellorStorage.TellorStorageStruct storage self, bytes32 _queryHash) internal view returns (uint256) {
                return self.requestIdByQueryHash[_queryHash];
            }
        
            /**
            * @dev Getter function for the requestQ array
            * @return the requestQ arrray
            */
            function getRequestQ(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256[51] memory) {
                return self.requestQ;
            }
        
            /**
            * @dev Allowes access to the uint variables saved in the apiUintVars under the requestDetails struct
            * for the requestId specified
            * @param _requestId to look up
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is
            * the variables/strings used to save the data in the mapping. The variables names are
            * commented out under the apiUintVars under the requestDetails struct
            * @return uint value of the apiUintVars specified in _data for the requestId specified
            */
            function getRequestUintVars(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, bytes32 _data)
                internal
                view
                returns (uint256)
            {
                return self.requestDetails[_requestId].apiUintVars[_data];
            }
        
            /**
            * @dev Gets the API struct variables that are not mappings
            * @param _requestId to look up
            * @return string of api to query
            * @return string of symbol of api to query
            * @return bytes32 hash of string
            * @return bytes32 of the granularity(decimal places) requested
            * @return uint of index in requestQ array
            * @return uint of current payout/tip for this requestId
            */
            function getRequestVars(TellorStorage.TellorStorageStruct storage self, uint256 _requestId)
                internal
                view
                returns (string memory, string memory, bytes32, uint256, uint256, uint256)
            {
                TellorStorage.Request storage _request = self.requestDetails[_requestId];
                return (
                    _request.queryString,
                    _request.dataSymbol,
                    _request.queryHash,
                    _request.apiUintVars[keccak256("granularity")],
                    _request.apiUintVars[keccak256("requestQPosition")],
                    _request.apiUintVars[keccak256("totalTip")]
                );
            }
        
            /**
            * @dev This function allows users to retireve all information about a staker
            * @param _staker address of staker inquiring about
            * @return uint current state of staker
            * @return uint startDate of staking
            */
            function getStakerInfo(TellorStorage.TellorStorageStruct storage self, address _staker) internal view returns (uint256, uint256) {
                return (self.stakerDetails[_staker].currentStatus, self.stakerDetails[_staker].startDate);
            }
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp
            * @param _requestId to look up
            * @param _timestamp is the timestampt to look up miners for
            * @return address[5] array of 5 addresses ofminers that mined the requestId
            */
            function getSubmissionsByTimestamp(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _timestamp)
                internal
                view
                returns (uint256[5] memory)
            {
                return self.requestDetails[_requestId].valuesByTimestamp[_timestamp];
            }
        
            /**
            * @dev Gets the timestamp for the value based on their index
            * @param _requestID is the requestId to look up
            * @param _index is the value index to look up
            * @return uint timestamp
            */
            function getTimestampbyRequestIDandIndex(TellorStorage.TellorStorageStruct storage self, uint256 _requestID, uint256 _index)
                internal
                view
                returns (uint256)
            {
                return self.requestDetails[_requestID].requestTimestamps[_index];
            }
        
            /**
            * @dev Getter for the variables saved under the TellorStorageStruct uintVars variable
            * @param _data the variable to pull from the mapping. _data = keccak256("variable_name") where variable_name is
            * the variables/strings used to save the data in the mapping. The variables names are
            * commented out under the uintVars under the TellorStorageStruct struct
            * This is an example of how data is saved into the mapping within other functions:
            * self.uintVars[keccak256("stakerCount")]
            * @return uint of specified variable
            */
            function getUintVar(TellorStorage.TellorStorageStruct storage self, bytes32 _data) internal view returns (uint256) {
                return self.uintVars[_data];
            }
        
            /**
            * @dev Getter function for next requestId on queue/request with highest payout at time the function is called
            * @return onDeck/info on request with highest payout-- RequestId, Totaltips, and API query string
            */
            function getVariablesOnDeck(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256, uint256, string memory) {
                uint256 newRequestId = getTopRequestID(self);
                return (
                    newRequestId,
                    self.requestDetails[newRequestId].apiUintVars[keccak256("totalTip")],
                    self.requestDetails[newRequestId].queryString
                );
            }
        
            /**
            * @dev Getter function for the request with highest payout. This function is used within the getVariablesOnDeck function
            * @return uint _requestId of request with highest payout at the time the function is called
            */
            function getTopRequestID(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256 _requestId) {
                uint256 _max;
                uint256 _index;
                (_max, _index) = Utilities.getMax(self.requestQ);
                _requestId = self.requestIdByRequestQIndex[_index];
            }
        
            /**
            * @dev Gets the 5 miners who mined the value for the specified requestId/_timestamp
            * @param _requestId to looku p
            * @param _timestamp is the timestamp to look up miners for
            * @return bool true if requestId/timestamp is under dispute
            */
            function isInDispute(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _timestamp) internal view returns (bool) {
                return self.requestDetails[_requestId].inDispute[_timestamp];
            }
        
            /**
            * @dev Retreive value from oracle based on requestId/timestamp
            * @param _requestId being requested
            * @param _timestamp to retreive data/value from
            * @return uint value for requestId/timestamp submitted
            */
            function retrieveData(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _timestamp)
                internal
                view
                returns (uint256)
            {
                return self.requestDetails[_requestId].finalValues[_timestamp];
            }
        
            /**
            * @dev Getter for the total_supply of oracle tokens
            * @return uint total supply
            */
            function totalSupply(TellorStorage.TellorStorageStruct storage self) internal view returns (uint256) {
                return self.uintVars[keccak256("total_supply")];
            }
        
        }
        
        
        pragma solidity ^0.5.16;
        
        
        
        /**
         * @title Tellor Oracle System Library
         * @dev Contains the functions' logic for the Tellor contract where miners can submit the proof of work
         * along with the value and smart contracts can requestData and tip miners.
         */
        library TellorLibrary {
            using SafeMath for uint256;
        
            bytes32 public constant requestCount = 0x05de9147d05477c0a5dc675aeea733157f5092f82add148cf39d579cafe3dc98; //keccak256("requestCount")
            bytes32 public constant totalTip = 0x2a9e355a92978430eca9c1aa3a9ba590094bac282594bccf82de16b83046e2c3; //keccak256("totalTip")
            bytes32 public constant _tBlock = 0x969ea04b74d02bb4d9e6e8e57236e1b9ca31627139ae9f0e465249932e824502; //keccak256("_tBlock")
            bytes32 public constant timeOfLastNewValue = 0x97e6eb29f6a85471f7cc9b57f9e4c3deaf398cfc9798673160d7798baf0b13a4; //keccak256("timeOfLastNewValue")
            bytes32 public constant difficulty = 0xb12aff7664b16cb99339be399b863feecd64d14817be7e1f042f97e3f358e64e; //keccak256("difficulty")
            bytes32 public constant timeTarget = 0xad16221efc80aaf1b7e69bd3ecb61ba5ffa539adf129c3b4ffff769c9b5bbc33; //keccak256("timeTarget")
            bytes32 public constant runningTips = 0xdb21f0c4accc4f2f5f1045353763a9ffe7091ceaf0fcceb5831858d96cf84631; //keccak256("runningTips")
            bytes32 public constant currentReward = 0x9b6853911475b07474368644a0d922ee13bc76a15cd3e97d3e334326424a47d4; //keccak256("currentReward")
            bytes32 public constant total_supply = 0xb1557182e4359a1f0c6301278e8f5b35a776ab58d39892581e357578fb287836; //keccak256("total_supply")
            bytes32 public constant devShare = 0x8fe9ded8d7c08f720cf0340699024f83522ea66b2bbfb8f557851cb9ee63b54c; //keccak256("devShare")
            bytes32 public constant _owner =  0x9dbc393ddc18fd27b1d9b1b129059925688d2f2d5818a5ec3ebb750b7c286ea6; //keccak256("_owner")
            bytes32 public constant requestQPosition = 0x1e344bd070f05f1c5b3f0b1266f4f20d837a0a8190a3a2da8b0375eac2ba86ea; //keccak256("requestQPosition")
            bytes32 public constant currentTotalTips = 0xd26d9834adf5a73309c4974bf654850bb699df8505e70d4cfde365c417b19dfc; //keccak256("currentTotalTips")
            bytes32 public constant slotProgress =0x6c505cb2db6644f57b42d87bd9407b0f66788b07d0617a2bc1356a0e69e66f9a; //keccak256("slotProgress")
            bytes32 public constant pending_owner = 0x44b2657a0f8a90ed8e62f4c4cceca06eacaa9b4b25751ae1ebca9280a70abd68; //keccak256("pending_owner")
            bytes32 public constant currentRequestId = 0x7584d7d8701714da9c117f5bf30af73b0b88aca5338a84a21eb28de2fe0d93b8; //keccak256("currentRequestId")
        
        
            event TipAdded(address indexed _sender, uint256 indexed _requestId, uint256 _tip, uint256 _totalTips);
            //emits when a new challenge is created (either on mined block or when a new request is pushed forward on waiting system)
            event NewChallenge(
                bytes32 indexed _currentChallenge,
                uint256[5] _currentRequestId,
                uint256 _difficulty,
                uint256 _totalTips
            );
            //Emits upon a successful Mine, indicates the blocktime at point of the mine and the value mined
            event NewValue(uint256[5] _requestId, uint256 _time, uint256[5] _value, uint256 _totalTips, bytes32 indexed _currentChallenge);
            //Emits upon each mine (5 total) and shows the miner, nonce, and value submitted
            event NonceSubmitted(address indexed _miner, string _nonce, uint256[5] _requestId, uint256[5] _value, bytes32 indexed _currentChallenge);
            event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);
            event OwnershipProposed(address indexed _previousOwner, address indexed _newOwner);
        
            /*Functions*/
            /**
            * @dev Add tip to Request value from oracle
            * @param _requestId being requested to be mined
            * @param _tip amount the requester is willing to pay to be get on queue. Miners
            * mine the onDeckQueryHash, or the api with the highest payout pool
            */
            function addTip(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _tip) public {
                require(_requestId != 0, "RequestId is 0");
                require(_tip != 0, "Tip should be greater than 0");
                uint256 _count =self.uintVars[requestCount] + 1;
                if(_requestId == _count){
                    self.uintVars[requestCount] = _count;
                }
                else{
                    require(_requestId < _count, "RequestId is not less than count");
                }
                TellorTransfer.doTransfer(self, msg.sender, address(this), _tip);
                //Update the information for the request that should be mined next based on the tip submitted
                updateOnDeck(self, _requestId, _tip);
                emit TipAdded(msg.sender, _requestId, _tip, self.requestDetails[_requestId].apiUintVars[totalTip]);
            }
        
           /**
            * @dev This function is called by submitMiningSolution and adjusts the difficulty, sorts and stores the first
            * 5 values received, pays the miners, the dev share and assigns a new challenge
            * @param _nonce or solution for the PoW  for the requestId
            * @param _requestId for the current request being mined
            */
            function newBlock(TellorStorage.TellorStorageStruct storage self, string memory _nonce, uint256[5] memory _requestId) public {
                TellorStorage.Request storage _tblock = self.requestDetails[self.uintVars[_tBlock]];
                // If the difference between the timeTarget and how long it takes to solve the challenge this updates the challenge
                //difficulty up or donw by the difference between the target time and how long it took to solve the previous challenge
                //otherwise it sets it to 1
                uint timeDiff = now - self.uintVars[timeOfLastNewValue];
                int256 _change = int256(SafeMath.min(1200, timeDiff));
                int256 _diff = int256(self.uintVars[difficulty]);
                _change = (_diff * (int256(self.uintVars[timeTarget]) - _change)) / 4000;
                if (_change == 0) {
                        _change = 1;
                    }
                self.uintVars[difficulty]  = uint256(SafeMath.max(_diff + _change,1));
        
        
                //Sets time of value submission rounded to 1 minute
                bytes32 _currChallenge = self.currentChallenge;
                uint256 _timeOfLastNewValue = now - (now % 1 minutes);
                self.uintVars[timeOfLastNewValue] = _timeOfLastNewValue;
                uint[5] memory a; 
                for (uint k = 0; k < 5; k++) {
                    for (uint i = 1; i < 5; i++) {
                        uint256 temp = _tblock.valuesByTimestamp[k][i];
                        address temp2 = _tblock.minersByValue[k][i];
                        uint256 j = i;
                        while (j > 0 && temp < _tblock.valuesByTimestamp[k][j - 1]) {
                            _tblock.valuesByTimestamp[k][j] = _tblock.valuesByTimestamp[k][j - 1];
                            _tblock.minersByValue[k][j] = _tblock.minersByValue[k][j - 1];
                            j--;
                        }
                        if (j < i) {
                            _tblock.valuesByTimestamp[k][j] = temp;
                            _tblock.minersByValue[k][j] = temp2;
                        }
                    }
                    TellorStorage.Request storage _request = self.requestDetails[_requestId[k]];
                    //Save the official(finalValue), timestamp of it, 5 miners and their submitted values for it, and its block number
                    a = _tblock.valuesByTimestamp[k];
                    _request.finalValues[_timeOfLastNewValue] = a[2];
                    _request.minersByValue[_timeOfLastNewValue] = _tblock.minersByValue[k];
                    _request.valuesByTimestamp[_timeOfLastNewValue] = _tblock.valuesByTimestamp[k];
                    delete _tblock.minersByValue[k];
                    delete _tblock.valuesByTimestamp[k];
                    _request.requestTimestamps.push(_timeOfLastNewValue);
                    _request.minedBlockNum[_timeOfLastNewValue] = block.number;
                    _request.apiUintVars[totalTip] = 0;
                }
                    emit NewValue(
                        _requestId,
                        _timeOfLastNewValue,
                        a,
                        self.uintVars[runningTips],
                        _currChallenge
                    );
                //map the timeOfLastValue to the requestId that was just mined
                self.requestIdByTimestamp[_timeOfLastNewValue] = _requestId[0];
                //add timeOfLastValue to the newValueTimestamps array
                self.newValueTimestamps.push(_timeOfLastNewValue);
        
                address[5] memory miners = self.requestDetails[_requestId[0]].minersByValue[_timeOfLastNewValue];
                //payMinersRewards
                _payReward(self, timeDiff, miners);
                
                self.uintVars[_tBlock] ++;
                uint256[5] memory _topId = TellorStake.getTopRequestIDs(self);
                for(uint i = 0; i< 5;i++){
                    self.currentMiners[i].value = _topId[i];
                    self.requestQ[self.requestDetails[_topId[i]].apiUintVars[requestQPosition]] = 0;
                    self.uintVars[currentTotalTips] += self.requestDetails[_topId[i]].apiUintVars[totalTip];
                }
                //Issue the the next challenge
               
                _currChallenge = keccak256(abi.encode(_nonce, _currChallenge, blockhash(block.number - 1)));
                self.currentChallenge = _currChallenge; // Save hash for next proof
                emit NewChallenge(
                    _currChallenge,
                    _topId,
                    self.uintVars[difficulty],
                    self.uintVars[currentTotalTips]
                );
            }
        
            /**
            * @dev Proof of work is called by the miner when they submit the solution (proof of work and value)
            * @param _nonce uint submitted by miner
            * @param _requestId is the array of the 5 PSR's being mined
            * @param _value is an array of 5 values
            */
            function submitMiningSolution(TellorStorage.TellorStorageStruct storage self, string calldata _nonce,uint256[5] calldata _requestId, uint256[5] calldata _value)
                external
            {
                _verifyNonce(self, _nonce);
                _submitMiningSolution(self, _nonce, _requestId, _value);
            }
        
        
            function _submitMiningSolution(TellorStorage.TellorStorageStruct storage self, string memory _nonce,uint256[5] memory _requestId, uint256[5] memory _value)
                internal
            {
                        //Verifying Miner Eligibility
                bytes32 _hashMsgSender = keccak256(abi.encode(msg.sender));
                require(self.stakerDetails[msg.sender].currentStatus == 1, "Miner status is not staker");
                require(now - self.uintVars[_hashMsgSender] > 15 minutes, "Miner can only win rewards once per 15 min");
                require(_requestId[0] ==  self.currentMiners[0].value,"Request ID is wrong");
                require(_requestId[1] ==  self.currentMiners[1].value,"Request ID is wrong");
                require(_requestId[2] ==  self.currentMiners[2].value,"Request ID is wrong");
                require(_requestId[3] ==  self.currentMiners[3].value,"Request ID is wrong");
                require(_requestId[4] ==  self.currentMiners[4].value,"Request ID is wrong");
                self.uintVars[_hashMsgSender] = now;
        
                
                bytes32 _currChallenge = self.currentChallenge;
                uint256 _slotProgress = self.uintVars[slotProgress]; 
                //Saving the challenge information as unique by using the msg.sender
        
                //Checking and updating Miner Status
                require(self.minersByChallenge[_currChallenge][msg.sender] == false, "Miner already submitted the value");
                //Update the miner status to true once they submit a value so they don't submit more than once
                self.minersByChallenge[_currChallenge][msg.sender] = true;
        
                //Updating Request
                TellorStorage.Request storage _tblock = self.requestDetails[self.uintVars[_tBlock]];
                _tblock.minersByValue[1][_slotProgress]= msg.sender; 
                //Assigng directly is cheaper than using a for loop
                _tblock.valuesByTimestamp[0][_slotProgress] = _value[0];
                _tblock.valuesByTimestamp[1][_slotProgress] = _value[1];
                _tblock.valuesByTimestamp[2][_slotProgress] = _value[2];
                _tblock.valuesByTimestamp[3][_slotProgress] = _value[3];
                _tblock.valuesByTimestamp[4][_slotProgress] = _value[4];
                _tblock.minersByValue[0][_slotProgress]= msg.sender;
                _tblock.minersByValue[1][_slotProgress]= msg.sender;
                _tblock.minersByValue[2][_slotProgress]= msg.sender;
                _tblock.minersByValue[3][_slotProgress]= msg.sender;
                _tblock.minersByValue[4][_slotProgress]= msg.sender;
        
                //If 5 values have been received, adjust the difficulty otherwise sort the values until 5 are received         
                if (_slotProgress + 1 == 5) { //slotProgress has been incremented, but we're using the variable on stack to save gas
                    newBlock(self, _nonce, _requestId);
                    self.uintVars[slotProgress] = 0;
                }
                else{
                    self.uintVars[slotProgress]++;
                }
                emit NonceSubmitted(msg.sender, _nonce, _requestId, _value, _currChallenge);
            }
        
            function _verifyNonce(TellorStorage.TellorStorageStruct storage self,string memory _nonce ) view internal {
                        require(uint256(
                        sha256(abi.encodePacked(ripemd160(abi.encodePacked(keccak256(abi.encodePacked(self.currentChallenge, msg.sender, _nonce))))))
                    ) %
                        self.uintVars[difficulty] == 0
                        || (now - (now % 1 minutes)) - self.uintVars[timeOfLastNewValue] >= 15 minutes,
                    "Incorrect nonce for current challenge"
                );
            }
        
             /**
            * @dev Internal function to calculate and pay rewards to miners
            * 
            */
            function _payReward(TellorStorage.TellorStorageStruct storage self, uint _timeDiff, address[5] memory miners) internal {
                //_timeDiff is how many minutes passed since last block
                uint _currReward = 1e18;
                uint reward = _timeDiff* _currReward / 300; //each miner get's 
                uint _tip = self.uintVars[currentTotalTips] / 10;
                uint _devShare = reward / 2;
        
                TellorTransfer.doTransfer(self, address(this), miners[0], reward + _tip);
                TellorTransfer.doTransfer(self, address(this), miners[1], reward + _tip);
                TellorTransfer.doTransfer(self, address(this), miners[2], reward + _tip);
                TellorTransfer.doTransfer(self, address(this), miners[3], reward + _tip);
                TellorTransfer.doTransfer(self, address(this), miners[4], reward + _tip);
         
                //update the total supply
                self.uintVars[total_supply] +=  _devShare + reward * 5 - (self.uintVars[currentTotalTips] / 2);
                TellorTransfer.doTransfer(self, address(this), self.addressVars[_owner],  _devShare);
                self.uintVars[currentTotalTips] = 0;
            }
        
        
            /**
            * @dev Allows the current owner to propose transfer control of the contract to a
            * newOwner and the ownership is pending until the new owner calls the claimOwnership
            * function
            * @param _pendingOwner The address to transfer ownership to.
            */
            function proposeOwnership(TellorStorage.TellorStorageStruct storage self, address payable _pendingOwner) public {
                require(msg.sender == self.addressVars[_owner], "Sender is not owner");
                emit OwnershipProposed(self.addressVars[_owner], _pendingOwner);
                self.addressVars[pending_owner] = _pendingOwner;
            }
        
            /**
            * @dev Allows the new owner to claim control of the contract
            */
            function claimOwnership(TellorStorage.TellorStorageStruct storage self) public {
                require(msg.sender == self.addressVars[pending_owner], "Sender is not pending owner");
                emit OwnershipTransferred(self.addressVars[_owner], self.addressVars[pending_owner]);
                self.addressVars[_owner] = self.addressVars[pending_owner];
            }
        
            /**
            * @dev This function updates APIonQ and the requestQ when requestData or addTip are ran
            * @param _requestId being requested
            * @param _tip is the tip to add
            */
            function updateOnDeck(TellorStorage.TellorStorageStruct storage self, uint256 _requestId, uint256 _tip) public {
                TellorStorage.Request storage _request = self.requestDetails[_requestId];
                _request.apiUintVars[totalTip] = _request.apiUintVars[totalTip].add(_tip);
                if(self.currentMiners[0].value == _requestId || self.currentMiners[1].value== _requestId ||self.currentMiners[2].value == _requestId||self.currentMiners[3].value== _requestId || self.currentMiners[4].value== _requestId ){
                    self.uintVars[currentTotalTips] += _tip;
                }
                else {
                    //if the request is not part of the requestQ[51] array
                    //then add to the requestQ[51] only if the _payout/tip is greater than the minimum(tip) in the requestQ[51] array
                    if (_request.apiUintVars[requestQPosition] == 0) {
                        uint256 _min;
                        uint256 _index;
                        (_min, _index) = Utilities.getMin(self.requestQ);
                        //we have to zero out the oldOne
                        //if the _payout is greater than the current minimum payout in the requestQ[51] or if the minimum is zero
                        //then add it to the requestQ array aand map its index information to the requestId and the apiUintvars
                        if (_request.apiUintVars[totalTip] > _min || _min == 0) {
                            self.requestQ[_index] = _request.apiUintVars[totalTip];
                            self.requestDetails[self.requestIdByRequestQIndex[_index]].apiUintVars[requestQPosition] = 0;
                            self.requestIdByRequestQIndex[_index] = _requestId;
                            _request.apiUintVars[requestQPosition] = _index;
                        }
                        // else if the requestid is part of the requestQ[51] then update the tip for it
                    } else{
                        self.requestQ[_request.apiUintVars[requestQPosition]] += _tip;
                    }
                }
            }
        
        }
        
        
        pragma solidity ^0.5.16;
        
        
        
        
        /**
         * @title Tellor Oracle System
         * @dev Oracle contract where miners can submit the proof of work along with the value.
         * The logic for this contract is in TellorLibrary.sol, TellorDispute.sol, TellorStake.sol,
         * and TellorTransfer.sol
         */
        contract Tellor {
            using SafeMath for uint256;
        
            using TellorDispute for TellorStorage.TellorStorageStruct;
            using TellorLibrary for TellorStorage.TellorStorageStruct;
            using TellorStake for TellorStorage.TellorStorageStruct;
            using TellorTransfer for TellorStorage.TellorStorageStruct;
        
            TellorStorage.TellorStorageStruct tellor;
        
            /*Functions*/
        
            /**
            * @dev Helps initialize a dispute by assigning it a disputeId
            * when a miner returns a false on the validate array(in Tellor.ProofOfWork) it sends the
            * invalidated value information to POS voting
            * @param _requestId being disputed
            * @param _timestamp being disputed
            * @param _minerIndex the index of the miner that submitted the value being disputed. Since each official value
            * requires 5 miners to submit a value.
            */
            function beginDispute(uint256 _requestId, uint256 _timestamp, uint256 _minerIndex) external {
                tellor.beginDispute(_requestId, _timestamp, _minerIndex);
            }
        
            /**
            * @dev Allows token holders to vote
            * @param _disputeId is the dispute id
            * @param _supportsDispute is the vote (true=the dispute has basis false = vote against dispute)
            */
            function vote(uint256 _disputeId, bool _supportsDispute) external {
                tellor.vote(_disputeId, _supportsDispute);
            }
        
            /**
            * @dev tallies the votes.
            * @param _disputeId is the dispute id
            */
            function tallyVotes(uint256 _disputeId) external {
                tellor.tallyVotes(_disputeId);
            }
        
            /**
            * @dev Allows for a fork to be proposed
            * @param _propNewTellorAddress address for new proposed Tellor
            */
            function proposeFork(address _propNewTellorAddress) external {
                tellor.proposeFork(_propNewTellorAddress);
            }
        
            /**
            * @dev Add tip to Request value from oracle
            * @param _requestId being requested to be mined
            * @param _tip amount the requester is willing to pay to be get on queue. Miners
            * mine the onDeckQueryHash, or the api with the highest payout pool
            */
            function addTip(uint256 _requestId, uint256 _tip) external {
                tellor.addTip(_requestId, _tip);
            }
        
            /**
            * @dev This is called by the miner when they submit the PoW solution (proof of work and value)
            * @param _nonce uint submitted by miner
            * @param _requestId is the array of the 5 PSR's being mined
            * @param _value is an array of 5 values
            */
            function submitMiningSolution(string calldata _nonce,uint256[5] calldata _requestId, uint256[5] calldata _value) external {
                tellor.submitMiningSolution(_nonce,_requestId, _value);
            }
        
        
            /**
            * @dev Allows the current owner to propose transfer control of the contract to a
            * newOwner and the ownership is pending until the new owner calls the claimOwnership
            * function
            * @param _pendingOwner The address to transfer ownership to.
            */
            function proposeOwnership(address payable _pendingOwner) external {
                tellor.proposeOwnership(_pendingOwner);
            }
        
            /**
            * @dev Allows the new owner to claim control of the contract
            */
            function claimOwnership() external {
                tellor.claimOwnership();
            }
        
            /**
            * @dev This function allows miners to deposit their stake.
            */
            function depositStake() external {
                tellor.depositStake();
            }
        
            /**
            * @dev This function allows stakers to request to withdraw their stake (no longer stake)
            * once they lock for withdraw(stakes.currentStatus = 2) they are locked for 7 days before they
            * can withdraw the stake
            */
            function requestStakingWithdraw() external {
                tellor.requestStakingWithdraw();
            }
        
            /**
            * @dev This function allows users to withdraw their stake after a 7 day waiting period from request
            */
            function withdrawStake() external {
                tellor.withdrawStake();
            }
        
            /**
            * @dev This function approves a _spender an _amount of tokens to use
            * @param _spender address
            * @param _amount amount the spender is being approved for
            * @return true if spender appproved successfully
            */
            function approve(address _spender, uint256 _amount) external returns (bool) {
                return tellor.approve(_spender, _amount);
            }
        
            /**
            * @dev Allows for a transfer of tokens to _to
            * @param _to The address to send tokens to
            * @param _amount The amount of tokens to send
            * @return true if transfer is successful
            */
            function transfer(address _to, uint256 _amount) external returns (bool) {
                return tellor.transfer(_to, _amount);
            }
        
            /**
            * @dev Sends _amount tokens to _to from _from on the condition it
            * is approved by _from
            * @param _from The address holding the tokens being transferred
            * @param _to The address of the recipient
            * @param _amount The amount of tokens to be transferred
            * @return True if the transfer was successful
            */
            function transferFrom(address _from, address _to, uint256 _amount) external returns (bool) {
                return tellor.transferFrom(_from, _to, _amount);
            }
        
            /**
            * @dev Allows users to access the token's name
            */
            function name() external pure returns (string memory) {
                return "Tellor Tributes";
            }
        
            /**
            * @dev Allows users to access the token's symbol
            */
            function symbol() external pure returns (string memory) {
                return "TRB";
            }
        
            /**
            * @dev Allows users to access the number of decimals
            */
            function decimals() external pure returns (uint8) {
                return 18;
            }
        
            /**
            * @dev Getter for the current variables that include the 5 requests Id's
            * @return the challenge, 5 requestsId, difficulty and tip
            */
            function getNewCurrentVariables() external view returns(bytes32 _challenge,uint[5] memory _requestIds,uint256 _difficutly, uint256 _tip){
                return tellor.getNewCurrentVariables();
            }
        
            /**
            * @dev Getter for the top tipped 5 requests Id's
            * @return the 5 requestsId
            */
            function getTopRequestIDs() external view returns(uint256[5] memory _requestIds){
                return tellor.getTopRequestIDs();
            }
        
            /**
            * @dev Getter for the 5 requests Id's next in line to get mined
            * @return the 5 requestsId
            */
            function getNewVariablesOnDeck() external view returns (uint256[5] memory idsOnDeck, uint256[5] memory tipsOnDeck) {
                return tellor.getNewVariablesOnDeck();
            }
        
            /**
            * @dev Updates the Tellor address after a proposed fork has 
            * passed the vote and day has gone by without a dispute
            * @param _disputeId the disputeId for the proposed fork
            */
             function updateTellor(uint _disputeId) external{
                return tellor.updateTellor(_disputeId);
            }
        
            /**
            * @dev Allows disputer to unlock the dispute fee
            * @param _disputeId to unlock fee from
            */
             function unlockDisputeFee (uint _disputeId) external{
                return tellor.unlockDisputeFee(_disputeId);
            }
        
            /*******************TEST Functions NOT INCLUDED ON PRODUCTION/MAINNET/RINKEBY******/
            // /*This is a cheat for demo purposes, will delete upon actual launch*/
            // function theLazyCoon(address _address, uint _amount) external {
            //     tellor.theLazyCoon(_address,_amount);
            // }
        
            // // function testSubmitMiningSolution(string calldata _nonce, uint256 _requestId, uint256 _value) external {
            // //     tellor.testSubmitMiningSolution(_nonce, _requestId, _value);
            // // }
        
            // function testSubmitMiningSolution(string calldata _nonce,uint256[5] calldata _requestId, uint256[5] calldata _value) external {
            //     tellor.testSubmitMiningSolution(_nonce,_requestId, _value);
            // }
            /***************END TEST Functions NOT INCLUDED ON PRODUCTION/MAINNET/RINKEBY******/
         }