Contract
0x3eb81A11DD28Fe8ED9f53D1456248aC86d5893C6
4
Contract Overview
Balance:
0 Ether
More Info
My Name Tag:
Not Available
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x0cb4d2b161acfcce66440c96b565f15789197c661a8babd6d97943273a3b5740 | 0x60806040 | 32105103 | 62 days 3 hrs ago | 0x79ef1fba1480b2d06cbd8fa67260a906909246f9 | IN | Create: Governance | 0 Ether | 0.00448496 |
[ Download CSV Export ]
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x0cb4d2b161acfcce66440c96b565f15789197c661a8babd6d97943273a3b5740 | 32105103 | 62 days 3 hrs ago | 0x3eb81a11dd28fe8ed9f53d1456248ac86d5893c6 | 0xbb97c038c338c3dcaf06d5be3b4a3e0b24835f9c | 0 Ether |
[ Download CSV Export ]
Contract Name:
Governance
Compiler Version
v0.8.3+commit.8d00100c
Optimization Enabled:
Yes with 300 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.3; import "./TellorFlex.sol"; /** @author Tellor Inc. @title Governance @dev This is a governance contract to be used with TellorFlex. It handles disputing * Tellor oracle data, proposing system parameter changes, and voting on those * disputes and proposals. */ contract Governance { // Storage TellorFlex public tellor; // Tellor oracle contract IERC20 public token; // token used for dispute fees, same as reporter staking token address public teamMultisig; // address of team multisig wallet, one of four stakeholder groups uint256 public voteCount; // total number of votes initiated uint256 public disputeFee; // dispute fee for a vote mapping(uint256 => Dispute) private disputeInfo; // mapping of dispute IDs to the details of the dispute mapping(bytes32 => uint256) private openDisputesOnId; // mapping of a query ID to the number of disputes on that query ID mapping(address => bool) private users; // mapping of users with voting power, determined by governance proposal votes mapping(uint256 => Vote) private voteInfo; // mapping of dispute IDs to the details of the vote mapping(bytes32 => uint256[]) private voteRounds; // mapping of vote identifier hashes to an array of dispute IDs enum VoteResult { FAILED, PASSED, INVALID } // status of a potential vote // Structs struct Dispute { bytes32 queryId; // query ID of disputed value uint256 timestamp; // timestamp of disputed value bytes value; // disputed value address disputedReporter; // reporter who submitted the disputed value uint256 slashedAmount; // amount of tokens slashed from reporter } struct Tally { uint256 doesSupport; // number of votes in favor uint256 against; // number of votes against uint256 invalidQuery; // number of votes for invalid } struct Vote { bytes32 identifierHash; // identifier hash of the vote uint256 voteRound; // the round of voting on a given dispute or proposal uint256 startDate; // timestamp of when vote was initiated uint256 blockNumber; // block number of when vote was initiated uint256 fee; // fee paid to initiate the vote round uint256 tallyDate; // timestamp of when the votes were tallied Tally tokenholders; // vote tally of tokenholders Tally users; // vote tally of users Tally reporters; // vote tally of reporters Tally teamMultisig; // vote tally of teamMultisig bool executed; // boolean of whether the vote was executed VoteResult result; // VoteResult after votes were tallied bool isDispute; // boolean of whether the vote is a dispute as opposed to a proposal bytes data; // arguments used to execute a proposal bytes4 voteFunction; // hash of the function associated with a proposal vote address voteAddress; // address of contract to execute function on address initiator; // address which initiated dispute/proposal mapping(address => bool) voted; // mapping of address to whether or not they voted } // Events event NewDispute( uint256 _disputeId, bytes32 _queryId, uint256 _timestamp, address _reporter ); // Emitted when a new dispute is opened event NewVote( address _contract, bytes4 _function, bytes _data, uint256 _disputeId ); // Emitted when a new proposal vote is initiated event Voted( uint256 _disputeId, bool _supports, address _voter, bool _invalidQuery ); // Emitted when an address casts their vote event VoteExecuted(uint256 _disputeId, VoteResult _result); // Emitted when a vote is executed event VoteTallied( uint256 _disputeId, VoteResult _result, address _initiator, address _reporter ); // Emitted when all casting for a vote is tallied /** * @dev Initializes contract parameters * @param _tellor address of tellor oracle contract to be governed * @param _disputeFee base dispute fee * @param _teamMultisig address of tellor team multisig, one of four voting * stakeholder groups */ constructor( address _tellor, uint256 _disputeFee, address _teamMultisig ) { tellor = TellorFlex(_tellor); token = tellor.token(); disputeFee = _disputeFee; teamMultisig = _teamMultisig; } /** * @dev Helps initialize a dispute by assigning it a disputeId * @param _queryId being disputed * @param _timestamp being disputed */ function beginDispute(bytes32 _queryId, uint256 _timestamp) external { // Ensure value actually exists require( tellor.getBlockNumberByTimestamp(_queryId, _timestamp) != 0, "no value exists at given timestamp" ); bytes32 _hash = keccak256(abi.encodePacked(_queryId, _timestamp)); // Increment vote count and push new vote round voteCount++; uint256 _disputeId = voteCount; voteRounds[_hash].push(_disputeId); // Check if dispute is started within correct time frame if (voteRounds[_hash].length > 1) { uint256 _prevId = voteRounds[_hash][voteRounds[_hash].length - 2]; require( block.timestamp - voteInfo[_prevId].tallyDate < 1 days, "New dispute round must be started within a day" ); // Within a day for new round } else { require( block.timestamp - _timestamp < tellor.reportingLock(), "Dispute must be started within reporting lock time" ); // New dispute within reporting lock openDisputesOnId[_queryId]++; } // Create new vote and dispute Vote storage _thisVote = voteInfo[_disputeId]; Dispute storage _thisDispute = disputeInfo[_disputeId]; // Initialize dispute information - query ID, timestamp, value, etc. _thisDispute.queryId = _queryId; _thisDispute.timestamp = _timestamp; _thisDispute.value = tellor.retrieveData(_queryId, _timestamp); _thisDispute.disputedReporter = tellor.getReporterByTimestamp( _queryId, _timestamp ); // Initialize vote information - hash, initiator, block number, etc. _thisVote.identifierHash = _hash; _thisVote.initiator = msg.sender; _thisVote.blockNumber = block.number; _thisVote.startDate = block.timestamp; _thisVote.voteRound = voteRounds[_hash].length; _thisVote.isDispute = true; // Calculate dispute fee based on number of current vote rounds uint256 _fee; if (voteRounds[_hash].length == 1) { _fee = disputeFee * 2**(openDisputesOnId[_queryId] - 1); } else { _fee = disputeFee * 2**(voteRounds[_hash].length - 1); } if (_fee > tellor.stakeAmount()) { _fee = tellor.stakeAmount(); } _thisVote.fee = _fee; _thisVote.fee = _fee; require( token.transferFrom(msg.sender, address(this), _fee), "Fee must be paid" ); // This is the dispute fee. Returned if dispute passes if (voteRounds[_hash].length == 1) { _thisDispute.slashedAmount = tellor.slashReporter( _thisDispute.disputedReporter, address(this) ); tellor.removeValue(_queryId, _timestamp); } else { _thisDispute.slashedAmount = disputeInfo[voteRounds[_hash][0]] .slashedAmount; } emit NewDispute( _disputeId, _queryId, _timestamp, _thisDispute.disputedReporter ); } /** * @dev Executes vote by using result and transferring balance to either * initiator or disputed reporter * @param _disputeId is the ID of the vote being executed */ function executeVote(uint256 _disputeId) external { // Ensure validity of vote ID, vote has been executed, and vote must be tallied Vote storage _thisVote = voteInfo[_disputeId]; require(_disputeId <= voteCount, "Vote ID must be valid"); require(!_thisVote.executed, "Vote has been executed"); require(_thisVote.tallyDate > 0, "Vote must be tallied"); // Ensure vote must be final vote and that time has to be pass (86400 = 24 * 60 * 60 for seconds in a day) require( voteRounds[_thisVote.identifierHash].length == _thisVote.voteRound, "Must be the final vote" ); require( block.timestamp - _thisVote.tallyDate >= 86400 * _thisVote.voteRound, "Vote needs to be tallied and time must pass" ); _thisVote.executed = true; if (!_thisVote.isDispute) { // If vote is not in dispute and passed, execute proper vote function with vote data if (_thisVote.result == VoteResult.PASSED) { address _destination = _thisVote.voteAddress; bool _succ; bytes memory _res; (_succ, _res) = _destination.call( abi.encodePacked(_thisVote.voteFunction, _thisVote.data) ); //When testing _destination.call can require higher gas than the standard. Be sure to increase the gas if it fails. } emit VoteExecuted(_disputeId, _thisVote.result); } else { Dispute storage _thisDispute = disputeInfo[_disputeId]; if ( voteRounds[_thisVote.identifierHash].length == _thisVote.voteRound ) { openDisputesOnId[_thisDispute.queryId]--; } uint256 _i; uint256 _voteID; if (_thisVote.result == VoteResult.PASSED) { // If vote is in dispute and passed, iterate through each vote round and transfer the dispute to initiator for ( _i = voteRounds[_thisVote.identifierHash].length; _i > 0; _i-- ) { _voteID = voteRounds[_thisVote.identifierHash][_i - 1]; _thisVote = voteInfo[_voteID]; // If the first vote round, also make sure to transfer the reporter's slashed stake to the initiator if (_i == 1) { token.transfer( _thisVote.initiator, _thisDispute.slashedAmount ); } token.transfer(_thisVote.initiator, _thisVote.fee); } } else if (_thisVote.result == VoteResult.INVALID) { // If vote is in dispute and is invalid, iterate through each vote round and transfer the dispute fee to initiator for ( _i = voteRounds[_thisVote.identifierHash].length; _i > 0; _i-- ) { _voteID = voteRounds[_thisVote.identifierHash][_i - 1]; _thisVote = voteInfo[_voteID]; token.transfer(_thisVote.initiator, _thisVote.fee); } // Transfer slashed tokens back to disputed reporter token.transfer( _thisDispute.disputedReporter, _thisDispute.slashedAmount ); } else if (_thisVote.result == VoteResult.FAILED) { // If vote is in dispute and fails, iterate through each vote round and transfer the dispute fee to disputed reporter uint256 _reporterReward = 0; for ( _i = voteRounds[_thisVote.identifierHash].length; _i > 0; _i-- ) { _voteID = voteRounds[_thisVote.identifierHash][_i - 1]; _thisVote = voteInfo[_voteID]; _reporterReward += _thisVote.fee; } _reporterReward += _thisDispute.slashedAmount; token.transfer(_thisDispute.disputedReporter, _reporterReward); } emit VoteExecuted(_disputeId, voteInfo[_disputeId].result); } } /** * @dev Initializes proposal to change oracle governance address * @param _newGovernanceAddress proposed new governance address * @param _timestamp used to differentiate proposals. If set to zero, timestamp * will automatically be reset to block timestamp */ function proposeChangeGovernanceAddress( address _newGovernanceAddress, uint256 _timestamp ) external { _proposeVote( address(tellor), bytes4(keccak256(bytes("changeGovernanceAddress(address)"))), abi.encode(_newGovernanceAddress), _timestamp ); } /** * @dev Initializes proposal to change reporting lock time * @param _newReportingLock proposed new reporting lock time * @param _timestamp used to differentiate proposals. If set to zero, timestamp * will automatically be reset to block timestamp */ function proposeChangeReportingLock( uint256 _newReportingLock, uint256 _timestamp ) external { _proposeVote( address(tellor), bytes4(keccak256(bytes("changeReportingLock(uint256)"))), abi.encode(_newReportingLock), _timestamp ); } /** * @dev Initializes proposal to change stake amount * @param _newStakeAmount proposed new stake amount * @param _timestamp used to differentiate proposals. If set to zero, timestamp * will automatically be reset to block timestamp */ function proposeChangeStakeAmount( uint256 _newStakeAmount, uint256 _timestamp ) external { _proposeVote( address(tellor), bytes4(keccak256(bytes("changeStakeAmount(uint256)"))), abi.encode(_newStakeAmount), _timestamp ); } /** * @dev Initializes proposal to update user stakeholder list * @param _address address whose user status to update * @param _isUser true to set address as user, false to remove address from user list * @param _timestamp used to differentiate proposals. If set to zero, timestamp * will automatically be reset to block timestamp */ function proposeUpdateUserList( address _address, bool _isUser, uint256 _timestamp ) external { _proposeVote( address(this), bytes4(keccak256(bytes("updateUserList(address,bool)"))), abi.encode(_address, _isUser), _timestamp ); } /** * @dev Tallies the votes and begins the 1 day challenge period * @param _disputeId is the dispute id */ function tallyVotes(uint256 _disputeId) external { // Ensure vote has not been executed and that vote has not been tallied Vote storage _thisVote = voteInfo[_disputeId]; require(!_thisVote.executed, "Dispute has already been executed"); require(_thisVote.tallyDate == 0, "Vote has already been tallied"); require(_disputeId <= voteCount, "Vote does not exist"); // Determine appropriate vote duration and quorum based on dispute status uint256 _duration = 2 days; if (!_thisVote.isDispute) { _duration = 7 days; } // Ensure voting is not still open require( block.timestamp - _thisVote.startDate > _duration, "Time for voting has not elapsed" ); // Get total votes from each separate stakeholder group. This will allow // normalization so each group's votes can be combined and compared to // determine the vote outcome. uint256 tokenVoteSum = _thisVote.tokenholders.doesSupport + _thisVote.tokenholders.against + _thisVote.tokenholders.invalidQuery; uint256 reportersVoteSum = _thisVote.reporters.doesSupport + _thisVote.reporters.against + _thisVote.reporters.invalidQuery; uint256 multisigVoteSum = _thisVote.teamMultisig.doesSupport + _thisVote.teamMultisig.against + _thisVote.teamMultisig.invalidQuery; uint256 usersVoteSum = _thisVote.users.doesSupport + _thisVote.users.against + _thisVote.users.invalidQuery; // Cannot divide by zero if ( tokenVoteSum * reportersVoteSum * multisigVoteSum * usersVoteSum == 0 ) { if (tokenVoteSum == 0) { tokenVoteSum++; } if (reportersVoteSum == 0) { reportersVoteSum++; } if (multisigVoteSum == 0) { multisigVoteSum++; } if (usersVoteSum == 0) { usersVoteSum++; } } // Normalize and combine each stakeholder group votes uint256 scaledDoesSupport = ((_thisVote.tokenholders.doesSupport * 10000) / tokenVoteSum) + ((_thisVote.reporters.doesSupport * 10000) / reportersVoteSum) + ((_thisVote.teamMultisig.doesSupport * 10000) / multisigVoteSum) + ((_thisVote.users.doesSupport * 10000) / multisigVoteSum); uint256 scaledAgainst = ((_thisVote.tokenholders.against * 10000) / tokenVoteSum) + ((_thisVote.reporters.against * 10000) / reportersVoteSum) + ((_thisVote.teamMultisig.against * 10000) / multisigVoteSum) + ((_thisVote.users.against * 10000) / multisigVoteSum); uint256 scaledInvalid = ((_thisVote.tokenholders.invalidQuery * 10000) / tokenVoteSum) + ((_thisVote.reporters.invalidQuery * 10000) / reportersVoteSum) + ((_thisVote.teamMultisig.invalidQuery * 10000) / multisigVoteSum) + ((_thisVote.users.invalidQuery * 10000) / multisigVoteSum); // If there are more invalid votes than for and against, result is invalid if ( scaledInvalid >= scaledDoesSupport && scaledInvalid >= scaledAgainst && _thisVote.isDispute ) { _thisVote.result = VoteResult.INVALID; } else if (scaledDoesSupport > scaledAgainst) { // If there are more support votes than against votes, allow the vote to pass _thisVote.result = VoteResult.PASSED; } // If there are more against votes than support votes, the result failed else { _thisVote.result = VoteResult.FAILED; } _thisVote.tallyDate = block.timestamp; // Update time vote was tallied emit VoteTallied( _disputeId, _thisVote.result, _thisVote.initiator, disputeInfo[_disputeId].disputedReporter ); } /** * @dev Changes address's status as user. Can only be called by this contract * through a proposeUpdateUserList proposal * @param _address address whose user status to update * @param _isUser true to set address as user, false to remove address from user list */ function updateUserList(address _address, bool _isUser) external { require( msg.sender == address(this), "Only governance can update user list" ); users[_address] = _isUser; } /** * @dev Enables the sender address to cast a vote * @param _disputeId is the ID of the vote * @param _supports is the address's vote: whether or not they support or are against * @param _invalidQuery is whether or not the dispute is valid */ function vote( uint256 _disputeId, bool _supports, bool _invalidQuery ) external { // Ensure that dispute has not been executed and that vote does not exist and is not tallied require(_disputeId <= voteCount, "Vote does not exist"); Vote storage _thisVote = voteInfo[_disputeId]; require(_thisVote.tallyDate == 0, "Vote has already been tallied"); require(!_thisVote.voted[msg.sender], "Sender has already voted"); // Update voting status and increment total queries for support, invalid, or against based on vote _thisVote.voted[msg.sender] = true; uint256 voteWeight = token.balanceOf(msg.sender); (, uint256 stakedBalance, uint256 lockedBalance, , ) = tellor .getStakerInfo(msg.sender); voteWeight += stakedBalance + lockedBalance; if (_thisVote.isDispute && _invalidQuery) { if (voteWeight > 0) { _thisVote.tokenholders.invalidQuery += voteWeight; } voteWeight = tellor.getReportsSubmittedByAddress(msg.sender); if (voteWeight > 0) { _thisVote.reporters.invalidQuery += voteWeight; } if (users[msg.sender]) { _thisVote.users.invalidQuery += 1; } if (msg.sender == teamMultisig) { _thisVote.teamMultisig.invalidQuery += 1; } } else if (_supports) { if (voteWeight > 0) { _thisVote.tokenholders.doesSupport += voteWeight; } voteWeight = tellor.getReportsSubmittedByAddress(msg.sender); if (voteWeight > 0) { _thisVote.reporters.doesSupport += voteWeight; } if (users[msg.sender]) { _thisVote.users.doesSupport += 1; } if (msg.sender == teamMultisig) { _thisVote.teamMultisig.doesSupport += 1; } } else { if (voteWeight > 0) { _thisVote.tokenholders.against += voteWeight; } voteWeight = tellor.getReportsSubmittedByAddress(msg.sender); if (voteWeight > 0) { _thisVote.reporters.against += voteWeight; } if (users[msg.sender]) { _thisVote.users.against += 1; } if (msg.sender == teamMultisig) { _thisVote.teamMultisig.against += 1; } } emit Voted(_disputeId, _supports, msg.sender, _invalidQuery); } // Getters /** * @dev Determines if an address voted for a specific vote * @param _disputeId is the ID of the vote * @param _voter is the address of the voter to check for * @return bool of whether or note the address voted for the specific vote */ function didVote(uint256 _disputeId, address _voter) external view returns (bool) { return voteInfo[_disputeId].voted[_voter]; } /** * @dev Returns info on a dispute for a given ID * @param _disputeId is the ID of a specific dispute * @return bytes32 of the data ID of the dispute * @return uint256 of the timestamp of the dispute * @return bytes memory of the value being disputed * @return address of the reporter being disputed */ function getDisputeInfo(uint256 _disputeId) external view returns ( bytes32, uint256, bytes memory, address ) { Dispute storage _d = disputeInfo[_disputeId]; return (_d.queryId, _d.timestamp, _d.value, _d.disputedReporter); } /** * @dev Returns the number of open disputes for a specific query ID * @param _queryId is the ID of a specific data feed * @return uint256 of the number of open disputes for the query ID */ function getOpenDisputesOnId(bytes32 _queryId) external view returns (uint256) { return openDisputesOnId[_queryId]; } /** * @dev Returns the total number of votes * @return uint256 of the total number of votes */ function getVoteCount() external view returns (uint256) { return voteCount; } /** * @dev Returns info on a vote for a given vote ID * @param _disputeId is the ID of a specific vote * @return bytes32 identifier hash of the vote * @return uint256[8] memory of the pertinent round info (vote rounds, start date, fee, etc.) * @return bool[2] memory of both whether or not the vote was executed and is dispute * @return VoteResult result of the vote * @return bytes memory of the argument data of a proposal vote * @return bytes4 of the function selector proposed to be called * @return address[2] memory of the Tellor system contract address and vote initiator */ function getVoteInfo(uint256 _disputeId) external view returns ( bytes32, uint256[17] memory, bool[2] memory, VoteResult, bytes memory, bytes4, address[2] memory ) { Vote storage _v = voteInfo[_disputeId]; return ( _v.identifierHash, [ _v.voteRound, _v.startDate, _v.blockNumber, _v.fee, _v.tallyDate, _v.tokenholders.doesSupport, _v.tokenholders.against, _v.tokenholders.invalidQuery, _v.users.doesSupport, _v.users.against, _v.users.invalidQuery, _v.reporters.doesSupport, _v.reporters.against, _v.reporters.invalidQuery, _v.teamMultisig.doesSupport, _v.teamMultisig.against, _v.teamMultisig.invalidQuery ], [_v.executed, _v.isDispute], _v.result, _v.data, _v.voteFunction, [_v.voteAddress, _v.initiator] ); } /** * @dev Returns an array of voting rounds for a given vote * @param _hash is the identifier hash for a vote * @return uint256[] memory dispute IDs of the vote rounds */ function getVoteRounds(bytes32 _hash) external view returns (uint256[] memory) { return voteRounds[_hash]; } /** * @dev Returns boolean value for whether a given address is set as a user with * voting rights * @param _address address of potential user * @return bool whether or not the address is set as a user */ function isUser(address _address) external view returns (bool) { return users[_address]; } // Internal /** * @dev Proposes a vote for an associated Tellor contract and function, and defines the properties of the vote * @param _contract is the Tellor contract to propose a vote for -> used to calculate identifier hash * @param _function is the Tellor function to propose a vote for -> used to calculate identifier hash * @param _data is the function argument data associated with the vote proposal -> used to calculate identifier hash * @param _timestamp is the timestamp associated with the vote -> used to calculate identifier hash */ function _proposeVote( address _contract, bytes4 _function, bytes memory _data, uint256 _timestamp ) internal { // Update vote count, vote ID, current vote, and timestamp voteCount++; uint256 _disputeId = voteCount; Vote storage _thisVote = voteInfo[_disputeId]; if (_timestamp == 0) { _timestamp = block.timestamp; } // Calculate vote identifier hash and push to vote rounds bytes32 _hash = keccak256( abi.encodePacked(_contract, _function, _data, _timestamp) ); voteRounds[_hash].push(_disputeId); // Ensure new dispute round started within a day if (voteRounds[_hash].length > 1) { uint256 _prevId = voteRounds[_hash][voteRounds[_hash].length - 2]; require( block.timestamp - voteInfo[_prevId].tallyDate < 1 days, "New dispute round must be started within a day" ); // 1 day for new disputes } // Calculate fee to propose vote. Starts as just 10 tokens flat, doubles with each round uint256 _fee = 10e18 * 2**(voteRounds[_hash].length - 1); require( token.transferFrom(msg.sender, address(this), _fee), "Fee must be paid" ); // Update information on vote -- hash, vote round, start date, block number, fee, etc. _thisVote.identifierHash = _hash; _thisVote.voteRound = voteRounds[_hash].length; _thisVote.startDate = block.timestamp; _thisVote.blockNumber = block.number; _thisVote.fee = _fee; _thisVote.data = _data; _thisVote.voteFunction = _function; _thisVote.voteAddress = _contract; _thisVote.initiator = msg.sender; emit NewVote(_contract, _function, _data, _disputeId); } }
// 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 { IERC20 public token; address public governance; uint256 public stakeAmount; //amount required to be a staker uint256 public totalStakeAmount; //total amount of tokens locked in contract (via stake) uint256 public reportingLock; // base amount of time before a reporter is able to submit a value again uint256 public timeOfLastNewValue = block.timestamp; // time of the last new submitted value, originally set to the block timestamp mapping(bytes32 => Report) private reports; // mapping of query IDs to a report mapping(address => StakeInfo) 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 => uint256) timestampToBlockNum; // mapping of timestamp to block number mapping(uint256 => bytes) valueByTimestamp; // mapping of timestamps to values mapping(uint256 => address) reporterByTimestamp; // mapping of timestamps to reporters } struct StakeInfo { uint256 startDate; //stake start date uint256 stakedBalance; // staked balance uint256 lockedBalance; // amount locked for withdrawal uint256 reporterLastTimestamp; // timestamp of reporter's last reported value uint256 reportsSubmitted; // total number of reports submitted by reporter mapping(bytes32 => uint256) reportsSubmittedByQueryId; } // Events event NewGovernanceAddress(address _newGovernanceAddress); event NewReport( bytes32 _queryId, uint256 _time, bytes _value, uint256 _nonce, bytes _queryData, address _reporter ); event NewReportingLock(uint256 _newReportingLock); event NewStakeAmount(uint256 _newStakeAmount); event NewStaker(address _staker, uint256 _amount); event ReporterSlashed( address _reporter, address _recipient, uint256 _slashAmount ); event StakeWithdrawRequested(address _staker, uint256 _amount); event StakeWithdrawn(address _staker); event ValueRemoved(bytes32 _queryId, uint256 _timestamp); /** * @dev Initializes system parameters * @param _token address of token used for staking * @param _governance address which controls system * @param _stakeAmount amount of token needed to report oracle values * @param _reportingLock base amount of time (seconds) before reporter is able to report again */ constructor( address _token, address _governance, uint256 _stakeAmount, uint256 _reportingLock ) { require(_token != address(0), "must set token address"); require(_governance != address(0), "must set governance address"); token = IERC20(_token); governance = _governance; stakeAmount = _stakeAmount; reportingLock = _reportingLock; } /** * @dev Changes governance address * @param _newGovernanceAddress new governance address */ function changeGovernanceAddress(address _newGovernanceAddress) external { require(msg.sender == governance, "caller must be governance address"); require( _newGovernanceAddress != address(0), "must set governance address" ); governance = _newGovernanceAddress; emit NewGovernanceAddress(_newGovernanceAddress); } /** * @dev Changes base amount of time (seconds) before reporter is allowed to report again * @param _newReportingLock new reporter lock time in seconds */ function changeReportingLock(uint256 _newReportingLock) external { require(msg.sender == governance, "caller must be governance address"); require( _newReportingLock > 0, "reporting lock must be greater than zero" ); reportingLock = _newReportingLock; emit NewReportingLock(_newReportingLock); } /** * @dev Changes amount of token stake required to report values * @param _newStakeAmount new reporter stake amount */ function changeStakeAmount(uint256 _newStakeAmount) external { require(msg.sender == governance, "caller must be governance address"); require(_newStakeAmount > 0, "stake amount must be greater than zero"); stakeAmount = _newStakeAmount; emit NewStakeAmount(_newStakeAmount); } /** * @dev Allows a reporter to submit stake * @param _amount amount of tokens to stake */ function depositStake(uint256 _amount) external { StakeInfo storage _staker = stakerDetails[msg.sender]; if (_staker.lockedBalance > 0) { if (_staker.lockedBalance >= _amount) { _staker.lockedBalance -= _amount; } else { require( token.transferFrom( msg.sender, address(this), _amount - _staker.lockedBalance ) ); _staker.lockedBalance = 0; } } else { require(token.transferFrom(msg.sender, address(this), _amount)); } _staker.startDate = block.timestamp; // This resets their stake start date to now _staker.stakedBalance += _amount; totalStakeAmount += _amount; 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 rep = reports[_queryId]; uint256 _index = rep.timestampIndex[_timestamp]; require(_timestamp == rep.timestamps[_index], "invalid timestamp"); // Shift all timestamps back to reflect deletion of value for (uint256 _i = _index; _i < rep.timestamps.length - 1; _i++) { rep.timestamps[_i] = rep.timestamps[_i + 1]; rep.timestampIndex[rep.timestamps[_i]] -= 1; } // Delete and reset timestamp and value delete rep.timestamps[rep.timestamps.length - 1]; rep.timestamps.pop(); rep.valueByTimestamp[_timestamp] = ""; rep.timestampIndex[_timestamp] = 0; 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" ); _staker.startDate = block.timestamp; _staker.lockedBalance += _amount; _staker.stakedBalance -= _amount; totalStakeAmount -= _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 uint256 amount of token slashed and sent to recipient address */ function slashReporter(address _reporter, address _recipient) external returns (uint256) { require(msg.sender == governance, "only governance can slash reporter"); StakeInfo storage _staker = stakerDetails[_reporter]; require( _staker.stakedBalance + _staker.lockedBalance > 0, "zero staker balance" ); uint256 _slashAmount; if (_staker.lockedBalance >= stakeAmount) { _slashAmount = stakeAmount; _staker.lockedBalance -= stakeAmount; } else if ( _staker.lockedBalance + _staker.stakedBalance >= stakeAmount ) { _slashAmount = stakeAmount; _staker.stakedBalance -= stakeAmount - _staker.lockedBalance; totalStakeAmount -= stakeAmount - _staker.lockedBalance; _staker.lockedBalance = 0; } else { _slashAmount = _staker.stakedBalance + _staker.lockedBalance; totalStakeAmount -= _staker.stakedBalance; _staker.stakedBalance = 0; _staker.lockedBalance = 0; } token.transfer(_recipient, _slashAmount); emit ReporterSlashed(_reporter, _recipient, _slashAmount); return (_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 memory _queryData ) external { Report storage rep = reports[_queryId]; require( _nonce == rep.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) || uint256(_queryId) <= 100, "id must be hash of bytes data" ); _staker.reporterLastTimestamp = block.timestamp; // Checks for no double reporting of timestamps require( rep.reporterByTimestamp[block.timestamp] == address(0), "timestamp already reported for" ); // Update number of timestamps, value for given timestamp, and reporter for timestamp rep.timestampIndex[block.timestamp] = rep.timestamps.length; rep.timestamps.push(block.timestamp); rep.timestampToBlockNum[block.timestamp] = block.number; rep.valueByTimestamp[block.timestamp] = _value; rep.reporterByTimestamp[block.timestamp] = msg.sender; // Update last oracle value and number of values submitted by a reporter timeOfLastNewValue = block.timestamp; _staker.reportsSubmitted++; _staker.reportsSubmittedByQueryId[_queryId]++; emit NewReport( _queryId, block.timestamp, _value, _nonce, _queryData, msg.sender ); } /** * @dev Withdraws a reporter's stake */ function withdrawStake() external { StakeInfo storage _s = stakerDetails[msg.sender]; // Ensure reporter is locked and that enough time has passed require(block.timestamp - _s.startDate >= 7 days, "7 days didn't pass"); require(_s.lockedBalance > 0, "reporter not locked for withdrawal"); token.transfer(msg.sender, _s.lockedBalance); _s.lockedBalance = 0; emit StakeWithdrawn(msg.sender); } //Getters /** * @dev Returns the block number at a given timestamp * @param _queryId is ID of the specific data feed * @param _timestamp is the timestamp to find the corresponding block number for * @return uint256 block number of the timestamp for the given data ID */ function getBlockNumberByTimestamp(bytes32 _queryId, uint256 _timestamp) external view returns (uint256) { return reports[_queryId].timestampToBlockNum[_timestamp]; } /** * @dev Returns the current value of a data feed given a specific ID * @param _queryId is the ID of the specific data feed * @return bytes memory of the current value of data */ function getCurrentValue(bytes32 _queryId) external view returns (bytes memory) { return reports[_queryId].valueByTimestamp[ reports[_queryId].timestamps[ reports[_queryId].timestamps.length - 1 ] ]; } /** * @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) external view returns (uint256) { return reports[_queryId].timestamps.length; } /** * @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) { bool _wasRemoved = reports[_queryId].timestampIndex[_timestamp] == 0 && keccak256(reports[_queryId].valueByTimestamp[_timestamp]) == keccak256(bytes("")) && reports[_queryId].reporterByTimestamp[_timestamp] != address(0); return (reports[_queryId].reporterByTimestamp[_timestamp], _wasRemoved); } /** * @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 of the number of values submitted by the given reporter */ function getReportsSubmittedByAddress(address _reporter) external view returns (uint256) { return stakerDetails[_reporter].reportsSubmitted; } /** * @dev Returns the number of values submitted to a specific queryId by a specific reporter address * @param _reporter is the address of a reporter * @param _queryId is the ID of the specific data feed * @return uint256 of the number of values submitted by the given reporter to the given queryId */ function getReportsSubmittedByAddressAndQueryId( address _reporter, bytes32 _queryId ) external view returns (uint256) { return stakerDetails[_reporter].reportsSubmittedByQueryId[_queryId]; } /** * @dev Returns amount required to report oracle values * @return uint256 stake amount */ function getStakeAmount() external view returns (uint256) { return stakeAmount; } /** * @dev Allows users to retrieve all information about a staker * @param _staker address of staker inquiring about * @return uint startDate of staking * @return uint current amount staked * @return uint current amount locked for withdrawal * @return uint reporter's last reported timestamp * @return uint total number of reports submitted by reporter */ function getStakerInfo(address _staker) external view returns ( uint256, uint256, uint256, uint256, uint256 ) { return ( stakerDetails[_staker].startDate, stakerDetails[_staker].stakedBalance, stakerDetails[_staker].lockedBalance, stakerDetails[_staker].reporterLastTimestamp, stakerDetails[_staker].reportsSubmitted ); } /** * @dev Returns the timestamp for the last value of any ID from the oracle * @return uint256 of 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) external view returns (uint256) { return reports[_queryId].timestamps[_index]; } /** * @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 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) external view returns (bytes memory) { return reports[_queryId].valueByTimestamp[_timestamp]; } }
// 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); }
{ "optimizer": { "enabled": true, "runs": 300 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_tellor","type":"address"},{"internalType":"uint256","name":"_disputeFee","type":"uint256"},{"internalType":"address","name":"_teamMultisig","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_disputeId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_queryId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_timestamp","type":"uint256"},{"indexed":false,"internalType":"address","name":"_reporter","type":"address"}],"name":"NewDispute","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_contract","type":"address"},{"indexed":false,"internalType":"bytes4","name":"_function","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"_disputeId","type":"uint256"}],"name":"NewVote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_disputeId","type":"uint256"},{"indexed":false,"internalType":"enum Governance.VoteResult","name":"_result","type":"uint8"}],"name":"VoteExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_disputeId","type":"uint256"},{"indexed":false,"internalType":"enum Governance.VoteResult","name":"_result","type":"uint8"},{"indexed":false,"internalType":"address","name":"_initiator","type":"address"},{"indexed":false,"internalType":"address","name":"_reporter","type":"address"}],"name":"VoteTallied","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_disputeId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_supports","type":"bool"},{"indexed":false,"internalType":"address","name":"_voter","type":"address"},{"indexed":false,"internalType":"bool","name":"_invalidQuery","type":"bool"}],"name":"Voted","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_queryId","type":"bytes32"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"beginDispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeId","type":"uint256"},{"internalType":"address","name":"_voter","type":"address"}],"name":"didVote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputeFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeId","type":"uint256"}],"name":"executeVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeId","type":"uint256"}],"name":"getDisputeInfo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_queryId","type":"bytes32"}],"name":"getOpenDisputesOnId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVoteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeId","type":"uint256"}],"name":"getVoteInfo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256[17]","name":"","type":"uint256[17]"},{"internalType":"bool[2]","name":"","type":"bool[2]"},{"internalType":"enum Governance.VoteResult","name":"","type":"uint8"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"address[2]","name":"","type":"address[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"getVoteRounds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"isUser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernanceAddress","type":"address"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"proposeChangeGovernanceAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newReportingLock","type":"uint256"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"proposeChangeReportingLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newStakeAmount","type":"uint256"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"proposeChangeStakeAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_isUser","type":"bool"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"proposeUpdateUserList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeId","type":"uint256"}],"name":"tallyVotes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"teamMultisig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tellor","outputs":[{"internalType":"contract TellorFlex","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_isUser","type":"bool"}],"name":"updateUserList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_disputeId","type":"uint256"},{"internalType":"bool","name":"_supports","type":"bool"},{"internalType":"bool","name":"_invalidQuery","type":"bool"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"voteCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620034e3380380620034e38339810160408190526200003491620000fc565b600080546001600160a01b0319166001600160a01b03851690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156200008957600080fd5b505afa1580156200009e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000c4919062000143565b600180546001600160a01b03199081166001600160a01b03938416179091556004939093556002805490931691161790555062000182565b60008060006060848603121562000111578283fd5b83516200011e8162000169565b602085015160408601519194509250620001388162000169565b809150509250925092565b60006020828403121562000155578081fd5b8151620001628162000169565b9392505050565b6001600160a01b03811681146200017f57600080fd5b50565b61335180620001926000396000f3fe608060405234801561001057600080fd5b50600436106101475760003560e01c8063a3cb1604116100c8578063dbc0c0851161008c578063ec36902511610066578063ec36902514610340578063f98a4eca14610353578063fc0c546a1461036657610147565b8063dbc0c08514610312578063df133bca14610325578063e7b3387c1461033857610147565b8063a3cb16041461029d578063a7c438bc146102b0578063b9ce896b146102ed578063c6384071146102f6578063d3b5e361146102ff57610147565b80634209fff11161010f5780634209fff1146101f25780634ac6eb7c1461022e5780634d318b0e146102415780636169c308146102545780638d8242731461027757610147565b80630e1596ef1461014c5780631959ad5b1461017f5780631f379acc146101aa57806321440a77146101bf578063248638e5146101d2575b600080fd5b61016c61015a366004612b67565b60009081526006602052604090205490565b6040519081526020015b60405180910390f35b600054610192906001600160a01b031681565b6040516001600160a01b039091168152602001610176565b6101bd6101b8366004612b7f565b610379565b005b6101bd6101cd366004612b7f565b610c3e565b6101e56101e0366004612b67565b610cc8565b6040516101769190612ee9565b61021e610200366004612a69565b6001600160a01b031660009081526007602052604090205460ff1690565b6040519015158152602001610176565b6101bd61023c366004612b20565b610d2a565b6101bd61024f366004612b67565b610db0565b610267610262366004612b67565b61130c565b6040516101769493929190612fdd565b61028a610285366004612b67565b6113e0565b6040516101769796959493929190612f2d565b6101bd6102ab366004612aa8565b6115e2565b61021e6102be366004612c61565b60008281526008602090815260408083206001600160a01b038516845260160190915290205460ff1692915050565b61016c60045481565b61016c60035481565b6101bd61030d366004612ae0565b611668565b600254610192906001600160a01b031681565b6101bd610333366004612c85565b6116ef565b60035461016c565b6101bd61034e366004612b7f565b611d1e565b6101bd610361366004612b67565b611d93565b600154610192906001600160a01b031681565b600054604051630935408d60e41b815260048101849052602481018390526001600160a01b039091169063935408d09060440160206040518083038186803b1580156103c457600080fd5b505afa1580156103d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fc9190612c49565b6104585760405162461bcd60e51b815260206004820152602260248201527f6e6f2076616c75652065786973747320617420676976656e2074696d6573746160448201526106d760f41b60648201526084015b60405180910390fd5b6040805160208082018590528183018490528251808303840181526060909201909252805191012060038054906000610490836132ae565b90915550506003546000828152600960209081526040822080546001818101835582855292842001849055918490529054111561055757600082815260096020526040812080546104e390600290613219565b8154811061050157634e487b7160e01b600052603260045260246000fd5b90600052602060002001549050620151806008600083815260200190815260200160002060050154426105349190613219565b106105515760405162461bcd60e51b815260040161044f90613016565b5061066d565b60008054906101000a90046001600160a01b03166001600160a01b0316633321fc416040518163ffffffff1660e01b815260040160206040518083038186803b1580156105a357600080fd5b505afa1580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db9190612c49565b6105e58442613219565b1061064d5760405162461bcd60e51b815260206004820152603260248201527f44697370757465206d75737420626520737461727465642077697468696e207260448201527165706f7274696e67206c6f636b2074696d6560701b606482015260840161044f565b6000848152600660205260408120805491610667836132ae565b91905055505b60008181526008602090815260408083206005909252808320878155600181018790559254905163c5958af960e01b815260048101889052602481018790529192916001600160a01b039091169063c5958af99060440160006040518083038186803b1580156106dc57600080fd5b505afa1580156106f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107189190810190612ba0565b805161072e916002840191602090910190612993565b5060005460405163703e2a4360e11b815260048101889052602481018790526001600160a01b039091169063e07c54869060440160206040518083038186803b15801561077a57600080fd5b505afa15801561078e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b29190612a8c565b600380830180546001600160a01b03939093166001600160a01b0319938416179055858455601584018054909216331790915543908301554260028301556000848152600960205260408120805460018581019190915560128501805462ff00001916620100001790559054141561085e5760008781526006602052604090205461083f90600190613219565b61084a90600261312c565b60045461085791906131fa565b9050610894565b60008581526009602052604090205461087990600190613219565b61088490600261312c565b60045461089191906131fa565b90505b60008054906101000a90046001600160a01b03166001600160a01b03166360c7dc476040518163ffffffff1660e01b815260040160206040518083038186803b1580156108e057600080fd5b505afa1580156108f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109189190612c49565b8111156109a65760008054906101000a90046001600160a01b03166001600160a01b03166360c7dc476040518163ffffffff1660e01b815260040160206040518083038186803b15801561096b57600080fd5b505afa15801561097f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a39190612c49565b90505b60048381018290556001546040516323b872dd60e01b81523392810192909252306024830152604482018390526001600160a01b0316906323b872dd90606401602060405180830381600087803b158015610a0057600080fd5b505af1158015610a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a389190612b4b565b610a775760405162461bcd60e51b815260206004820152601060248201526f119959481b5d5cdd081899481c185a5960821b604482015260640161044f565b60008581526009602052604090205460011415610b8757600054600383015460405163137f0a8d60e21b81526001600160a01b039182166004820152306024820152911690634dfc2a3490604401602060405180830381600087803b158015610adf57600080fd5b505af1158015610af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b179190612c49565b6004838101919091556000546040516316d7b73f60e21b8152918201899052602482018890526001600160a01b031690635b5edcfc90604401600060405180830381600087803b158015610b6a57600080fd5b505af1158015610b7e573d6000803e3d6000fd5b50505050610bde565b6000858152600960205260408120805460059291908290610bb857634e487b7160e01b600052603260045260246000fd5b906000526020600020015481526020019081526020016000206004015482600401819055505b600382015460408051868152602081018a90529081018890526001600160a01b0390911660608201527f12b7317353cd7caa8eae8057464e3de356c1429d814fb3421797eccb19043044906080015b60405180910390a150505050505050565b600054604080518082018252601a81527f6368616e67655374616b65416d6f756e742875696e74323536290000000000006020918201528151908101859052610cc4926001600160a01b0316917fca79b5a978ea700f37e874524ca56caf88471abdb2cff892cab3e91ff005e0a191015b6040516020818303038152906040528461269c565b5050565b600081815260096020908152604091829020805483518184028101840190945280845260609392830182828015610d1e57602002820191906000526020600020905b815481526020019060010190808311610d0a575b50505050509050919050565b60005460408051808201825260208082527f6368616e6765476f7665726e616e636541646472657373286164647265737329918101919091529051610cc4926001600160a01b0316917f0636769e56486090c573831c9de80fac4458ca89aa37a2afff688bfcbc1ad71191610caf918791016001600160a01b0391909116815260200190565b6000818152600860205260409020601281015460ff1615610e1d5760405162461bcd60e51b815260206004820152602160248201527f446973707574652068617320616c7265616479206265656e20657865637574656044820152601960fa1b606482015260840161044f565b600581015415610e6f5760405162461bcd60e51b815260206004820152601d60248201527f566f74652068617320616c7265616479206265656e2074616c6c696564000000604482015260640161044f565b600354821115610eb75760405162461bcd60e51b8152602060048201526013602482015272159bdd1948191bd95cc81b9bdd08195e1a5cdd606a1b604482015260640161044f565b60128101546202a3009062010000900460ff16610ed4575062093a805b80826002015442610ee59190613219565b11610f325760405162461bcd60e51b815260206004820152601f60248201527f54696d6520666f7220766f74696e6720686173206e6f7420656c617073656400604482015260640161044f565b60088201546007830154600684015460009291610f4e916130ae565b610f5891906130ae565b600e840154600d850154600c860154929350600092610f7791906130ae565b610f8191906130ae565b60118501546010860154600f870154929350600092610fa091906130ae565b610faa91906130ae565b600b860154600a8701546009880154929350600092610fc991906130ae565b610fd391906130ae565b90508082610fe185876131fa565b610feb91906131fa565b610ff591906131fa565b611045578361100c5783611008816132ae565b9450505b8261101f578261101b816132ae565b9350505b81611032578161102e816132ae565b9250505b806110455780611041816132ae565b9150505b6009860154600090839061105b906127106131fa565b61106591906130c6565b600f8801548490611078906127106131fa565b61108291906130c6565b600c8901548690611095906127106131fa565b61109f91906130c6565b60068a015488906110b2906127106131fa565b6110bc91906130c6565b6110c691906130ae565b6110d091906130ae565b6110da91906130ae565b905060008388600901600101546127106110f491906131fa565b6110fe91906130c6565b60108901548590611111906127106131fa565b61111b91906130c6565b600d8a0154879061112e906127106131fa565b61113891906130c6565b60078b0154899061114b906127106131fa565b61115591906130c6565b61115f91906130ae565b61116991906130ae565b61117391906130ae565b9050600084896009016002015461271061118d91906131fa565b61119791906130c6565b60118a015486906111aa906127106131fa565b6111b491906130c6565b600e8b015488906111c7906127106131fa565b6111d191906130c6565b60088c01548a906111e4906127106131fa565b6111ee91906130c6565b6111f891906130ae565b61120291906130ae565b61120c91906130ae565b905082811015801561121e5750818110155b80156112345750601289015462010000900460ff165b15611257576012890180546002919061ff001916610100835b0217905550611285565b81831115611277576012890180546001919061ff0019166101008361124d565b60128901805461ff00191690555b4260058a81019190915560128a015460158b015460008d81526020939093526040928390206003015492517fa2d4e500801849d40ad00f0f12ba92a5263f83ec68946e647be95cfbe581c7b6936112f8938f9361010090910460ff16926001600160a01b03918216929190911690613078565b60405180910390a150505050505050505050565b6000818152600560205260408120805460018201546003830154600284018054869560609587959194909391926001600160a01b0390911690829061135090613273565b80601f016020809104026020016040519081016040528092919081815260200182805461137c90613273565b80156113c95780601f1061139e576101008083540402835291602001916113c9565b820191906000526020600020905b8154815290600101906020018083116113ac57829003601f168201915b505050505091509450945094509450509193509193565b60006113ea612a17565b6113f2612a36565b600060606000611400612a36565b6000888152600860208181526040928390208054845161022081018652600183015481526002830154818501526003830154818701526004830154606082015260058301546080820152600683015460a0820152600783015460c08201529382015460e080860191909152600983015461010080870191909152600a840154610120870152600b840154610140870152600c840154610160870152600d840154610180870152600e8401546101a0870152600f8401546101c087015260108401546101e0870152601184015461020087015286518088018852601285015460ff80821615158352620100008204811615158389015260148701548a51808c01909b526001600160a01b03640100000000820481168c52601589015416988b0198909852601387018054979a969998939794909204169490939190911b91839061154890613273565b80601f016020809104026020016040519081016040528092919081815260200182805461157490613273565b80156115c15780601f10611596576101008083540402835291602001916115c1565b820191906000526020600020905b8154815290600101906020018083116115a457829003601f168201915b50505050509250975097509750975097509750975050919395979092949650565b33301461163d5760405162461bcd60e51b8152602060048201526024808201527f4f6e6c7920676f7665726e616e63652063616e207570646174652075736572206044820152631b1a5cdd60e21b606482015260840161044f565b6001600160a01b03919091166000908152600760205260409020805460ff1916911515919091179055565b604080518082018252601c81527f757064617465557365724c69737428616464726573732c626f6f6c290000000060209182015290516116ea9130917fa3cb1604d428d5b2db415cab07e750952a0559e3ea14fc2ad01393fcccac6aee91610caf9188918891016001600160a01b039290921682521515602082015260400190565b505050565b6003548311156117375760405162461bcd60e51b8152602060048201526013602482015272159bdd1948191bd95cc81b9bdd08195e1a5cdd606a1b604482015260640161044f565b60008381526008602052604090206005810154156117975760405162461bcd60e51b815260206004820152601d60248201527f566f74652068617320616c7265616479206265656e2074616c6c696564000000604482015260640161044f565b33600090815260168201602052604090205460ff16156117f95760405162461bcd60e51b815260206004820152601860248201527f53656e6465722068617320616c726561647920766f7465640000000000000000604482015260640161044f565b336000818152601683016020526040808220805460ff191660019081179091555490516370a0823160e01b8152600481019390935290916001600160a01b03909116906370a082319060240160206040518083038186803b15801561185d57600080fd5b505afa158015611871573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118959190612c49565b60008054604051630733bdef60e41b8152336004820152929350909182916001600160a01b03169063733bdef09060240160a06040518083038186803b1580156118de57600080fd5b505afa1580156118f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119169190612cc6565b50509250925050808261192991906130ae565b61193390846130ae565b601285015490935062010000900460ff16801561194d5750845b15611a81578215611975578284600601600201600082825461196f91906130ae565b90915550505b600054604051631c3c149f60e11b81523360048201526001600160a01b0390911690633878293e9060240160206040518083038186803b1580156119b857600080fd5b505afa1580156119cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f09190612c49565b92508215611a15578284600c016002016000828254611a0f91906130ae565b90915550505b3360009081526007602052604090205460ff1615611a4b576001846009016002016000828254611a4591906130ae565b90915550505b6002546001600160a01b0316331415611a7c57600184600f016002016000828254611a7691906130ae565b90915550505b611cd5565b8515611bab578215611aaa5782846006016000016000828254611aa491906130ae565b90915550505b600054604051631c3c149f60e11b81523360048201526001600160a01b0390911690633878293e9060240160206040518083038186803b158015611aed57600080fd5b505afa158015611b01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b259190612c49565b92508215611b4a578284600c016000016000828254611b4491906130ae565b90915550505b3360009081526007602052604090205460ff1615611b80576001846009016000016000828254611b7a91906130ae565b90915550505b6002546001600160a01b0316331415611a7c57600184600f016000016000828254611a7691906130ae565b8215611bce5782846006016001016000828254611bc891906130ae565b90915550505b600054604051631c3c149f60e11b81523360048201526001600160a01b0390911690633878293e9060240160206040518083038186803b158015611c1157600080fd5b505afa158015611c25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c499190612c49565b92508215611c6e578284600c016001016000828254611c6891906130ae565b90915550505b3360009081526007602052604090205460ff1615611ca4576001846009016001016000828254611c9e91906130ae565b90915550505b6002546001600160a01b0316331415611cd557600184600f016001016000828254611ccf91906130ae565b90915550505b604080518881528715156020820152339181019190915285151560608201527fbe6f1c58cc15c8e86d6f0ef23c5a30eb33319af3b57f6b7d9b56ccfa87696b8490608001610c2d565b600054604080518082018252601c81527f6368616e67655265706f7274696e674c6f636b2875696e7432353629000000006020918201528151908101859052610cc4926001600160a01b0316917f5d183cfa1084f72f49f0f81fe5d34bf9533a659ae85960ce554cbcf02302ca309101610caf565b6000818152600860205260409020600354821115611df35760405162461bcd60e51b815260206004820152601560248201527f566f7465204944206d7573742062652076616c69640000000000000000000000604482015260640161044f565b601281015460ff1615611e485760405162461bcd60e51b815260206004820152601660248201527f566f746520686173206265656e20657865637574656400000000000000000000604482015260640161044f565b6000816005015411611e9c5760405162461bcd60e51b815260206004820152601460248201527f566f7465206d7573742062652074616c6c696564000000000000000000000000604482015260640161044f565b6001810154815460009081526009602052604090205414611eff5760405162461bcd60e51b815260206004820152601660248201527f4d757374206265207468652066696e616c20766f746500000000000000000000604482015260640161044f565b6001810154611f1190620151806131fa565b6005820154611f209042613219565b1015611f825760405162461bcd60e51b815260206004820152602b60248201527f566f7465206e6565647320746f2062652074616c6c69656420616e642074696d60448201526a65206d757374207061737360a81b606482015260840161044f565b60128101805460ff19166001179081905562010000900460ff166120b95760016012820154610100900460ff166002811115611fce57634e487b7160e01b600052602160045260246000fd5b141561206e5760148101546040516001600160a01b0364010000000083041691600091606091849161200b9160e01b906013880190602001612dd7565b60408051601f198184030181529082905261202591612e8b565b6000604051808303816000865af19150503d8060008114612062576040519150601f19603f3d011682016040523d82523d6000602084013e612067565b606091505b5050505050505b60128101546040517f40d231bf91823121de9e1c012d95f835ea5684dc1d93360d9510a30543345da4916120ac918591610100900460ff1690613064565b60405180910390a1610cc4565b60008281526005602090815260408083206001850154855485526009909352922054141561210357805460009081526006602052604081208054916120fd8361325c565b91905055505b60008060016012850154610100900460ff16600281111561213457634e487b7160e01b600052602160045260246000fd5b14156122f257835460009081526009602052604090205491505b81156122ed578354600090815260096020526040902061216f600184613219565b8154811061218d57634e487b7160e01b600052603260045260246000fd5b90600052602060002001549050600860008281526020019081526020016000209350816001141561224a57600154601585015460048581015460405163a9059cbb60e01b81526001600160a01b0393841692810192909252602482015291169063a9059cbb90604401602060405180830381600087803b15801561221057600080fd5b505af1158015612224573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122489190612b4b565b505b600154601585015460048087015460405163a9059cbb60e01b81526001600160a01b0393841692810192909252602482015291169063a9059cbb90604401602060405180830381600087803b1580156122a257600080fd5b505af11580156122b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122da9190612b4b565b50816122e58161325c565b92505061214e565b612641565b60026012850154610100900460ff16600281111561232057634e487b7160e01b600052602160045260246000fd5b14156124d657835460009081526009602052604090205491505b8115612440578354600090815260096020526040902061235b600184613219565b8154811061237957634e487b7160e01b600052603260045260246000fd5b60009182526020808320919091015480835260089091526040918290206001546015820154600480840154955163a9059cbb60e01b81526001600160a01b03928316918101919091526024810195909552919750919350169063a9059cbb90604401602060405180830381600087803b1580156123f557600080fd5b505af1158015612409573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242d9190612b4b565b50816124388161325c565b92505061233a565b600154600384015460048086015460405163a9059cbb60e01b81526001600160a01b0393841692810192909252602482015291169063a9059cbb90604401602060405180830381600087803b15801561249857600080fd5b505af11580156124ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d09190612b4b565b50612641565b60006012850154610100900460ff16600281111561250457634e487b7160e01b600052602160045260246000fd5b141561264157835460009081526009602052604081205492505b82156125a3578454600090815260096020526040902061253f600185613219565b8154811061255d57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154915060086000838152602001908152602001600020945084600401548161258f91906130ae565b90508261259b8161325c565b93505061251e565b60048401546125b290826130ae565b600154600386015460405163a9059cbb60e01b81526001600160a01b03918216600482015260248101849052929350169063a9059cbb90604401602060405180830381600087803b15801561260657600080fd5b505af115801561261a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061263e9190612b4b565b50505b600085815260086020526040908190206012015490517f40d231bf91823121de9e1c012d95f835ea5684dc1d93360d9510a30543345da49161268d918891610100900460ff1690613064565b60405180910390a15050505050565b600380549060006126ac836132ae565b90915550506003546000818152600860205260409020826126cb574292505b6000868686866040516020016126e49493929190612d85565b60408051601f1981840301815291815281516020928301206000818152600984529182208054600181810183558285529484200187905591819052905490925011156127b6576000818152600960205260408120805461274690600290613219565b8154811061276457634e487b7160e01b600052603260045260246000fd5b90600052602060002001549050620151806008600083815260200190815260200160002060050154426127979190613219565b106127b45760405162461bcd60e51b815260040161044f90613016565b505b6000818152600960205260408120546127d190600190613219565b6127dc90600261312c565b6127ee90678ac7230489e800006131fa565b6001546040516323b872dd60e01b8152336004820152306024820152604481018390529192506001600160a01b0316906323b872dd90606401602060405180830381600087803b15801561284157600080fd5b505af1158015612855573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128799190612b4b565b6128b85760405162461bcd60e51b815260206004820152601060248201526f119959481b5d5cdd081899481c185a5960821b604482015260640161044f565b81835560008281526009602090815260409091205460018501554260028501554360038501556004840182905586516128f991601386019190890190612993565b506014830180546001600160a01b038a166401000000000277ffffffffffffffffffffffffffffffffffffffffffffffff1990911660e08a901c171790556015830180546001600160a01b031916331790556040517f03cd1db94c84fbf802bb289f9fec190fc43fcb105eee5554433e8d642ceab11890612981908a908a908a908990612ea7565b60405180910390a15050505050505050565b82805461299f90613273565b90600052602060002090601f0160209004810192826129c15760008555612a07565b82601f106129da57805160ff1916838001178555612a07565b82800160010185558215612a07579182015b82811115612a075782518255916020019190600101906129ec565b50612a13929150612a54565b5090565b6040518061022001604052806011906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b5b80821115612a135760008155600101612a55565b600060208284031215612a7a578081fd5b8135612a85816132f5565b9392505050565b600060208284031215612a9d578081fd5b8151612a85816132f5565b60008060408385031215612aba578081fd5b8235612ac5816132f5565b91506020830135612ad58161330d565b809150509250929050565b600080600060608486031215612af4578081fd5b8335612aff816132f5565b92506020840135612b0f8161330d565b929592945050506040919091013590565b60008060408385031215612b32578182fd5b8235612b3d816132f5565b946020939093013593505050565b600060208284031215612b5c578081fd5b8151612a858161330d565b600060208284031215612b78578081fd5b5035919050565b60008060408385031215612b91578182fd5b50508035926020909101359150565b600060208284031215612bb1578081fd5b815167ffffffffffffffff80821115612bc8578283fd5b818401915084601f830112612bdb578283fd5b815181811115612bed57612bed6132df565b604051601f8201601f19908116603f01168101908382118183101715612c1557612c156132df565b81604052828152876020848701011115612c2d578586fd5b612c3e836020830160208801613230565b979650505050505050565b600060208284031215612c5a578081fd5b5051919050565b60008060408385031215612c73578182fd5b823591506020830135612ad5816132f5565b600080600060608486031215612c99578283fd5b833592506020840135612cab8161330d565b91506040840135612cbb8161330d565b809150509250925092565b600080600080600060a08688031215612cdd578081fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b8060005b6002811015612d315781516001600160a01b0316845260209384019390910190600101612d09565b50505050565b60008151808452612d4f816020860160208601613230565b601f01601f19169290920160200192915050565b60038110612d8157634e487b7160e01b600052602160045260246000fd5b9052565b606085901b6bffffffffffffffffffffffff191681526001600160e01b0319841660148201528251600090612dc1816018850160208801613230565b6018920191820192909252603801949350505050565b6001600160e01b03198316815281546000906004908290600181811c9080831680612e0357607f831692505b6020808410821415612e2257634e487b7160e01b885260228752602488fd5b818015612e365760018114612e4b57612e7b565b60ff1986168a890152848a0188019650612e7b565b60008b815260209020895b86811015612e715781548c82018b0152908501908301612e56565b505087858b010196505b50949a9950505050505050505050565b60008251612e9d818460208701613230565b9190910192915050565b60006001600160a01b038616825263ffffffff60e01b8516602083015260806040830152612ed86080830185612d37565b905082606083015295945050505050565b6020808252825182820181905260009190848201906040850190845b81811015612f2157835183529284019291840191600101612f05565b50909695505050505050565b600061032089835260208084018a845b6011811015612f5a57815183529183019190830190600101612f3d565b505050610240840189845b6002811015612f84578151151583529183019190830190600101612f65565b50505050612f96610280840188612d63565b806102a0840152612fa981840187612d37565b915050612fc36102c08301856001600160e01b0319169052565b612fd16102e0830184612d05565b98975050505050505050565b600085825284602083015260806040830152612ffc6080830185612d37565b90506001600160a01b038316606083015295945050505050565b6020808252602e908201527f4e6577206469737075746520726f756e64206d7573742062652073746172746560408201526d642077697468696e20612064617960901b606082015260800190565b82815260408101612a856020830184612d63565b8481526080810161308c6020830186612d63565b6001600160a01b03808516604084015280841660608401525095945050505050565b600082198211156130c1576130c16132c9565b500190565b6000826130e157634e487b7160e01b81526012600452602481fd5b500490565b80825b60018086116130f85750613123565b81870482111561310a5761310a6132c9565b8086161561311757918102915b9490941c9380026130e9565b94509492505050565b6000612a85600019848460008261314557506001612a85565b8161315257506000612a85565b816001811461316857600281146131725761319f565b6001915050612a85565b60ff841115613183576131836132c9565b6001841b915084821115613199576131996132c9565b50612a85565b5060208310610133831016604e8410600b84101617156131d2575081810a838111156131cd576131cd6132c9565b612a85565b6131df84848460016130e6565b8086048211156131f1576131f16132c9565b02949350505050565b6000816000190483118215151615613214576132146132c9565b500290565b60008282101561322b5761322b6132c9565b500390565b60005b8381101561324b578181015183820152602001613233565b83811115612d315750506000910152565b60008161326b5761326b6132c9565b506000190190565b600181811c9082168061328757607f821691505b602082108114156132a857634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156132c2576132c26132c9565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461330a57600080fd5b50565b801515811461330a57600080fdfea2646970667358221220536e4cff473bb31c6129dbfb81b7ca596767912786dbac6ba78dda5a551456c364736f6c63430008030033000000000000000000000000bb97c038c338c3dcaf06d5be3b4a3e0b24835f9c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000007671ea70ce097bc82464b4ab78f79d279356b6cd
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bb97c038c338c3dcaf06d5be3b4a3e0b24835f9c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000007671ea70ce097bc82464b4ab78f79d279356b6cd
-----Decoded View---------------
Arg [0] : _tellor (address): 0xbb97c038c338c3dcaf06d5be3b4a3e0b24835f9c
Arg [1] : _disputeFee (uint256): 1000000000000000000
Arg [2] : _teamMultisig (address): 0x7671ea70ce097bc82464b4ab78f79d279356b6cd
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000bb97c038c338c3dcaf06d5be3b4a3e0b24835f9c
Arg [1] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [2] : 0000000000000000000000007671ea70ce097bc82464b4ab78f79d279356b6cd
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.