ETH Price: $2,513.19 (-0.28%)

Transaction Decoder

Block:
19678080 at Apr-17-2024 10:09:59 PM +UTC
Transaction Fee:
0.00315723077077804 ETH $7.93
Gas Used:
286,990 Gas / 11.001187396 Gwei

Emitted Events:

50 TellorMaster.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000008cfc184c877154a8f9ffe0fe75649dbe5e2dbebf, 0x000000000000000000000000ea907797dd7243de1ae030d97279edde936ae779, 0000000000000000000000000000000000000000000000000853a0d2313c0000 )
51 TellorFlex.NewReport( _queryId=83A7F3D48786AC2667503A61E8C415438ED2922EB86A2906E4EE66D9A2CE4992, _time=1713391799, _value=0x0000000000000000000000000000000000000000000000A256B36FD2C0480000, _nonce=7078, _queryData=0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000953706F745072696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003657468000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037573640000000000000000000000000000000000000000000000000000000000, _reporter=[Receiver] 0xea907797dd7243de1ae030d97279edde936ae779 )

Account State Difference:

  Address   Before After State Difference Code
(Fee Recipient: 0x4493...e02)
105.858002784051381494 Eth105.858207060903785054 Eth0.00020427685240356
0x88dF592F...2cf3778a0
0x8cFc184c...e5e2DBEbf
(Tellor: Oracle Contract)
0xBe3FC39C...77ea5203A
2.087614860163344636 Eth
Nonce: 8041
2.084257629392566596 Eth
Nonce: 8042
0.00335723077077804

Execution Trace

ETH 0.0002 MEV Bot: 0xea9...779.42d4b2f0( )
  • TellorMaster.70a08231( )
    • Tellor360.balanceOf( _user=0xea907797Dd7243DE1ae030d97279eDde936AE779 ) => ( 62580964500000000000 )
    • TellorFlex.submitValue( _queryId=83A7F3D48786AC2667503A61E8C415438ED2922EB86A2906E4EE66D9A2CE4992, _value=0x0000000000000000000000000000000000000000000000A256B36FD2C0480000, _nonce=7078, _queryData=0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000953706F745072696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003657468000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037573640000000000000000000000000000000000000000000000000000000000 )
      • TellorMaster.70a08231( )
        • Tellor360.balanceOf( _user=0x8cFc184c877154a8F9ffE0fe75649dbe5e2DBEbf ) => ( 25776339285353065366143 )
        • TellorMaster.a9059cbb( )
          • Tellor360.transfer( _to=0xea907797Dd7243DE1ae030d97279eDde936AE779, _amount=600000000000000000 ) => ( success=True )
          • TellorMaster.70a08231( )
            • Tellor360.balanceOf( _user=0xea907797Dd7243DE1ae030d97279eDde936AE779 ) => ( 63180964500000000000 )
            • ETH 0.0002 Fee Recipient: 0x4493...e02.CALL( )
              File 1 of 3: TellorMaster
              // SPDX-License-Identifier: MIT
              pragma solidity 0.7.4;
              import "./TellorStorage.sol";
              import "./TellorVariables.sol";
              /**
               * @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 TellorStorage, TellorVariables {
                  event NewTellorAddress(address _newTellor);
                  constructor(address _tContract, address _oTellor) {
                      addresses[_OWNER] = msg.sender;
                      addresses[_DEITY] = msg.sender;
                      addresses[_TELLOR_CONTRACT] = _tContract;
                      addresses[_OLD_TELLOR] = _oTellor;
                      bytesVars[_CURRENT_CHALLENGE] = bytes32("1");
                      uints[_DIFFICULTY] = 100;
                      uints[_TIME_TARGET] = 240;
                      uints[_TARGET_MINERS] = 200;
                      uints[_CURRENT_REWARD] = 1e18;
                      uints[_DISPUTE_FEE] = 500e18;
                      uints[_STAKE_AMOUNT] = 500e18;
                      uints[_TIME_OF_LAST_NEW_VALUE] = block.timestamp - 240;
                      currentMiners[0].value = 1;
                      currentMiners[1].value = 2;
                      currentMiners[2].value = 3;
                      currentMiners[3].value = 4;
                      currentMiners[4].value = 5;
                      // Bootstraping Request Queue
                      for (uint256 index = 1; index < 51; index++) {
                          Request storage req = requestDetails[index];
                          req.apiUintVars[_REQUEST_Q_POSITION] = index;
                          requestIdByRequestQIndex[index] = index;
                      }
                      assembly {
                          sstore(_EIP_SLOT, _tContract)
                      }
                      emit NewTellorAddress(_tContract);
                  }
                  /**
                   * @dev This function allows the Deity to set a new deity
                   * @param _newDeity the new Deity in the contract
                   */
                  function changeDeity(address _newDeity) external {
                      require(msg.sender == addresses[_DEITY]);
                      addresses[_DEITY] = _newDeity;
                  }
                  /**
                   * @dev This function allows the owner to set a new _owner
                   * @param _newOwner the new Owner in the contract
                   */
                  function changeOwner(address _newOwner) external {
                      require(msg.sender == addresses[_OWNER]);
                      addresses[_OWNER] = _newOwner;
                  }
                  /**
                   * @dev  allows for the deity to make fast upgrades.  Deity should be 0 address if decentralized
                   * @param _tContract the address of the new Tellor Contract
                   */
                  function changeTellorContract(address _tContract) external {
                      require(msg.sender == addresses[_DEITY]);
                      addresses[_TELLOR_CONTRACT] = _tContract;
                      assembly {
                          sstore(_EIP_SLOT, _tContract)
                      }
                  }
                  /**
                   * @dev This is the internal function that allows for delegate calls to the Tellor logic
                   * contract address
                   */
                  function _delegate(address implementation) internal virtual {
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          // Copy msg.data. We take full control of memory in this inline assembly
                          // block because it will not return to Solidity code. We overwrite the
                          // Solidity scratch pad at memory position 0.
                          calldatacopy(0, 0, calldatasize())
                          // Call the implementation.
                          // out and outsize are 0 because we don't know the size yet.
                          let result := delegatecall(
                              gas(),
                              implementation,
                              0,
                              calldatasize(),
                              0,
                              0
                          )
                          // Copy the returned data.
                          returndatacopy(0, 0, returndatasize())
                          switch result
                              // delegatecall returns 0 on error.
                              case 0 {
                                  revert(0, returndatasize())
                              }
                              default {
                                  return(0, returndatasize())
                              }
                      }
                  }
                  /**
                   * @dev This is the fallback function that allows contracts to call the tellor
                   * contract at the address stored
                   */
                  fallback() external payable {
                      address addr = addresses[_TELLOR_CONTRACT];
                      _delegate(addr);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.7.4;
              /**
               * @title Tellor Oracle Storage Library
               * @dev Contains all the variables/structs used by Tellor
               */
              contract 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 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 disputed 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 {
                      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("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;
                  }
                  uint256[51] requestQ; //uint50 array of the top50 requests by payment amount
                  uint256[] public newValueTimestamps; //array of all timestamps requested
                  //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
                  //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 hardcoded 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(uint256 => uint256) requestIdByTimestamp; //minedTimestamp to apiId
                  mapping(uint256 => uint256) requestIdByRequestQIndex; //link from payoutPoolIndex (position in payout pool array) to apiId
                  mapping(uint256 => Dispute) public disputesById; //disputeId=> Dispute details
                  mapping(bytes32 => uint256) public requestIdByQueryHash; // api bytes32 gets an id = to count of requests array
                  mapping(bytes32 => uint256) public disputeIdByDisputeHash; //maps a hash to an ID for each dispute
                  mapping(bytes32 => mapping(address => bool)) public minersByChallenge;
                  Details[5] public currentMiners; //This struct is for organizing the five mined values to find the median
                  mapping(address => StakeInfo) stakerDetails; //mapping from a persons address to their staking info
                  mapping(uint256 => Request) requestDetails;
                  mapping(bytes32 => uint256) public uints;
                  mapping(bytes32 => address) public addresses;
                  mapping(bytes32 => bytes32) public bytesVars;
                  //ERC20 storage
                  mapping(address => Checkpoint[]) public balances;
                  mapping(address => mapping(address => uint256)) public _allowances;
                  //Migration storage
                  mapping(address => bool) public migrated;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.7.4;
              // Helper contract to store hashes of variables
              contract TellorVariables {
                  bytes32 constant _BLOCK_NUMBER =
                      0x4b4cefd5ced7569ef0d091282b4bca9c52a034c56471a6061afd1bf307a2de7c; //keccak256("_BLOCK_NUMBER");
                  bytes32 constant _CURRENT_CHALLENGE =
                      0xd54702836c9d21d0727ffacc3e39f57c92b5ae0f50177e593bfb5ec66e3de280; //keccak256("_CURRENT_CHALLENGE");
                  bytes32 constant _CURRENT_REQUESTID =
                      0xf5126bb0ac211fbeeac2c0e89d4c02ac8cadb2da1cfb27b53c6c1f4587b48020; //keccak256("_CURRENT_REQUESTID");
                  bytes32 constant _CURRENT_REWARD =
                      0xd415862fd27fb74541e0f6f725b0c0d5b5fa1f22367d9b78ec6f61d97d05d5f8; //keccak256("_CURRENT_REWARD");
                  bytes32 constant _CURRENT_TOTAL_TIPS =
                      0x09659d32f99e50ac728058418d38174fe83a137c455ff1847e6fb8e15f78f77a; //keccak256("_CURRENT_TOTAL_TIPS");
                  bytes32 constant _DEITY =
                      0x5fc094d10c65bc33cc842217b2eccca0191ff24148319da094e540a559898961; //keccak256("_DEITY");
                  bytes32 constant _DIFFICULTY =
                      0xf758978fc1647996a3d9992f611883adc442931dc49488312360acc90601759b; //keccak256("_DIFFICULTY");
                  bytes32 constant _DISPUTE_COUNT =
                      0x310199159a20c50879ffb440b45802138b5b162ec9426720e9dd3ee8bbcdb9d7; //keccak256("_DISPUTE_COUNT");
                  bytes32 constant _DISPUTE_FEE =
                      0x675d2171f68d6f5545d54fb9b1fb61a0e6897e6188ca1cd664e7c9530d91ecfc; //keccak256("_DISPUTE_FEE");
                  bytes32 constant _DISPUTE_ROUNDS =
                      0x6ab2b18aafe78fd59c6a4092015bddd9fcacb8170f72b299074f74d76a91a923; //keccak256("_DISPUTE_ROUNDS");
                  bytes32 constant _FEE =
                      0x1da95f11543c9b03927178e07951795dfc95c7501a9d1cf00e13414ca33bc409; //keccak256("FEE");
                  bytes32 constant _MIN_EXECUTION_DATE =
                      0x46f7d53798d31923f6952572c6a19ad2d1a8238d26649c2f3493a6d69e425d28; //keccak256("_MIN_EXECUTION_DATE");
                  bytes32 constant _MINER_SLOT =
                      0x6de96ee4d33a0617f40a846309c8759048857f51b9d59a12d3c3786d4778883d; //keccak256("_MINER_SLOT");
                  bytes32 constant _NUM_OF_VOTES =
                      0x1da378694063870452ce03b189f48e04c1aa026348e74e6c86e10738514ad2c4; //keccak256("_NUM_OF_VOTES");
                  bytes32 constant _OLD_TELLOR =
                      0x56e0987db9eaec01ed9e0af003a0fd5c062371f9d23722eb4a3ebc74f16ea371; //keccak256("_OLD_TELLOR");
                  bytes32 constant _ORIGINAL_ID =
                      0xed92b4c1e0a9e559a31171d487ecbec963526662038ecfa3a71160bd62fb8733; //keccak256("_ORIGINAL_ID");
                  bytes32 constant _OWNER =
                      0x7a39905194de50bde334d18b76bbb36dddd11641d4d50b470cb837cf3bae5def; //keccak256("_OWNER");
                  bytes32 constant _PAID =
                      0x29169706298d2b6df50a532e958b56426de1465348b93650fca42d456eaec5fc; //keccak256("_PAID");
                  bytes32 constant _PENDING_OWNER =
                      0x7ec081f029b8ac7e2321f6ae8c6a6a517fda8fcbf63cabd63dfffaeaafa56cc0; //keccak256("_PENDING_OWNER");
                  bytes32 constant _REQUEST_COUNT =
                      0x3f8b5616fa9e7f2ce4a868fde15c58b92e77bc1acd6769bf1567629a3dc4c865; //keccak256("_REQUEST_COUNT");
                  bytes32 constant _REQUEST_ID =
                      0x9f47a2659c3d32b749ae717d975e7962959890862423c4318cf86e4ec220291f; //keccak256("_REQUEST_ID");
                  bytes32 constant _REQUEST_Q_POSITION =
                      0xf68d680ab3160f1aa5d9c3a1383c49e3e60bf3c0c031245cbb036f5ce99afaa1; //keccak256("_REQUEST_Q_POSITION");
                  bytes32 constant _SLOT_PROGRESS =
                      0xdfbec46864bc123768f0d134913175d9577a55bb71b9b2595fda21e21f36b082; //keccak256("_SLOT_PROGRESS");
                  bytes32 constant _STAKE_AMOUNT =
                      0x5d9fadfc729fd027e395e5157ef1b53ef9fa4a8f053043c5f159307543e7cc97; //keccak256("_STAKE_AMOUNT");
                  bytes32 constant _STAKE_COUNT =
                      0x10c168823622203e4057b65015ff4d95b4c650b308918e8c92dc32ab5a0a034b; //keccak256("_STAKE_COUNT");
                  bytes32 constant _T_BLOCK =
                      0xf3b93531fa65b3a18680d9ea49df06d96fbd883c4889dc7db866f8b131602dfb; //keccak256("_T_BLOCK");
                  bytes32 constant _TALLY_DATE =
                      0xf9e1ae10923bfc79f52e309baf8c7699edb821f91ef5b5bd07be29545917b3a6; //keccak256("_TALLY_DATE");
                  bytes32 constant _TARGET_MINERS =
                      0x0b8561044b4253c8df1d9ad9f9ce2e0f78e4bd42b2ed8dd2e909e85f750f3bc1; //keccak256("_TARGET_MINERS");
                  bytes32 constant _TELLOR_CONTRACT =
                      0x0f1293c916694ac6af4daa2f866f0448d0c2ce8847074a7896d397c961914a08; //keccak256("_TELLOR_CONTRACT");
                  bytes32 constant _TELLOR_GETTERS =
                      0xabd9bea65759494fe86471c8386762f989e1f2e778949e94efa4a9d1c4b3545a; //keccak256("_TELLOR_GETTERS");
                  bytes32 constant _TIME_OF_LAST_NEW_VALUE =
                      0x2c8b528fbaf48aaf13162a5a0519a7ad5a612da8ff8783465c17e076660a59f1; //keccak256("_TIME_OF_LAST_NEW_VALUE");
                  bytes32 constant _TIME_TARGET =
                      0xd4f87b8d0f3d3b7e665df74631f6100b2695daa0e30e40eeac02172e15a999e1; //keccak256("_TIME_TARGET");
                  bytes32 constant _TIMESTAMP =
                      0x2f9328a9c75282bec25bb04befad06926366736e0030c985108445fa728335e5; //keccak256("_TIMESTAMP");
                  bytes32 constant _TOTAL_SUPPLY =
                      0xe6148e7230ca038d456350e69a91b66968b222bfac9ebfbea6ff0a1fb7380160; //keccak256("_TOTAL_SUPPLY");
                  bytes32 constant _TOTAL_TIP =
                      0x1590276b7f31dd8e2a06f9a92867333eeb3eddbc91e73b9833e3e55d8e34f77d; //keccak256("_TOTAL_TIP");
                  bytes32 constant _VALUE =
                      0x9147231ab14efb72c38117f68521ddef8de64f092c18c69dbfb602ffc4de7f47; //keccak256("_VALUE");
                  bytes32 constant _EIP_SLOT =
                      0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
              }
              

              File 2 of 3: TellorFlex
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              interface IERC20 {
                  function balanceOf(address account) external view returns (uint256);
                  function transfer(address recipient, uint256 amount)
                      external
                      returns (bool);
                  function transferFrom(
                      address sender,
                      address recipient,
                      uint256 amount
                  ) external returns (bool);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              import "./interfaces/IERC20.sol";
              /**
               @author Tellor Inc.
               @title TellorFlex
               @dev This is a streamlined Tellor oracle system which handles staking, reporting,
               * slashing, and user data getters in one contract. This contract is controlled
               * by a single address known as 'governance', which could be an externally owned
               * account or a contract, allowing for a flexible, modular design.
              */
              contract TellorFlex {
                  // Storage
                  IERC20 public immutable token; // token used for staking and rewards
                  address public governance; // address with ability to remove values and slash reporters
                  address public immutable owner; // contract deployer, can call init function once
                  uint256 public accumulatedRewardPerShare; // accumulated staking reward per staked token
                  uint256 public immutable minimumStakeAmount; // minimum amount of tokens required to stake
                  uint256 public immutable reportingLock; // base amount of time before a reporter is able to submit a value again
                  uint256 public rewardRate; // total staking rewards released per second
                  uint256 public stakeAmount; // minimum amount required to be a staker
                  uint256 public immutable stakeAmountDollarTarget; // amount of US dollars required to be a staker
                  uint256 public stakingRewardsBalance; // total amount of staking rewards
                  bytes32 public immutable stakingTokenPriceQueryId; // staking token SpotPrice queryId, used for updating stakeAmount
                  uint256 public constant timeBasedReward = 5e17; // amount of TB rewards released per 5 minutes
                  uint256 public timeOfLastAllocation; // time of last update to accumulatedRewardPerShare
                  uint256 public timeOfLastNewValue = block.timestamp; // time of the last new submitted value, originally set to the block timestamp
                  uint256 public totalRewardDebt; // staking reward debt, used to calculate real staking rewards balance
                  uint256 public totalStakeAmount; // total amount of tokens locked in contract (via stake)
                  uint256 public totalStakers; // total number of stakers with at least stakeAmount staked, not exact
                  uint256 public toWithdraw; //amountLockedForWithdrawal
                  mapping(bytes32 => Report) private reports; // mapping of query IDs to a report
                  mapping(address => StakeInfo) private stakerDetails; // mapping from a persons address to their staking info
                  // Structs
                  struct Report {
                      uint256[] timestamps; // array of all newValueTimestamps reported
                      mapping(uint256 => uint256) timestampIndex; // mapping of timestamps to respective indices
                      mapping(uint256 => bytes) valueByTimestamp; // mapping of timestamps to values
                      mapping(uint256 => address) reporterByTimestamp; // mapping of timestamps to reporters
                      mapping(uint256 => bool) isDisputed;
                  }
                  struct StakeInfo {
                      uint256 startDate; // stake or withdrawal request start date
                      uint256 stakedBalance; // staked token balance
                      uint256 lockedBalance; // amount locked for withdrawal
                      uint256 rewardDebt; // used for staking reward calculation
                      uint256 reporterLastTimestamp; // timestamp of reporter's last reported value
                      uint256 reportsSubmitted; // total number of reports submitted by reporter
                      uint256 startVoteCount; // total number of governance votes when stake deposited
                      uint256 startVoteTally; // staker vote tally when stake deposited
                      bool staked; // used to keep track of total stakers
                  }
                  // Events
                  event NewReport(
                      bytes32 indexed _queryId,
                      uint256 indexed _time,
                      bytes _value,
                      uint256 _nonce,
                      bytes _queryData,
                      address indexed _reporter
                  );
                  event NewStakeAmount(uint256 _newStakeAmount);
                  event NewStaker(address indexed _staker, uint256 indexed _amount);
                  event ReporterSlashed(
                      address indexed _reporter,
                      address _recipient,
                      uint256 _slashAmount
                  );
                  event StakeWithdrawn(address _staker);
                  event StakeWithdrawRequested(address _staker, uint256 _amount);
                  event ValueRemoved(bytes32 _queryId, uint256 _timestamp);
                  // Functions
                  /**
                   * @dev Initializes system parameters
                   * @param _token address of token used for staking and rewards
                   * @param _reportingLock base amount of time (seconds) before reporter is able to report again
                   * @param _stakeAmountDollarTarget fixed USD amount that stakeAmount targets on updateStakeAmount
                   * @param _stakingTokenPrice current price of staking token in USD (18 decimals)
                   * @param _stakingTokenPriceQueryId queryId where staking token price is reported
                   */
                  constructor(
                      address _token,
                      uint256 _reportingLock,
                      uint256 _stakeAmountDollarTarget,
                      uint256 _stakingTokenPrice,
                      uint256 _minimumStakeAmount,
                      bytes32 _stakingTokenPriceQueryId
                  ) {
                      require(_token != address(0), "must set token address");
                      require(_stakingTokenPrice > 0, "must set staking token price");
                      require(_reportingLock > 0, "must set reporting lock");
                      require(_stakingTokenPriceQueryId != bytes32(0), "must set staking token price queryId");
                      token = IERC20(_token);
                      owner = msg.sender;
                      reportingLock = _reportingLock;
                      stakeAmountDollarTarget = _stakeAmountDollarTarget;
                      minimumStakeAmount = _minimumStakeAmount;
                      uint256 _potentialStakeAmount = (_stakeAmountDollarTarget * 1e18) / _stakingTokenPrice;
                      if(_potentialStakeAmount < _minimumStakeAmount) {
                          stakeAmount = _minimumStakeAmount;
                      } else {
                          stakeAmount = _potentialStakeAmount;
                      }
                      stakingTokenPriceQueryId = _stakingTokenPriceQueryId;
                  }
                  /**
                   * @dev Allows the owner to initialize the governance (flex addy needed for governance deployment)
                   * @param _governanceAddress address of governance contract (github.com/tellor-io/governance)
                   */
                  function init(address _governanceAddress) external {
                      require(msg.sender == owner, "only owner can set governance address");
                      require(governance == address(0), "governance address already set");
                      require(
                          _governanceAddress != address(0),
                          "governance address can't be zero address"
                      );
                      governance = _governanceAddress;
                  }
                  /**
                   * @dev Funds the Flex contract with staking rewards (paid by autopay and minting)
                   * @param _amount amount of tokens to fund contract with
                   */
                  function addStakingRewards(uint256 _amount) external {
                      require(token.transferFrom(msg.sender, address(this), _amount));
                      _updateRewards();
                      stakingRewardsBalance += _amount;
                      // update reward rate = real staking rewards balance / 30 days
                      rewardRate =
                          (stakingRewardsBalance -
                              ((accumulatedRewardPerShare * totalStakeAmount) /
                                  1e18 -
                                  totalRewardDebt)) /
                          30 days;
                  }
                  /**
                   * @dev Allows a reporter to submit stake
                   * @param _amount amount of tokens to stake
                   */
                  function depositStake(uint256 _amount) external {
                      require(governance != address(0), "governance address not set");
                      StakeInfo storage _staker = stakerDetails[msg.sender];
                      uint256 _stakedBalance = _staker.stakedBalance;
                      uint256 _lockedBalance = _staker.lockedBalance;
                      if (_lockedBalance > 0) {
                          if (_lockedBalance >= _amount) {
                              // if staker's locked balance covers full _amount, use that
                              _staker.lockedBalance -= _amount;
                              toWithdraw -= _amount;
                          } else {
                              // otherwise, stake the whole locked balance and transfer the
                              // remaining amount from the staker's address
                              require(
                                  token.transferFrom(
                                      msg.sender,
                                      address(this),
                                      _amount - _lockedBalance
                                  )
                              );
                              toWithdraw -= _staker.lockedBalance;
                              _staker.lockedBalance = 0;
                          }
                      } else {
                          if (_stakedBalance == 0) {
                              // if staked balance and locked balance equal 0, save current vote tally.
                              // voting participation used for calculating rewards
                              (bool _success, bytes memory _returnData) = governance.call(
                                  abi.encodeWithSignature("getVoteCount()")
                              );
                              if (_success) {
                                  _staker.startVoteCount = uint256(abi.decode(_returnData, (uint256)));
                              }
                              (_success,_returnData) = governance.call(
                                  abi.encodeWithSignature("getVoteTallyByAddress(address)",msg.sender)
                              );
                              if(_success){
                                  _staker.startVoteTally =  abi.decode(_returnData,(uint256));
                              }
                          }
                          require(token.transferFrom(msg.sender, address(this), _amount));
                      }
                      _updateStakeAndPayRewards(msg.sender, _stakedBalance + _amount);
                      _staker.startDate = block.timestamp; // This resets the staker start date to now
                      emit NewStaker(msg.sender, _amount);
                  }
                  /**
                   * @dev Removes a value from the oracle.
                   * Note: this function is only callable by the Governance contract.
                   * @param _queryId is ID of the specific data feed
                   * @param _timestamp is the timestamp of the data value to remove
                   */
                  function removeValue(bytes32 _queryId, uint256 _timestamp) external {
                      require(msg.sender == governance, "caller must be governance address");
                      Report storage _report = reports[_queryId];
                      require(!_report.isDisputed[_timestamp], "value already disputed");
                      uint256 _index = _report.timestampIndex[_timestamp];
                      require(_timestamp == _report.timestamps[_index], "invalid timestamp");
                      _report.valueByTimestamp[_timestamp] = "";
                      _report.isDisputed[_timestamp] = true;
                      emit ValueRemoved(_queryId, _timestamp);
                  }
                  /**
                   * @dev Allows a reporter to request to withdraw their stake
                   * @param _amount amount of staked tokens requesting to withdraw
                   */
                  function requestStakingWithdraw(uint256 _amount) external {
                      StakeInfo storage _staker = stakerDetails[msg.sender];
                      require(
                          _staker.stakedBalance >= _amount,
                          "insufficient staked balance"
                      );
                      _updateStakeAndPayRewards(msg.sender, _staker.stakedBalance - _amount);
                      _staker.startDate = block.timestamp;
                      _staker.lockedBalance += _amount;
                      toWithdraw += _amount;
                      emit StakeWithdrawRequested(msg.sender, _amount);
                  }
                  /**
                   * @dev Slashes a reporter and transfers their stake amount to the given recipient
                   * Note: this function is only callable by the governance address.
                   * @param _reporter is the address of the reporter being slashed
                   * @param _recipient is the address receiving the reporter's stake
                   * @return _slashAmount uint256 amount of token slashed and sent to recipient address
                   */
                  function slashReporter(address _reporter, address _recipient)
                      external
                      returns (uint256 _slashAmount)
                  {
                      require(msg.sender == governance, "only governance can slash reporter");
                      StakeInfo storage _staker = stakerDetails[_reporter];
                      uint256 _stakedBalance = _staker.stakedBalance;
                      uint256 _lockedBalance = _staker.lockedBalance;
                      require(_stakedBalance + _lockedBalance > 0, "zero staker balance");
                      if (_lockedBalance >= stakeAmount) {
                          // if locked balance is at least stakeAmount, slash from locked balance
                          _slashAmount = stakeAmount;
                          _staker.lockedBalance -= stakeAmount;
                          toWithdraw -= stakeAmount;
                      } else if (_lockedBalance + _stakedBalance >= stakeAmount) {
                          // if locked balance + staked balance is at least stakeAmount,
                          // slash from locked balance and slash remainder from staked balance
                          _slashAmount = stakeAmount;
                          _updateStakeAndPayRewards(
                              _reporter,
                              _stakedBalance - (stakeAmount - _lockedBalance)
                          );
                          toWithdraw -= _lockedBalance;
                          _staker.lockedBalance = 0;
                      } else {
                          // if sum(locked balance + staked balance) is less than stakeAmount,
                          // slash sum
                          _slashAmount = _stakedBalance + _lockedBalance;
                          toWithdraw -= _lockedBalance;
                          _updateStakeAndPayRewards(_reporter, 0);
                          _staker.lockedBalance = 0;
                      }
                      require(token.transfer(_recipient, _slashAmount));
                      emit ReporterSlashed(_reporter, _recipient, _slashAmount);
                  }
                  /**
                   * @dev Allows a reporter to submit a value to the oracle
                   * @param _queryId is ID of the specific data feed. Equals keccak256(_queryData) for non-legacy IDs
                   * @param _value is the value the user submits to the oracle
                   * @param _nonce is the current value count for the query id
                   * @param _queryData is the data used to fulfill the data query
                   */
                  function submitValue(
                      bytes32 _queryId,
                      bytes calldata _value,
                      uint256 _nonce,
                      bytes calldata _queryData
                  ) external {
                      require(keccak256(_value) != keccak256(""), "value must be submitted");
                      Report storage _report = reports[_queryId];
                      require(
                          _nonce == _report.timestamps.length || _nonce == 0,
                          "nonce must match timestamp index"
                      );
                      StakeInfo storage _staker = stakerDetails[msg.sender];
                      require(
                          _staker.stakedBalance >= stakeAmount,
                          "balance must be greater than stake amount"
                      );
                      // Require reporter to abide by given reporting lock
                      require(
                          (block.timestamp - _staker.reporterLastTimestamp) * 1000 >
                              (reportingLock * 1000) / (_staker.stakedBalance / stakeAmount),
                          "still in reporter time lock, please wait!"
                      );
                      require(
                          _queryId == keccak256(_queryData),
                          "query id must be hash of query data"
                      );
                      _staker.reporterLastTimestamp = block.timestamp;
                      // Checks for no double reporting of timestamps
                      require(
                          _report.reporterByTimestamp[block.timestamp] == address(0),
                          "timestamp already reported for"
                      );
                      // Update number of timestamps, value for given timestamp, and reporter for timestamp
                      _report.timestampIndex[block.timestamp] = _report.timestamps.length;
                      _report.timestamps.push(block.timestamp);
                      _report.valueByTimestamp[block.timestamp] = _value;
                      _report.reporterByTimestamp[block.timestamp] = msg.sender;
                      // Disperse Time Based Reward
                      uint256 _reward = ((block.timestamp - timeOfLastNewValue) * timeBasedReward) / 300; //.5 TRB per 5 minutes
                      uint256 _totalTimeBasedRewardsBalance =
                          token.balanceOf(address(this)) -
                          (totalStakeAmount + stakingRewardsBalance + toWithdraw);
                      if (_totalTimeBasedRewardsBalance > 0 && _reward > 0) {
                          if (_totalTimeBasedRewardsBalance < _reward) {
                              token.transfer(msg.sender, _totalTimeBasedRewardsBalance);
                          } else {
                              token.transfer(msg.sender, _reward);
                          }
                      }
                      // Update last oracle value and number of values submitted by a reporter
                      timeOfLastNewValue = block.timestamp;
                      unchecked{
                          _staker.reportsSubmitted++;
                      }
                      emit NewReport(
                          _queryId,
                          block.timestamp,
                          _value,
                          _nonce,
                          _queryData,
                          msg.sender
                      );
                  }
                  /**
                   * @dev Updates the stake amount after retrieving the latest
                   * 12+-hour-old staking token price from the oracle
                   */
                  function updateStakeAmount() external {
                      // get staking token price
                      (bool _valFound, bytes memory _val, ) = getDataBefore(
                          stakingTokenPriceQueryId,
                          block.timestamp - 12 hours
                      );
                      if (_valFound) {
                          uint256 _stakingTokenPrice = abi.decode(_val, (uint256));
                          require(
                              _stakingTokenPrice >= 0.01 ether && _stakingTokenPrice < 1000000 ether,
                              "invalid staking token price"
                          );
                          uint256 _adjustedStakeAmount = (stakeAmountDollarTarget * 1e18) / _stakingTokenPrice;
                          if(_adjustedStakeAmount < minimumStakeAmount) {
                              stakeAmount = minimumStakeAmount;
                          } else {
                              stakeAmount = _adjustedStakeAmount;
                          }
                          emit NewStakeAmount(stakeAmount);
                      }
                  }
                  /**
                   * @dev Withdraws a reporter's stake after the lock period expires
                   */
                  function withdrawStake() external {
                      StakeInfo storage _staker = stakerDetails[msg.sender];
                      // Ensure reporter is locked and that enough time has passed
                      require(
                          block.timestamp - _staker.startDate >= 7 days,
                          "7 days didn't pass"
                      );
                      require(
                          _staker.lockedBalance > 0,
                          "reporter not locked for withdrawal"
                      );
                      require(token.transfer(msg.sender, _staker.lockedBalance));
                      toWithdraw -= _staker.lockedBalance;
                      _staker.lockedBalance = 0;
                      emit StakeWithdrawn(msg.sender);
                  }
                  // *****************************************************************************
                  // *                                                                           *
                  // *                               Getters                                     *
                  // *                                                                           *
                  // *****************************************************************************
                  /**
                   * @dev Returns the current value of a data feed given a specific ID
                   * @param _queryId is the ID of the specific data feed
                   * @return _value the latest submitted value for the given queryId
                   */
                  function getCurrentValue(bytes32 _queryId)
                      external
                      view
                      returns (bytes memory _value)
                  {
                      bool _didGet;
                      (_didGet, _value, ) = getDataBefore(_queryId, block.timestamp + 1);
                      if(!_didGet){revert();}
                  }
                  /**
                   * @dev Retrieves the latest value for the queryId before the specified timestamp
                   * @param _queryId is the queryId to look up the value for
                   * @param _timestamp before which to search for latest value
                   * @return _ifRetrieve bool true if able to retrieve a non-zero value
                   * @return _value the value retrieved
                   * @return _timestampRetrieved the value's timestamp
                   */
                  function getDataBefore(bytes32 _queryId, uint256 _timestamp)
                      public
                      view
                      returns (
                          bool _ifRetrieve,
                          bytes memory _value,
                          uint256 _timestampRetrieved
                      )
                  {
                      (bool _found, uint256 _index) = getIndexForDataBefore(
                          _queryId,
                          _timestamp
                      );
                      if (!_found) return (false, bytes(""), 0);
                      _timestampRetrieved = getTimestampbyQueryIdandIndex(_queryId, _index);
                      _value = retrieveData(_queryId, _timestampRetrieved);
                      return (true, _value, _timestampRetrieved);
                  }
                  /**
                   * @dev Returns governance address
                   * @return address governance
                   */
                  function getGovernanceAddress() external view returns (address) {
                      return governance;
                  }
                  /**
                   * @dev Counts the number of values that have been submitted for the request.
                   * @param _queryId the id to look up
                   * @return uint256 count of the number of values received for the id
                   */
                  function getNewValueCountbyQueryId(bytes32 _queryId)
                      public
                      view
                      returns (uint256)
                  {
                      return reports[_queryId].timestamps.length;
                  }
                  /**
                   * @dev Returns the pending staking reward for a given address
                   * @param _stakerAddress staker address to look up
                   * @return _pendingReward - pending reward for given staker
                   */
                  function getPendingRewardByStaker(address _stakerAddress)
                      external
                      returns (uint256 _pendingReward)
                  {
                      StakeInfo storage _staker = stakerDetails[_stakerAddress];
                      _pendingReward = (_staker.stakedBalance *
                          _getUpdatedAccumulatedRewardPerShare()) /
                          1e18 -
                          _staker.rewardDebt;
                      (bool _success, bytes memory _returnData) = governance.call(
                          abi.encodeWithSignature("getVoteCount()")
                      );
                      uint256 _numberOfVotes;
                      if (_success) {
                              _numberOfVotes = uint256(abi.decode(_returnData, (uint256))) - _staker.startVoteCount;
                      }
                      if (_numberOfVotes > 0) {
                              (_success,_returnData) = governance.call(
                                  abi.encodeWithSignature("getVoteTallyByAddress(address)",_stakerAddress)
                              );
                              if(_success){
                                  _pendingReward =
                                      (_pendingReward * (abi.decode(_returnData,(uint256)) - _staker.startVoteTally)) 
                                      / _numberOfVotes;
                              }
                      }
                  }
                  /**
                   * @dev Returns the real staking rewards balance after accounting for unclaimed rewards
                   * @return uint256 real staking rewards balance
                   */
                  function getRealStakingRewardsBalance() external view returns (uint256) {
                      uint256 _pendingRewards = (_getUpdatedAccumulatedRewardPerShare() *
                          totalStakeAmount) /
                          1e18 -
                          totalRewardDebt;
                      return (stakingRewardsBalance - _pendingRewards);
                  }
                  /**
                   * @dev Returns reporter address and whether a value was removed for a given queryId and timestamp
                   * @param _queryId the id to look up
                   * @param _timestamp is the timestamp of the value to look up
                   * @return address reporter who submitted the value
                   * @return bool true if the value was removed
                   */
                  function getReportDetails(bytes32 _queryId, uint256 _timestamp)
                      external
                      view
                      returns (address, bool)
                  {
                      return (reports[_queryId].reporterByTimestamp[_timestamp], reports[_queryId].isDisputed[_timestamp]);
                  }
                  /**
                   * @dev Returns the address of the reporter who submitted a value for a data ID at a specific time
                   * @param _queryId is ID of the specific data feed
                   * @param _timestamp is the timestamp to find a corresponding reporter for
                   * @return address of the reporter who reported the value for the data ID at the given timestamp
                   */
                  function getReporterByTimestamp(bytes32 _queryId, uint256 _timestamp)
                      external
                      view
                      returns (address)
                  {
                      return reports[_queryId].reporterByTimestamp[_timestamp];
                  }
                  /**
                   * @dev Returns the timestamp of the reporter's last submission
                   * @param _reporter is address of the reporter
                   * @return uint256 timestamp of the reporter's last submission
                   */
                  function getReporterLastTimestamp(address _reporter)
                      external
                      view
                      returns (uint256)
                  {
                      return stakerDetails[_reporter].reporterLastTimestamp;
                  }
                  /**
                   * @dev Returns the reporting lock time, the amount of time a reporter must wait to submit again
                   * @return uint256 reporting lock time
                   */
                  function getReportingLock() external view returns (uint256) {
                      return reportingLock;
                  }
                  /**
                   * @dev Returns the number of values submitted by a specific reporter address
                   * @param _reporter is the address of a reporter
                   * @return uint256 the number of values submitted by the given reporter
                   */
                  function getReportsSubmittedByAddress(address _reporter)
                      external
                      view
                      returns (uint256)
                  {
                      return stakerDetails[_reporter].reportsSubmitted;
                  }
                  /**
                   * @dev Returns amount required to report oracle values
                   * @return uint256 stake amount
                   */
                  function getStakeAmount() external view returns (uint256) {
                      return stakeAmount;
                  }
                  /**
                   * @dev Returns all information about a staker
                   * @param _stakerAddress address of staker inquiring about
                   * @return uint startDate of staking
                   * @return uint current amount staked
                   * @return uint current amount locked for withdrawal
                   * @return uint reward debt used to calculate staking rewards
                   * @return uint reporter's last reported timestamp
                   * @return uint total number of reports submitted by reporter
                   * @return uint governance vote count when first staked
                   * @return uint number of votes cast by staker when first staked
                   * @return bool whether staker is counted in totalStakers
                   */
                  function getStakerInfo(address _stakerAddress)
                      external
                      view
                      returns (
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          bool
                      )
                  {
                      StakeInfo storage _staker = stakerDetails[_stakerAddress];
                      return (
                          _staker.startDate,
                          _staker.stakedBalance,
                          _staker.lockedBalance,
                          _staker.rewardDebt,
                          _staker.reporterLastTimestamp,
                          _staker.reportsSubmitted,
                          _staker.startVoteCount,
                          _staker.startVoteTally,
                          _staker.staked
                      );
                  }
                  /**
                   * @dev Returns the timestamp for the last value of any ID from the oracle
                   * @return uint256 timestamp of the last oracle value
                   */
                  function getTimeOfLastNewValue() external view returns (uint256) {
                      return timeOfLastNewValue;
                  }
                  /**
                   * @dev Gets the timestamp for the value based on their index
                   * @param _queryId is the id to look up
                   * @param _index is the value index to look up
                   * @return uint256 timestamp
                   */
                  function getTimestampbyQueryIdandIndex(bytes32 _queryId, uint256 _index)
                      public
                      view
                      returns (uint256)
                  {
                      return reports[_queryId].timestamps[_index];
                  }
                  /**
                   * @dev Retrieves latest array index of data before the specified timestamp for the queryId
                   * @param _queryId is the queryId to look up the index for
                   * @param _timestamp is the timestamp before which to search for the latest index
                   * @return _found whether the index was found
                   * @return _index the latest index found before the specified timestamp
                   */
                  // slither-disable-next-line calls-loop
                  function getIndexForDataBefore(bytes32 _queryId, uint256 _timestamp)
                      public
                      view
                      returns (bool _found, uint256 _index)
                  {
                      uint256 _count = getNewValueCountbyQueryId(_queryId);
                      if (_count > 0) {
                          uint256 _middle;
                          uint256 _start = 0;
                          uint256 _end = _count - 1;
                          uint256 _time;
                          //Checking Boundaries to short-circuit the algorithm
                          _time = getTimestampbyQueryIdandIndex(_queryId, _start);
                          if (_time >= _timestamp) return (false, 0);
                          _time = getTimestampbyQueryIdandIndex(_queryId, _end);
                          if (_time < _timestamp) {
                              while(isInDispute(_queryId, _time) && _end > 0) {
                                  _end--;
                                  _time = getTimestampbyQueryIdandIndex(_queryId, _end);
                              }
                              if(_end == 0 && isInDispute(_queryId, _time)) {
                                  return (false, 0);
                              }
                              return (true, _end);
                          }
                          //Since the value is within our boundaries, do a binary search
                          while (true) {
                              _middle = (_end - _start) / 2 + 1 + _start;
                              _time = getTimestampbyQueryIdandIndex(_queryId, _middle);
                              if (_time < _timestamp) {
                                  //get immediate next value
                                  uint256 _nextTime = getTimestampbyQueryIdandIndex(
                                      _queryId,
                                      _middle + 1
                                  );
                                  if (_nextTime >= _timestamp) {
                                      if(!isInDispute(_queryId, _time)) {
                                          // _time is correct
                                          return (true, _middle);
                                      } else {
                                          // iterate backwards until we find a non-disputed value
                                          while(isInDispute(_queryId, _time) && _middle > 0) {
                                              _middle--;
                                              _time = getTimestampbyQueryIdandIndex(_queryId, _middle);
                                          }
                                          if(_middle == 0 && isInDispute(_queryId, _time)) {
                                              return (false, 0);
                                          }
                                          // _time is correct
                                          return (true, _middle);
                                      }
                                  } else {
                                      //look from middle + 1(next value) to end
                                      _start = _middle + 1;
                                  }
                              } else {
                                  uint256 _prevTime = getTimestampbyQueryIdandIndex(
                                      _queryId,
                                      _middle - 1
                                  );
                                  if (_prevTime < _timestamp) {
                                      if(!isInDispute(_queryId, _prevTime)) {
                                          // _prevTime is correct
                                          return (true, _middle - 1);
                                      } else {
                                          // iterate backwards until we find a non-disputed value
                                          _middle--;
                                          while(isInDispute(_queryId, _prevTime) && _middle > 0) {
                                              _middle--;
                                              _prevTime = getTimestampbyQueryIdandIndex(
                                                  _queryId,
                                                  _middle
                                              );
                                          }
                                          if(_middle == 0 && isInDispute(_queryId, _prevTime)) {
                                              return (false, 0);
                                          }
                                          // _prevtime is correct
                                          return (true, _middle);
                                      }
                                  } else {
                                      //look from start to middle -1(prev value)
                                      _end = _middle - 1;
                                  }
                              }
                          }
                      }
                      return (false, 0);
                  }
                  /**
                   * @dev Returns the index of a reporter timestamp in the timestamp array for a specific data ID
                   * @param _queryId is ID of the specific data feed
                   * @param _timestamp is the timestamp to find in the timestamps array
                   * @return uint256 of the index of the reporter timestamp in the array for specific ID
                   */
                  function getTimestampIndexByTimestamp(bytes32 _queryId, uint256 _timestamp)
                      external
                      view
                      returns (uint256)
                  {
                      return reports[_queryId].timestampIndex[_timestamp];
                  }
                  /**
                   * @dev Returns the address of the token used for staking
                   * @return address of the token used for staking
                   */
                  function getTokenAddress() external view returns (address) {
                      return address(token);
                  }
                  /**
                   * @dev Returns total amount of token staked for reporting
                   * @return uint256 total amount of token staked
                   */
                  function getTotalStakeAmount() external view returns (uint256) {
                      return totalStakeAmount;
                  }
                  /**
                   * @dev Returns total number of current stakers. Reporters with stakedBalance less than stakeAmount are excluded from this total
                   * @return uint256 total stakers
                   */
                  function getTotalStakers() external view returns (uint256) {
                      return totalStakers;
                  }
                  /**
                   * @dev Returns total balance of time based rewards in contract
                   * @return uint256 amount of trb
                   */
                  function getTotalTimeBasedRewardsBalance() external view returns (uint256) {
                      return token.balanceOf(address(this)) - (totalStakeAmount + stakingRewardsBalance + toWithdraw);
                  }
                  /**
                   * @dev Returns whether a given value is disputed
                   * @param _queryId unique ID of the data feed
                   * @param _timestamp timestamp of the value
                   * @return bool whether the value is disputed
                   */
                  function isInDispute(bytes32 _queryId, uint256 _timestamp)
                      public
                      view
                      returns (bool)
                  {
                      return reports[_queryId].isDisputed[_timestamp];
                  }
                  /**
                   * @dev Retrieve value from oracle based on timestamp
                   * @param _queryId being requested
                   * @param _timestamp to retrieve data/value from
                   * @return bytes value for timestamp submitted
                   */
                  function retrieveData(bytes32 _queryId, uint256 _timestamp)
                      public
                      view
                      returns (bytes memory)
                  {
                      return reports[_queryId].valueByTimestamp[_timestamp];
                  }
                  /**
                   * @dev Used during the upgrade process to verify valid Tellor contracts
                   * @return bool value used to verify valid Tellor contracts
                   */
                  function verify() external pure returns (uint256) {
                      return 9999;
                  }
                  // *****************************************************************************
                  // *                                                                           *
                  // *                          Internal functions                               *
                  // *                                                                           *
                  // *****************************************************************************
                  /**
                   * @dev Updates accumulated staking rewards per staked token
                   */
                  function _updateRewards() internal {
                      if (timeOfLastAllocation == block.timestamp) {
                          return;
                      }
                      if (totalStakeAmount == 0 || rewardRate == 0) {
                          timeOfLastAllocation = block.timestamp;
                          return;
                      }
                      // calculate accumulated reward per token staked
                      uint256 _newAccumulatedRewardPerShare = accumulatedRewardPerShare +
                          ((block.timestamp - timeOfLastAllocation) * rewardRate * 1e18) /
                          totalStakeAmount;
                      // calculate accumulated reward with _newAccumulatedRewardPerShare
                      uint256 _accumulatedReward = (_newAccumulatedRewardPerShare *
                          totalStakeAmount) /
                          1e18 -
                          totalRewardDebt;
                      if (_accumulatedReward >= stakingRewardsBalance) {
                          // if staking rewards run out, calculate remaining reward per staked
                          // token and set rewardRate to 0
                          uint256 _newPendingRewards = stakingRewardsBalance -
                              ((accumulatedRewardPerShare * totalStakeAmount) /
                                  1e18 -
                                  totalRewardDebt);
                          accumulatedRewardPerShare +=
                              (_newPendingRewards * 1e18) /
                              totalStakeAmount;
                          rewardRate = 0;
                      } else {
                          accumulatedRewardPerShare = _newAccumulatedRewardPerShare;
                      }
                      timeOfLastAllocation = block.timestamp;
                  }
                  /**
                   * @dev Called whenever a user's stake amount changes. First updates staking rewards,
                   * transfers pending rewards to user's address, and finally updates user's stake amount
                   * and other relevant variables.
                   * @param _stakerAddress address of user whose stake is being updated
                   * @param _newStakedBalance new staked balance of user
                   */
                  function _updateStakeAndPayRewards(
                      address _stakerAddress,
                      uint256 _newStakedBalance
                  ) internal {
                      _updateRewards();
                      StakeInfo storage _staker = stakerDetails[_stakerAddress];
                      if (_staker.stakedBalance > 0) {
                          // if address already has a staked balance, calculate and transfer pending rewards
                          uint256 _pendingReward = (_staker.stakedBalance *
                              accumulatedRewardPerShare) /
                              1e18 -
                              _staker.rewardDebt;
                          // get staker voting participation rate
                          uint256 _numberOfVotes;
                          (bool _success, bytes memory _returnData) = governance.call(
                              abi.encodeWithSignature("getVoteCount()")
                          );
                          if (_success) {
                              _numberOfVotes =
                                  uint256(abi.decode(_returnData, (uint256))) -
                                  _staker.startVoteCount;
                          }
                          if (_numberOfVotes > 0) {
                              // staking reward = pending reward * voting participation rate
                              (_success, _returnData) = governance.call(
                                  abi.encodeWithSignature("getVoteTallyByAddress(address)",_stakerAddress)
                              );
                              if(_success){
                                  uint256 _voteTally = abi.decode(_returnData,(uint256));
                                  uint256 _tempPendingReward =
                                      (_pendingReward *
                                          (_voteTally - _staker.startVoteTally)) /
                                      _numberOfVotes;
                                  if (_tempPendingReward < _pendingReward) {
                                      _pendingReward = _tempPendingReward;
                                  }
                              }
                          }
                          stakingRewardsBalance -= _pendingReward;
                          require(token.transfer(msg.sender, _pendingReward));
                          totalRewardDebt -= _staker.rewardDebt;
                          totalStakeAmount -= _staker.stakedBalance;
                      }
                      _staker.stakedBalance = _newStakedBalance;
                      // Update total stakers
                      if (_staker.stakedBalance >= stakeAmount) {
                          if (_staker.staked == false) {
                              totalStakers++;
                          }
                          _staker.staked = true;
                      } else {
                          if (_staker.staked == true && totalStakers > 0) {
                              totalStakers--;
                          }
                          _staker.staked = false;
                      }
                      // tracks rewards accumulated before stake amount updated
                      _staker.rewardDebt =
                          (_staker.stakedBalance * accumulatedRewardPerShare) /
                          1e18;
                      totalRewardDebt += _staker.rewardDebt;
                      totalStakeAmount += _staker.stakedBalance;
                      // update reward rate if staking rewards are available 
                      // given staker's updated parameters
                      if(rewardRate == 0) {
                          rewardRate =
                          (stakingRewardsBalance -
                              ((accumulatedRewardPerShare * totalStakeAmount) /
                                  1e18 -
                                  totalRewardDebt)) /
                          30 days;
                      }
                  }
                  /**
                   * @dev Internal function retrieves updated accumulatedRewardPerShare
                   * @return uint256 up-to-date accumulated reward per share
                   */
                  function _getUpdatedAccumulatedRewardPerShare()
                      internal
                      view
                      returns (uint256)
                  {
                      if (totalStakeAmount == 0) {
                          return accumulatedRewardPerShare;
                      }
                      uint256 _newAccumulatedRewardPerShare = accumulatedRewardPerShare +
                          ((block.timestamp - timeOfLastAllocation) * rewardRate * 1e18) /
                          totalStakeAmount;
                      uint256 _accumulatedReward = (_newAccumulatedRewardPerShare *
                          totalStakeAmount) /
                          1e18 -
                          totalRewardDebt;
                      if (_accumulatedReward >= stakingRewardsBalance) {
                          uint256 _newPendingRewards = stakingRewardsBalance -
                              ((accumulatedRewardPerShare * totalStakeAmount) /
                                  1e18 -
                                  totalRewardDebt);
                          _newAccumulatedRewardPerShare =
                              accumulatedRewardPerShare +
                              (_newPendingRewards * 1e18) /
                              totalStakeAmount;
                      }
                      return _newAccumulatedRewardPerShare;
                  }
              }
              

              File 3 of 3: Tellor360
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              import "./BaseToken.sol";
              import "./NewTransition.sol";
              import "./interfaces/ITellorFlex.sol";
              /**
               @author Tellor Inc.
               @title Tellor360
               @dev This is the controller contract which defines the functionality for
               * changing the oracle contract address, as well as minting and migrating tokens
              */
              contract Tellor360 is BaseToken, NewTransition {
                  // Events
                  event NewOracleAddress(address _newOracle, uint256 _timestamp);
                  event NewProposedOracleAddress(
                      address _newProposedOracle,
                      uint256 _timestamp
                  );
                  // Functions
                  /**
                   * @dev Constructor used to store new flex oracle address
                   * @param _flexAddress is the new oracle contract which will replace the
                   * tellorX oracle
                   */
                  constructor(address _flexAddress) {
                      require(_flexAddress != address(0), "oracle address must be non-zero");
                      addresses[keccak256("_ORACLE_CONTRACT_FOR_INIT")] = _flexAddress;
                  }
                  /**
                   * @dev Use this function to initiate the contract
                   */
                  function init() external {
                      require(uints[keccak256("_INIT")] == 0, "should only happen once");
                      uints[keccak256("_INIT")] = 1;
                      // retrieve new oracle address from Tellor360 contract address storage
                      NewTransition _newController = NewTransition(
                          addresses[_TELLOR_CONTRACT]
                      );
                      address _flexAddress = _newController.getAddressVars(
                          keccak256("_ORACLE_CONTRACT_FOR_INIT")
                      );
                      //on switch over, require tellorFlex values are over 12 hours old
                      //then when we switch, the governance switch can be instantaneous
                      bytes32 _id = 0x83a7f3d48786ac2667503a61e8c415438ed2922eb86a2906e4ee66d9a2ce4992;
                      uint256 _firstTimestamp = IOracle(_flexAddress)
                          .getTimestampbyQueryIdandIndex(_id, 0);
                      require(
                          block.timestamp - _firstTimestamp >= 12 hours,
                          "contract should be at least 12 hours old"
                      );
                      addresses[_ORACLE_CONTRACT] = _flexAddress; //used by Liquity+AMPL for this contract's reads
                      //init minting uints (timestamps)
                      uints[keccak256("_LAST_RELEASE_TIME_TEAM")] = block.timestamp;
                      uints[keccak256("_LAST_RELEASE_TIME_DAO")] = block.timestamp - 12 weeks;
                      // transfer dispute fees collected during transition period to team
                      _doTransfer(
                          addresses[_GOVERNANCE_CONTRACT],
                          addresses[_OWNER],
                          balanceOf(addresses[_GOVERNANCE_CONTRACT])
                      );
                  }
                  /**
                   * @dev Mints tokens of the sender from the old contract to the sender
                   */
                  function migrate() external {
                      require(!migrated[msg.sender], "Already migrated");
                      _doMint(
                          msg.sender,
                          BaseToken(addresses[_OLD_TELLOR]).balanceOf(msg.sender)
                      );
                      migrated[msg.sender] = true;
                  }
                  /**
                   * @dev Use this function to withdraw released tokens to the oracle
                   */
                  function mintToOracle() external {
                      require(uints[keccak256("_INIT")] == 1, "tellor360 not initiated");
                      // X - 0.02X = 144 daily time based rewards. X = 146.94
                      uint256 _releasedAmount = (146.94 ether *
                          (block.timestamp - uints[keccak256("_LAST_RELEASE_TIME_DAO")])) /
                          86400;
                      uints[keccak256("_LAST_RELEASE_TIME_DAO")] = block.timestamp;
                      uint256 _stakingRewards = (_releasedAmount * 2) / 100;
                      _doMint(addresses[_ORACLE_CONTRACT], _releasedAmount - _stakingRewards);
                      // Send staking rewards
                      _doMint(address(this), _stakingRewards);
                      _allowances[address(this)][
                          addresses[_ORACLE_CONTRACT]
                      ] = _stakingRewards;
                      ITellorFlex(addresses[_ORACLE_CONTRACT]).addStakingRewards(
                          _stakingRewards
                      );
                  }
                  /**
                   * @dev Use this function to withdraw released tokens to the team
                   */
                  function mintToTeam() external {
                      require(uints[keccak256("_INIT")] == 1, "tellor360 not initiated");
                      uint256 _releasedAmount = (146.94 ether *
                          (block.timestamp - uints[keccak256("_LAST_RELEASE_TIME_TEAM")])) /
                          (86400);
                      uints[keccak256("_LAST_RELEASE_TIME_TEAM")] = block.timestamp;
                      _doMint(addresses[_OWNER], _releasedAmount);
                  }
                  /**
                   * @dev This function allows team to gain control of any tokens sent directly to this
                   * contract (and send them back))
                   */
                  function transferOutOfContract() external {
                      _doTransfer(address(this), addresses[_OWNER], balanceOf(address(this)));
                  }
                  /**
                   * @dev Use this function to update the oracle contract
                   */
                  function updateOracleAddress() external {
                      bytes32 _queryID = keccak256(
                          abi.encode("TellorOracleAddress", abi.encode(bytes("")))
                      );
                      bytes memory _proposedOracleAddressBytes;
                      (, _proposedOracleAddressBytes, ) = IOracle(addresses[_ORACLE_CONTRACT])
                          .getDataBefore(_queryID, block.timestamp - 12 hours);
                      address _proposedOracle = abi.decode(
                          _proposedOracleAddressBytes,
                          (address)
                      );
                      // If the oracle address being reported is the same as the proposed oracle then update the oracle contract
                      // only if 7 days have passed since the new oracle address was made official
                      // and if 12 hours have passed since query id 1 was first reported on the new oracle contract
                      if (_proposedOracle == addresses[keccak256("_PROPOSED_ORACLE")]) {
                          require(
                              block.timestamp >
                                  uints[keccak256("_TIME_PROPOSED_UPDATED")] + 7 days,
                              "must wait 7 days after proposing new oracle"
                          );
                          bytes32 _id = 0x83a7f3d48786ac2667503a61e8c415438ed2922eb86a2906e4ee66d9a2ce4992;
                          uint256 _firstTimestamp = IOracle(_proposedOracle)
                              .getTimestampbyQueryIdandIndex(_id, 0);
                          require(
                              block.timestamp - _firstTimestamp >= 12 hours,
                              "contract should be at least 12 hours old"
                          );
                          addresses[_ORACLE_CONTRACT] = _proposedOracle;
                          emit NewOracleAddress(_proposedOracle, block.timestamp);
                      }
                      // Otherwise if the current reported oracle is not the proposed oracle, then propose it and
                      // start the clock on the 7 days before it can be made official
                      else {
                          require(_isValid(_proposedOracle), "invalid oracle address");
                          addresses[keccak256("_PROPOSED_ORACLE")] = _proposedOracle;
                          uints[keccak256("_TIME_PROPOSED_UPDATED")] = block.timestamp;
                          emit NewProposedOracleAddress(_proposedOracle, block.timestamp);
                      }
                  }
                  /**
                   * @dev Used during the upgrade process to verify valid Tellor Contracts
                   */
                  function verify() external pure returns (uint256) {
                      return 9999;
                  }
                  /**Internal Functions */
                  /**
                   * @dev Used during the upgrade process to verify valid Tellor Contracts and ensure
                   * they have the right signature
                   * @param _contract is the address of the Tellor contract to verify
                   * @return bool of whether or not the address is a valid Tellor contract
                   */
                  function _isValid(address _contract) internal returns (bool) {
                      (bool _success, bytes memory _data) = address(_contract).call(
                          abi.encodeWithSelector(0xfc735e99, "") // verify() signature
                      );
                      require(
                          _success && abi.decode(_data, (uint256)) > 9000, // An arbitrary number to ensure that the contract is valid
                          "New contract is invalid"
                      );
                      return true;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              interface ITellorFlex {
                  function addStakingRewards(uint256 _amount) external;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              import "./oldContracts/contracts/TellorVars.sol";
              import "./oldContracts/contracts/interfaces/IOracle.sol";
              import "./oldContracts/contracts/tellor3/TellorStorage.sol";
              /**
               @author Tellor Inc.
               @title NewTransition
              * @dev The Transition contract links to the Oracle contract and
              * allows parties (like Liquity) to continue to use the master
              * address to access values which use legacy query IDs (request IDs). 
              */
              contract NewTransition is TellorStorage, TellorVars {
                  // Functions
                  //Getters
                  /**
                   * @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("_TELLOR_CONTRACT")]
                   * @return address of the requested variable
                   */
                  function getAddressVars(bytes32 _data) external view returns (address) {
                      return addresses[_data];
                  }
                  /**
                   * @dev Returns the latest value for a specific request ID.
                   * @param _requestId the requestId to look up
                   * @return uint256 the latest value of the request ID
                   * @return bool whether or not the value was successfully retrieved
                   */
                  function getLastNewValueById(uint256 _requestId)
                      external
                      view
                      returns (uint256, bool)
                  {
                      uint256 _count = getNewValueCountbyRequestId(_requestId);
                      if (_count == 0) {
                          return (0, false);
                      }
                      uint256 _latestTimestamp = getTimestampbyRequestIDandIndex(
                          _requestId,
                          _count - 1
                      );
                      return (retrieveData(_requestId, _latestTimestamp), true);
                  }
                  /**
                   * @dev Function is solely for the parachute contract
                   */
                  function getNewCurrentVariables()
                      external
                      view
                      returns (
                          bytes32 _c,
                          uint256[5] memory _r,
                          uint256 _diff,
                          uint256 _tip
                      )
                  {
                      _r = [uint256(1), uint256(1), uint256(1), uint256(1), uint256(1)];
                      _diff = 0;
                      _tip = 0;
                      _c = keccak256(
                          abi.encode(
                              IOracle(addresses[_ORACLE_CONTRACT]).getTimeOfLastNewValue()
                          )
                      );
                  }
                  /**
                   * @dev Counts the number of values that have been submitted for the requestId.
                   * @param _requestId the requestId to look up
                   * @return uint256 count of the number of values received for the requestId
                   */
                  function getNewValueCountbyRequestId(uint256 _requestId)
                      public
                      view
                      returns (uint256)
                  {
                      (bytes32 _queryId, ) = _getQueryIdAndDecimals(_requestId);
                      IOracle _oracle = IOracle(addresses[_ORACLE_CONTRACT]);
                      // try the new oracle first
                      try _oracle.getNewValueCountbyQueryId(_queryId) returns (
                          uint256 _valueCount
                      ) {
                          if (_valueCount == 0) {
                              return 0;
                          }
                          // if last value is disputed, subtract 1 from the count until a non-disputed value is found
                          uint256 _timestamp = _oracle.getTimestampbyQueryIdandIndex(
                              _queryId,
                              _valueCount - 1
                          );
                          while (
                              _oracle.isInDispute(_queryId, _timestamp) &&
                              _valueCount > 1
                          ) {
                              _valueCount--;
                              _timestamp = _oracle.getTimestampbyQueryIdandIndex(
                                  _queryId,
                                  _valueCount - 1
                              );
                          }
                          if (
                              _valueCount == 1 &&
                              _oracle.isInDispute(_queryId, _timestamp)
                          ) {
                              return 0;
                          }
                          return _valueCount;
                      } catch {
                          return
                              IOracle(addresses[_ORACLE_CONTRACT]).getTimestampCountById(
                                  bytes32(_requestId)
                              );
                      }
                  }
                  /**
                   * @dev Gets the timestamp for the value based on its index
                   * @param _requestId is the requestId to look up
                   * @param _index is the value index to look up
                   * @return uint256 timestamp
                   */
                  function getTimestampbyRequestIDandIndex(uint256 _requestId, uint256 _index)
                      public
                      view
                      returns (uint256)
                  {
                      (bytes32 _queryId, ) = _getQueryIdAndDecimals(_requestId);
                      try
                          IOracle(addresses[_ORACLE_CONTRACT]).getTimestampbyQueryIdandIndex(
                              _queryId,
                              _index
                          )
                      returns (uint256 _val) {
                          if(_requestId == 1 && _val > block.timestamp - 15 minutes) {
                              ( , , _val) = IOracle(addresses[_ORACLE_CONTRACT]).getDataBefore(_queryId, block.timestamp - 15 minutes);
                          }
                          return _val;
                      } catch {
                          return
                              IOracle(addresses[_ORACLE_CONTRACT]).getReportTimestampByIndex(
                                  bytes32(_requestId),
                                  _index
                              );
                      }
                  }
                  /**
                   * @dev Getter for the variables saved under the TellorStorageStruct uints 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 in the TellorVariables contract
                   * @return uint256 of specified variable
                   */
                  function getUintVar(bytes32 _data) external view returns (uint256) {
                      return uints[_data];
                  }
                  /**
                   * @dev Getter for if the party is migrated
                   * @param _addy address of party
                   * @return bool if the party is migrated
                   */
                  function isMigrated(address _addy) external view returns (bool) {
                      return migrated[_addy];
                  }
                  /**
                   * @dev Retrieve value from oracle based on timestamp
                   * @param _requestId being requested
                   * @param _timestamp to retrieve data/value from
                   * @return uint256 value for timestamp submitted
                   */
                  function retrieveData(uint256 _requestId, uint256 _timestamp)
                      public
                      view
                      returns (uint256)
                  {
                      (bytes32 _queryId, uint256 _decimalsAdjustment) = _getQueryIdAndDecimals(
                          _requestId
                      );
                      try
                          IOracle(addresses[_ORACLE_CONTRACT]).getValueByTimestamp(
                              bytes32(_requestId),
                              _timestamp
                          )
                      returns (bytes memory _val) {
                          return _sliceUint(_val);
                      } catch {
                          bytes memory _val;
                          if (_requestId == 1) {
                              (, _val, ) = IOracle(addresses[_ORACLE_CONTRACT])
                                  .getDataBefore(_queryId, block.timestamp - 15 minutes);
                          } else {
                               _val = IOracle(addresses[_ORACLE_CONTRACT])
                              .retrieveData(_queryId, _timestamp);
                          }
                          return (_sliceUint(_val) / (10**_decimalsAdjustment));
                      }
                  }
                  // Internal functions
                  /**
                   * @dev Utilized to help slice a bytes variable into a uint
                   * @param _b is the bytes variable to be sliced
                   * @return _number of the sliced uint256
                   */
                  function _sliceUint(bytes memory _b)
                      internal
                      pure
                      returns (uint256 _number)
                  {
                      for (uint256 _i = 0; _i < _b.length; _i++) {
                          _number = _number * 2**8;
                          _number = _number + uint8(_b[_i]);
                      }
                  }
                  function _getQueryIdAndDecimals(uint256 _requestId) internal pure returns (bytes32, uint256) {
                      bytes32 _queryId;
                      uint256 _decimalsAdjustment;
                      if(_requestId == 1) {
                          _queryId = 0x83a7f3d48786ac2667503a61e8c415438ed2922eb86a2906e4ee66d9a2ce4992; // SpotPrice(eth, usd)
                          _decimalsAdjustment = 12;
                      } else if(_requestId == 10) {
                          _queryId = 0x0d12ad49193163bbbeff4e6db8294ced23ff8605359fd666799d4e25a3aa0e3a; // AmpleforthCustomSpotPrice(0x)
                          _decimalsAdjustment = 0;
                      } else if(_requestId == 41) {
                          _queryId = 0x612ec1d9cee860bb87deb6370ed0ae43345c9302c085c1dfc4c207cbec2970d7; // AmpleforthUSPCE(0x)
                          _decimalsAdjustment = 0;
                      } else {
                          _queryId = bytes32(_requestId);
                          _decimalsAdjustment = 0;
                      }
                      return(_queryId, _decimalsAdjustment);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              import "./oldContracts/contracts/TellorVars.sol";
              import "./oldContracts/contracts/interfaces/IGovernance.sol";
              import "./oldContracts/contracts/tellor3/TellorStorage.sol";
              /**
               @author Tellor Inc.
               @title BaseToken
               @dev Contains the methods related to ERC20 transfers, allowance, and storage
              */
              contract BaseToken is TellorStorage, TellorVars {
                  // Events
                  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 This function approves a _spender an _amount of tokens to use
                   * @param _spender address receiving the allowance
                   * @param _amount amount the spender is being approved for
                   * @return bool true if spender approved successfully
                   */
                  function approve(address _spender, uint256 _amount)
                      external
                      returns (bool)
                  {
                      require(_spender != address(0), "ERC20: approve to the zero address");
                      _allowances[msg.sender][_spender] = _amount;
                      emit Approval(msg.sender, _spender, _amount);
                      return true;
                  }
                  /**
                   * @notice Allows tellor team to transfer stake of disputed TellorX reporter
                   * NOTE: this does not affect TellorFlex stakes, only disputes during 360 transition period
                   * @param _from the staker address holding the tokens being transferred
                   * @param _to the address of the recipient
                   */
                  function teamTransferDisputedStake(address _from, address _to) external {
                      require(
                          msg.sender == addresses[_OWNER],
                          "only owner can transfer disputed staked"
                      );
                      require(
                          stakerDetails[_from].currentStatus == 3,
                          "_from address not disputed"
                      );
                      stakerDetails[_from].currentStatus = 0;
                      _doTransfer(_from, _to, uints[_STAKE_AMOUNT]);
                  }
                  /**
                   * @dev Transfers _amount tokens from message sender to _to address
                   * @param _to token recipient
                   * @param _amount amount of tokens to send
                   * @return success whether the transfer was successful
                   */
                  function transfer(address _to, uint256 _amount)
                      external
                      returns (bool success)
                  {
                      _doTransfer(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 success whether the transfer was successful
                   */
                  function transferFrom(
                      address _from,
                      address _to,
                      uint256 _amount
                  ) external returns (bool success) {
                      require(
                          _allowances[_from][msg.sender] >= _amount,
                          "Allowance is wrong"
                      );
                      _allowances[_from][msg.sender] -= _amount;
                      _doTransfer(_from, _to, _amount);
                      return true;
                  }
                  // Getters
                  /**
                   * @dev Getter function for remaining spender balance
                   * @param _user address of party with the balance
                   * @param _spender address of spender of said user's balance
                   * @return uint256 the remaining allowance of tokens granted to the _spender from the _user
                   */
                  function allowance(address _user, address _spender)
                      external
                      view
                      returns (uint256)
                  {
                      return _allowances[_user][_spender];
                  }
                  /**
                   * @dev This function returns whether or not a given user is allowed to trade a given amount
                   * and removes the staked amount if they are staked in TellorX and disputed
                   * @param _user address of user
                   * @param _amount to check if the user can spend
                   * @return bool true if they are allowed to spend the amount being checked
                   */
                  function allowedToTrade(address _user, uint256 _amount)
                      public
                      view
                      returns (bool)
                  {
                      if (stakerDetails[_user].currentStatus == 3) {
                          // Subtracts the stakeAmount from balance if the _user is staked and disputed in TellorX
                          return (balanceOf(_user) - uints[_STAKE_AMOUNT] >= _amount);
                      }
                      return (balanceOf(_user) >= _amount); // Else, check if balance is greater than amount they want to spend
                  }
                  /**
                   * @dev Gets the balance of a given address
                   * @param _user the address whose balance to look up
                   * @return uint256 the balance of the given _user address
                   */
                  function balanceOf(address _user) public view returns (uint256) {
                      return balanceOfAt(_user, block.number);
                  }
                  /**
                   * @dev Gets the historic balance of a given _user address at a specific _blockNumber
                   * @param _user the address whose balance to look up
                   * @param _blockNumber the block number at which the balance is queried
                   * @return uint256 the balance of the _user address at the _blockNumber specified
                   */
                  function balanceOfAt(address _user, uint256 _blockNumber)
                      public
                      view
                      returns (uint256)
                  {
                      TellorStorage.Checkpoint[] storage checkpoints = 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 Allows users to access the number of decimals
                   */
                  function decimals() external pure returns (uint8) {
                      return 18;
                  }
                  /**
                   * @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 Getter for the total_supply of tokens
                   * @return uint256 total supply
                   */
                  function totalSupply() external view returns (uint256) {
                      return uints[_TOTAL_SUPPLY];
                  }
                  // Internal functions
                  /**
                   * @dev Helps mint new TRB
                   * @param _to is the address to send minted amount to
                   * @param _amount is the amount of TRB to mint and send
                   */
                  function _doMint(address _to, uint256 _amount) internal {
                      // Ensure to address and mint amount are valid
                      require(_amount != 0, "Tried to mint non-positive amount");
                      require(_to != address(0), "Receiver is 0 address");
                      uint128 _previousBalance = uint128(balanceOf(_to));
                      uint128 _sizedAmount = uint128(_amount);
                      // Update total supply and balance of _to address
                      uints[_TOTAL_SUPPLY] += _amount;
                      _updateBalanceAtNow(_to, _previousBalance + _sizedAmount);
                      emit Transfer(address(0), _to, _amount);
                  }
                  /**
                   * @dev Completes transfers by updating the balances at the current block number
                   * and ensuring the amount does not contain tokens locked for tellorX disputes
                   * @param _from address to transfer from
                   * @param _to address to transfer to
                   * @param _amount amount of tokens to transfer
                   */
                  function _doTransfer(
                      address _from,
                      address _to,
                      uint256 _amount
                  ) internal {
                      if (_amount == 0) {
                          return;
                      }
                      require(
                          allowedToTrade(_from, _amount),
                          "Should have sufficient balance to trade"
                      );
                      // Update balance of _from address
                      uint128 _previousBalance = uint128(balanceOf(_from));
                      uint128 _sizedAmount = uint128(_amount);
                      _updateBalanceAtNow(_from, _previousBalance - _sizedAmount);
                      // Update balance of _to address
                      _previousBalance = uint128(balanceOf(_to));
                      _updateBalanceAtNow(_to, _previousBalance + _sizedAmount);
                      emit Transfer(_from, _to, _amount);
                  }
                  /**
                   * @dev Updates balance checkpoint _amount for a given _user address at the current block number
                   * @param _user is the address whose balance to update
                   * @param _value is the new balance
                   */
                  function _updateBalanceAtNow(address _user, uint128 _value) internal {
                      Checkpoint[] storage checkpoints = balances[_user];
                      // Checks if no checkpoints exist, or if checkpoint block is not current block
                      if (
                          checkpoints.length == 0 ||
                          checkpoints[checkpoints.length - 1].fromBlock != block.number
                      ) {
                          // If yes, push a new checkpoint into the array
                          checkpoints.push(
                              TellorStorage.Checkpoint({
                                  fromBlock: uint128(block.number),
                                  value: _value
                              })
                          );
                      } else {
                          // Else, update old checkpoint
                          TellorStorage.Checkpoint storage oldCheckPoint = checkpoints[
                              checkpoints.length - 1
                          ];
                          oldCheckPoint.value = _value;
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              import "./tellor3/TellorVariables.sol";
              /**
               @author Tellor Inc.
               @title TellorVariables
               @dev Helper contract to store hashes of variables.
               * For each of the bytes32 constants, the values are equal to
               * keccak256([VARIABLE NAME])
              */
              contract TellorVars is TellorVariables {
                  // Storage
                  address constant TELLOR_ADDRESS =
                      0x88dF592F8eb5D7Bd38bFeF7dEb0fBc02cf3778a0; // Address of main Tellor Contract
                  // Hashes for each pertinent contract
                  bytes32 constant _GOVERNANCE_CONTRACT =
                      0xefa19baa864049f50491093580c5433e97e8d5e41f8db1a61108b4fa44cacd93;
                  bytes32 constant _ORACLE_CONTRACT =
                      0xfa522e460446113e8fd353d7fa015625a68bc0369712213a42e006346440891e;
                  bytes32 constant _TREASURY_CONTRACT =
                      0x1436a1a60dca0ebb2be98547e57992a0fa082eb479e7576303cbd384e934f1fa;
                  bytes32 constant _SWITCH_TIME =
                      0x6c0e91a96227393eb6e42b88e9a99f7c5ebd588098b549c949baf27ac9509d8f;
                  bytes32 constant _MINIMUM_DISPUTE_FEE =
                      0x7335d16d7e7f6cb9f532376441907fe76aa2ea267285c82892601f4755ed15f0;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.7.4;
              /**
                @author Tellor Inc.
                @title TellorStorage
                @dev Contains all the variables/structs used by Tellor
              */
              contract 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 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;
                      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 {
                      uint256[] requestTimestamps; //array of all newValueTimestamps requested
                      mapping(bytes32 => uint256) apiUintVars;
                      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;
                  }
                  uint256[51] requestQ; //uint50 array of the top50 requests by payment amount
                  uint256[] public newValueTimestamps; //array of all timestamps requested
                  //This is a boolean that tells you if a given challenge has been completed by a given miner
                  mapping(uint256 => uint256) requestIdByTimestamp; //minedTimestamp to apiId
                  mapping(uint256 => uint256) requestIdByRequestQIndex; //link from payoutPoolIndex (position in payout pool array) to apiId
                  mapping(uint256 => Dispute) public disputesById; //disputeId=> Dispute details
                  mapping(bytes32 => uint256) public requestIdByQueryHash; // api bytes32 gets an id = to count of requests array
                  mapping(bytes32 => uint256) public disputeIdByDisputeHash; //maps a hash to an ID for each dispute
                  mapping(bytes32 => mapping(address => bool)) public minersByChallenge;
                  Details[5] public currentMiners; //This struct is for organizing the five mined values to find the median
                  mapping(address => StakeInfo) stakerDetails; //mapping from a persons address to their staking info
                  mapping(uint256 => Request) requestDetails;
                  mapping(bytes32 => uint256) public uints;
                  mapping(bytes32 => address) public addresses;
                  mapping(bytes32 => bytes32) public bytesVars;
                  //ERC20 storage
                  mapping(address => Checkpoint[]) public balances;
                  mapping(address => mapping(address => uint256)) public _allowances;
                  //Migration storage
                  mapping(address => bool) public migrated;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              interface IOracle{
                  function getReportTimestampByIndex(bytes32 _queryId, uint256 _index) external view returns(uint256);
                  function getNewValueCountbyQueryId(bytes32 _queryId) external view returns(uint256);
                  function getValueByTimestamp(bytes32 _queryId, uint256 _timestamp) external view returns(bytes memory);
                  function getBlockNumberByTimestamp(bytes32 _queryId, uint256 _timestamp) external view returns(uint256);
                  function getReporterByTimestamp(bytes32 _queryId, uint256 _timestamp) external view returns(address);
                  function getReporterLastTimestamp(address _reporter) external view returns(uint256);
                  function reportingLock() external view returns(uint256);
                  function removeValue(bytes32 _queryId, uint256 _timestamp) external;
                  function getReportsSubmittedByAddress(address _reporter) external view returns(uint256);
                  function getTipsByUser(address _user) external view returns(uint256);
                  function tipQuery(bytes32 _queryId, uint256 _tip, bytes memory _queryData) external;
                  function submitValue(bytes32 _queryId, bytes calldata _value, uint256 _nonce, bytes memory _queryData) external;
                  function burnTips() external;
                  function verify() external pure returns(uint);
                  function changeReportingLock(uint256 _newReportingLock) external;
                  function changeTimeBasedReward(uint256 _newTimeBasedReward) external;
                  function getTipsById(bytes32 _queryId) external view returns(uint256);
                  function getTimestampCountById(bytes32 _queryId) external view returns(uint256);
                  function getTimestampIndexByTimestamp(bytes32 _queryId, uint256 _timestamp) external view returns(uint256);
                  function getCurrentValue(bytes32 _queryId) external view returns(bytes memory);
                  function getTimeOfLastNewValue() external view returns(uint256);
                  function getTimestampbyQueryIdandIndex(bytes32 _queryId, uint256 _index) external view returns(uint256);
                  function getDataBefore(bytes32 _queryId, uint256 _timestamp) external view returns(bool, bytes memory, uint256);
                  function getTokenAddress() external view returns(address);
                  function getStakeAmount() external view returns(uint256);
                  function isInDispute(bytes32 _queryId, uint256 _timestamp) external view returns(bool);
                  function slashReporter(address _reporter, address _recipient) external returns(uint256);
                  function retrieveData(bytes32 _queryId, uint256 _timestamp)
                      external
                      view
                      returns (bytes memory);
                  function getStakerInfo(address _stakerAddress)
                      external
                      view
                      returns (
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256,
                          uint256
                      );
                  
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.7.4;
              /**
               @author Tellor Inc.
               @title TellorVariables
               @dev Helper contract to store hashes of variables
              */
              contract TellorVariables {
                  bytes32 constant _BLOCK_NUMBER =
                      0x4b4cefd5ced7569ef0d091282b4bca9c52a034c56471a6061afd1bf307a2de7c; //keccak256("_BLOCK_NUMBER");
                  bytes32 constant _CURRENT_CHALLENGE =
                      0xd54702836c9d21d0727ffacc3e39f57c92b5ae0f50177e593bfb5ec66e3de280; //keccak256("_CURRENT_CHALLENGE");
                  bytes32 constant _CURRENT_REQUESTID =
                      0xf5126bb0ac211fbeeac2c0e89d4c02ac8cadb2da1cfb27b53c6c1f4587b48020; //keccak256("_CURRENT_REQUESTID");
                  bytes32 constant _CURRENT_REWARD =
                      0xd415862fd27fb74541e0f6f725b0c0d5b5fa1f22367d9b78ec6f61d97d05d5f8; //keccak256("_CURRENT_REWARD");
                  bytes32 constant _CURRENT_TOTAL_TIPS =
                      0x09659d32f99e50ac728058418d38174fe83a137c455ff1847e6fb8e15f78f77a; //keccak256("_CURRENT_TOTAL_TIPS");
                  bytes32 constant _DEITY =
                      0x5fc094d10c65bc33cc842217b2eccca0191ff24148319da094e540a559898961; //keccak256("_DEITY");
                  bytes32 constant _DIFFICULTY =
                      0xf758978fc1647996a3d9992f611883adc442931dc49488312360acc90601759b; //keccak256("_DIFFICULTY");
                  bytes32 constant _DISPUTE_COUNT =
                      0x310199159a20c50879ffb440b45802138b5b162ec9426720e9dd3ee8bbcdb9d7; //keccak256("_DISPUTE_COUNT");
                  bytes32 constant _DISPUTE_FEE =
                      0x675d2171f68d6f5545d54fb9b1fb61a0e6897e6188ca1cd664e7c9530d91ecfc; //keccak256("_DISPUTE_FEE");
                  bytes32 constant _DISPUTE_ROUNDS =
                      0x6ab2b18aafe78fd59c6a4092015bddd9fcacb8170f72b299074f74d76a91a923; //keccak256("_DISPUTE_ROUNDS");
                  bytes32 constant _EXTENSION =
                      0x2b2a1c876f73e67ebc4f1b08d10d54d62d62216382e0f4fd16c29155818207a4; //keccak256("_EXTENSION");
                  bytes32 constant _FEE =
                      0x1da95f11543c9b03927178e07951795dfc95c7501a9d1cf00e13414ca33bc409; //keccak256("_FEE");
                  bytes32 constant _FORK_EXECUTED =
                      0xda571dfc0b95cdc4a3835f5982cfdf36f73258bee7cb8eb797b4af8b17329875; //keccak256("_FORK_EXECUTED");
                  bytes32 constant _LOCK =
                      0xd051321aa26ce60d202f153d0c0e67687e975532ab88ce92d84f18e39895d907;
                  bytes32 constant _MIGRATOR =
                      0xc6b005d45c4c789dfe9e2895b51df4336782c5ff6bd59a5c5c9513955aa06307; //keccak256("_MIGRATOR");
                  bytes32 constant _MIN_EXECUTION_DATE =
                      0x46f7d53798d31923f6952572c6a19ad2d1a8238d26649c2f3493a6d69e425d28; //keccak256("_MIN_EXECUTION_DATE");
                  bytes32 constant _MINER_SLOT =
                      0x6de96ee4d33a0617f40a846309c8759048857f51b9d59a12d3c3786d4778883d; //keccak256("_MINER_SLOT");
                  bytes32 constant _NUM_OF_VOTES =
                      0x1da378694063870452ce03b189f48e04c1aa026348e74e6c86e10738514ad2c4; //keccak256("_NUM_OF_VOTES");
                  bytes32 constant _OLD_TELLOR =
                      0x56e0987db9eaec01ed9e0af003a0fd5c062371f9d23722eb4a3ebc74f16ea371; //keccak256("_OLD_TELLOR");
                  bytes32 constant _ORIGINAL_ID =
                      0xed92b4c1e0a9e559a31171d487ecbec963526662038ecfa3a71160bd62fb8733; //keccak256("_ORIGINAL_ID");
                  bytes32 constant _OWNER =
                      0x7a39905194de50bde334d18b76bbb36dddd11641d4d50b470cb837cf3bae5def; //keccak256("_OWNER");
                  bytes32 constant _PAID =
                      0x29169706298d2b6df50a532e958b56426de1465348b93650fca42d456eaec5fc; //keccak256("_PAID");
                  bytes32 constant _PENDING_OWNER =
                      0x7ec081f029b8ac7e2321f6ae8c6a6a517fda8fcbf63cabd63dfffaeaafa56cc0; //keccak256("_PENDING_OWNER");
                  bytes32 constant _REQUEST_COUNT =
                      0x3f8b5616fa9e7f2ce4a868fde15c58b92e77bc1acd6769bf1567629a3dc4c865; //keccak256("_REQUEST_COUNT");
                  bytes32 constant _REQUEST_ID =
                      0x9f47a2659c3d32b749ae717d975e7962959890862423c4318cf86e4ec220291f; //keccak256("_REQUEST_ID");
                  bytes32 constant _REQUEST_Q_POSITION =
                      0xf68d680ab3160f1aa5d9c3a1383c49e3e60bf3c0c031245cbb036f5ce99afaa1; //keccak256("_REQUEST_Q_POSITION");
                  bytes32 constant _SLOT_PROGRESS =
                      0xdfbec46864bc123768f0d134913175d9577a55bb71b9b2595fda21e21f36b082; //keccak256("_SLOT_PROGRESS");
                  bytes32 constant _STAKE_AMOUNT =
                      0x5d9fadfc729fd027e395e5157ef1b53ef9fa4a8f053043c5f159307543e7cc97; //keccak256("_STAKE_AMOUNT");
                  bytes32 constant _STAKE_COUNT =
                      0x10c168823622203e4057b65015ff4d95b4c650b308918e8c92dc32ab5a0a034b; //keccak256("_STAKE_COUNT");
                  bytes32 constant _T_BLOCK =
                      0xf3b93531fa65b3a18680d9ea49df06d96fbd883c4889dc7db866f8b131602dfb; //keccak256("_T_BLOCK");
                  bytes32 constant _TALLY_DATE =
                      0xf9e1ae10923bfc79f52e309baf8c7699edb821f91ef5b5bd07be29545917b3a6; //keccak256("_TALLY_DATE");
                  bytes32 constant _TARGET_MINERS =
                      0x0b8561044b4253c8df1d9ad9f9ce2e0f78e4bd42b2ed8dd2e909e85f750f3bc1; //keccak256("_TARGET_MINERS");
                  bytes32 constant _TELLOR_CONTRACT =
                      0x0f1293c916694ac6af4daa2f866f0448d0c2ce8847074a7896d397c961914a08; //keccak256("_TELLOR_CONTRACT");
                  bytes32 constant _TELLOR_GETTERS =
                      0xabd9bea65759494fe86471c8386762f989e1f2e778949e94efa4a9d1c4b3545a; //keccak256("_TELLOR_GETTERS");
                  bytes32 constant _TIME_OF_LAST_NEW_VALUE =
                      0x2c8b528fbaf48aaf13162a5a0519a7ad5a612da8ff8783465c17e076660a59f1; //keccak256("_TIME_OF_LAST_NEW_VALUE");
                  bytes32 constant _TIME_TARGET =
                      0xd4f87b8d0f3d3b7e665df74631f6100b2695daa0e30e40eeac02172e15a999e1; //keccak256("_TIME_TARGET");
                  bytes32 constant _TIMESTAMP =
                      0x2f9328a9c75282bec25bb04befad06926366736e0030c985108445fa728335e5; //keccak256("_TIMESTAMP");
                  bytes32 constant _TOTAL_SUPPLY =
                      0xe6148e7230ca038d456350e69a91b66968b222bfac9ebfbea6ff0a1fb7380160; //keccak256("_TOTAL_SUPPLY");
                  bytes32 constant _TOTAL_TIP =
                      0x1590276b7f31dd8e2a06f9a92867333eeb3eddbc91e73b9833e3e55d8e34f77d; //keccak256("_TOTAL_TIP");
                  bytes32 constant _VALUE =
                      0x9147231ab14efb72c38117f68521ddef8de64f092c18c69dbfb602ffc4de7f47; //keccak256("_VALUE");
                  bytes32 constant _EIP_SLOT =
                      0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.8.3;
              interface IGovernance{
                  enum VoteResult {FAILED,PASSED,INVALID}
                  function setApprovedFunction(bytes4 _func, bool _val) external;
                  function beginDispute(bytes32 _queryId,uint256 _timestamp) external;
                  function delegate(address _delegate) external;
                  function delegateOfAt(address _user, uint256 _blockNumber) external view returns (address);
                  function executeVote(uint256 _disputeId) external;
                  function proposeVote(address _contract,bytes4 _function, bytes calldata _data, uint256 _timestamp) external;
                  function tallyVotes(uint256 _disputeId) external;
                  function updateMinDisputeFee() external;
                  function verify() external pure returns(uint);
                  function vote(uint256 _disputeId, bool _supports, bool _invalidQuery) external;
                  function voteFor(address[] calldata _addys,uint256 _disputeId, bool _supports, bool _invalidQuery) external;
                  function getDelegateInfo(address _holder) external view returns(address,uint);
                  function isApprovedGovernanceContract(address _contract) external view returns(bool);
                  function isFunctionApproved(bytes4 _func) external view returns(bool);
                  function getVoteCount() external view returns(uint256);
                  function getVoteRounds(bytes32 _hash) external view returns(uint256[] memory);
                  function getVoteInfo(uint256 _disputeId) external view returns(bytes32,uint256[8] memory,bool[2] memory,VoteResult,bytes memory,bytes4,address[2] memory);
                  function getDisputeInfo(uint256 _disputeId) external view returns(uint256,uint256,bytes memory, address);
                  function getOpenDisputesOnId(uint256 _queryId) external view returns(uint256);
                  function didVote(uint256 _disputeId, address _voter) external view returns(bool);
                  function getVoteTallyByAddress(address _voter) external view returns (uint256);
                  //testing
                  function testMin(uint256 a, uint256 b) external pure returns (uint256);
              }