github.com/diadata-org/diadata@v1.4.593/contracts/Dispute.sol (about)

     1  pragma solidity 0.4.25;
     2  
     3  import "./DIAToken.sol";
     4  import "zos-lib/contracts/Initializable.sol";
     5  import "openzeppelin-eth/contracts/math/SafeMath.sol";
     6  
     7  contract Dispute is Initializable {
     8  	using SafeMath for uint;
     9  	// DIA token
    10  	DIAToken private dia_;
    11  	// Event to emit when a dispute is open
    12  	event DisputeOpen(uint256 _id, uint _deadline);
    13  	// Event to emit when a dispute is finalized
    14  	event DisputeClosed(uint256 _id, bool _result);
    15  	// How many blocks should we wait before the dispute can be closed
    16  	uint private DISPUTE_LENGTH;
    17  	// How many token a user should stake on each vote
    18  	uint private VOTE_COST;
    19  	// Disputes
    20  	mapping (uint256=>Disputes) private disputes_;
    21  	// Rewards that each voter can claim
    22  	mapping (address=>uint256) public rewards_;
    23  
    24  	struct Disputes{
    25  		// Block number to finalize dispute
    26  		uint deadline;
    27  		// Array of voters
    28  		Voter[] voters;
    29  		// Voters index in the voters array
    30  		mapping(address=>uint) votersIndex;
    31  	}
    32  	// Voters
    33  	struct Voter {
    34  		// store voter address. Required for payout
    35  		address id;
    36  		// Vote. true:keep, false:drop
    37  		bool vote;
    38  	}
    39  
    40  	/**
    41  	* @dev Acts as constructor for upgradeable contracts
    42  	* @param _dia Address of DIA token contract.
    43  	*/
    44  	function initialize(DIAToken _dia) public initializer() {
    45  		// ~2 weeks. weeks x days x hours x minute x seconds
    46  		DISPUTE_LENGTH = 2*7*24*60*60;
    47  		VOTE_COST = 10;
    48  		dia_ = _dia;
    49  	}
    50  
    51  	/**
    52  	* @dev Cast vote.
    53  	* @param _id Data source identifier.
    54  	* @param _vote true for drop and false to keep.
    55  	*/
    56  	function vote(uint256 _id, bool _vote) public{
    57  		// check only new voters
    58  		require (disputes_[_id].votersIndex[msg.sender] == 0, "Address already voted");
    59  		require (disputes_[_id].deadline > 0, "Dispute not available");
    60  		dia_.transferFrom(msg.sender, this, VOTE_COST);
    61  		disputes_[_id].voters.push(Voter(msg.sender, _vote));
    62  		disputes_[_id].votersIndex[msg.sender] = disputes_[_id].voters.length;
    63  	}
    64  
    65  	/**
    66  	* @dev Start a dispute.
    67  	* @param _id data source identifier.
    68  	*/
    69  	function openDispute(uint256 _id) external {
    70  		require(disputes_[_id].deadline == 0, "Dispute already ongoing");
    71  		disputes_[_id].deadline = now+DISPUTE_LENGTH;
    72  		emit DisputeOpen(_id, disputes_[_id].deadline);
    73  		vote(_id, true);
    74  	}
    75  
    76  	/**
    77  	* @dev Once the deadline is reached this function should be called to get decision.
    78  	* @param _id data source id.
    79  	*/
    80  	function triggerDecision(uint256 _id) external{
    81  		// Maybe we can get rid of a require
    82  		require(disputes_[_id].deadline > 0, "Dispute not available");
    83  		require(now > disputes_[_id].deadline, "Dispute deadline not reached");
    84  		// prevent method to be called again before its done
    85  		disputes_[_id].deadline = 0;
    86  		uint256 dropVotes = 0;
    87  		uint256 keepVotes = 0;
    88  		uint totalVoters = disputes_[_id].voters.length;
    89  		for (uint i = 0; i<totalVoters; i++){
    90  			if (disputes_[_id].voters[i].vote)
    91  				dropVotes++;
    92  			else
    93  				keepVotes++;
    94  		}
    95  		bool drop = (dropVotes>keepVotes);
    96  		uint payment;
    97  		// use safe math to compute payment
    98  		if (drop)
    99  			payment = ((totalVoters).mul(VOTE_COST)).div(dropVotes);
   100  		else
   101  			payment = ((totalVoters).mul(VOTE_COST)).div(keepVotes);
   102  		for (i = 0; i < totalVoters; i++){
   103  			if (disputes_[_id].voters[i].vote == drop){
   104  				rewards_[disputes_[_id].voters[i].id] += payment;
   105  			}
   106  			delete disputes_[_id].votersIndex[disputes_[_id].voters[i].id];
   107  		}
   108  		delete disputes_[_id];
   109  		emit DisputeClosed(_id, drop);
   110  	}
   111  
   112  	/**
   113  	* @dev Claim rewards
   114  	*/
   115  	function claimRewards() external {
   116  		require(rewards_[msg.sender] > 0, "No balance to withdraw");
   117  		dia_.transfer(msg.sender, rewards_[msg.sender]);
   118  		rewards_[msg.sender] = 0;
   119  	}
   120  
   121  	/**
   122  	* @dev Check rewards balance for account calling the method
   123  	*/
   124  	function checkRewardsBalance() external view returns (uint256) {
   125  		return rewards_[msg.sender];
   126  	}
   127  
   128  	/**
   129  	* @dev get dispute status.
   130  	* @param _id data source id.
   131  	*/
   132  	function isDisputeOpen(uint256 _id) external view returns (bool) {
   133  		return (disputes_[_id].deadline>0);
   134  	}
   135  
   136  	/**
   137  	* @dev check if address voted already.
   138  	* @param _id data source identifier.
   139  	*/
   140  	function didCastVote(uint256 _id) external view returns (bool){
   141  		return (disputes_[_id].votersIndex[msg.sender]>0);
   142  	}
   143  }