Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 12.2030414096296245 Eth | 12.203397161044772612 Eth | 0.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 )
File 1 of 3: TellorMaster
File 2 of 3: TellorFlex
File 3 of 3: Tellor360
// 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); }