ETH Price: $1,906.45 (-0.86%)

Transaction Decoder

Block:
22024964 at Mar-11-2025 04:57:23 PM +UTC
Transaction Fee:
0.000634108709909344 ETH $1.21
Gas Used:
270,448 Gas / 2.344660378 Gwei

Emitted Events:

118 TellorMaster.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000008cfc184c877154a8f9ffe0fe75649dbe5e2dbebf, 0x000000000000000000000000f9c7558e2e71f3e0ffe8b897426a3af89b6c516c, 000000000000000000000000000000000000000000000000030d98d59a960000 )
119 TellorFlex.NewReport( _queryId=83A7F3D48786AC2667503A61E8C415438ED2922EB86A2906E4EE66D9A2CE4992, _time=1741712243, _value=0x000000000000000000000000000000000000000000000068311BB0CEBCC80000, _nonce=79598, _queryData=0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000953706F745072696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003657468000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037573640000000000000000000000000000000000000000000000000000000000, _reporter=[Receiver] 0xf9c7558e2e71f3e0ffe8b897426a3af89b6c516c )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
12.2030414096296245 Eth12.203397161044772612 Eth0.000355751415148112
0x88dF592F...2cf3778a0
0x8cFc184c...e5e2DBEbf
(Tellor: Oracle Contract)
0xD1F16115...eE0334B66
4.487869684334501147 Eth
Nonce: 5529
4.487235575624591803 Eth
Nonce: 5530
0.000634108709909344

Execution Trace

0xf9c7558e2e71f3e0ffe8b897426a3af89b6c516c.5eaa9ced( )
  • TellorFlex.STATICCALL( )
  • TellorFlex.submitValue( _queryId=83A7F3D48786AC2667503A61E8C415438ED2922EB86A2906E4EE66D9A2CE4992, _value=0x000000000000000000000000000000000000000000000068311BB0CEBCC80000, _nonce=79598, _queryData=0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000953706F745072696365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003657468000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037573640000000000000000000000000000000000000000000000000000000000 )
    • TellorMaster.70a08231( )
      • Tellor360.balanceOf( _user=0x8cFc184c877154a8F9ffE0fe75649dbe5e2DBEbf ) => ( 44026993355802019662295 )
      • TellorMaster.a9059cbb( )
        • Tellor360.transfer( _to=0xF9c7558e2E71f3e0Ffe8b897426a3aF89b6c516c, _amount=220000000000000000 ) => ( success=True )
          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);
          }