evm-granularvoter

Granular voting contract for distribution of Community Inclusion Currencies
git clone git://holbrook.no/evm-granularvoter.git
Log | Files | Refs

GranularVoter.sol (2584B)


      1 pragma solidity >0.6.11;
      2 
      3 // Author:	Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746
      4 // SPDX-License-Identifier:	GPL-3.0-or-later
      5 // File-version: 1
      6 // Description: Granular voting contract to be used as backend for calculating (and sealing) ratios of rewards for other contracts
      7 
      8 contract GranularVoter {
      9 
     10 	uint256 public periodLength;
     11 	address public owner;
     12 	uint16 constant mintValue = 1000;
     13 
     14 	mapping (address => mapping(address => uint16))  public voteCount;
     15 	mapping (address => uint256) votes; // hidden because smart contracts may cheat to get the value outside of applyVote, still accessible to custodial machine realm through chain history
     16 	mapping (address => uint256) public voteHave;
     17 	mapping (address => mapping(address => uint256)) public lastPeriod;
     18 	mapping (address => bool) lock;
     19 
     20 	constructor(uint256 _periodLength) {
     21 		owner = msg.sender;
     22 		periodLength = _periodLength;
     23 	}
     24 
     25 	function register(address _voter) public returns (bool) {
     26 		require(msg.sender == owner);
     27 
     28 		voteCount[_voter][_voter] = mintValue;
     29 
     30 		return true;
     31 	}
     32 
     33 	// same interface as erc20/erc721
     34 	function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
     35 		require (!lock[_from]);
     36 		require (_value > 0);
     37 		if (voteCount[msg.sender][_from] > 0) {
     38 			require (lastPeriod[msg.sender][_from] >= period());
     39 		}
     40 		require (voteCount[msg.sender][_from] > _value);
     41 
     42 		// handle the vote decrement
     43 		voteCount[msg.sender][_from] -= uint16(_value);
     44 		if (voteCount[msg.sender][_from] == 0) {
     45 			voteHave[_from] -= 1;
     46 		}
     47 		if (_value > votes[_from]) {
     48 			votes[_from] = 0;
     49 		} else {
     50 			votes[_from] -= _value;
     51 		}
     52 
     53 		// handle the vote increment
     54 		voteCount[msg.sender][_to] += uint16(_value);
     55 		votes[_to] += _value;
     56 		voteHave[_to] += 1;
     57 
     58 		return true;
     59 	}
     60 
     61 	// lock is reentrancy guard across querying the calculated value of vote ratio
     62 	// should there be two locks? one for entering, then one for execution of the call code?
     63 	function begin(address _beneficiary, uint256 _value) public returns(uint256) {
     64 		lock[_beneficiary] = true;
     65 		return (_value * votes[_beneficiary]) / mintValue; 
     66 	}
     67 
     68 	// lock released here, unless it is called period cannot advance
     69 	function finish(address _beneficiary) public {
     70 		require(lock[_beneficiary]);
     71 		lastPeriod[msg.sender][_beneficiary] += 1;
     72 		lock[_beneficiary] = false;
     73 	}
     74 
     75 	// if something went wrong with start, can cancel and revert the effects here.
     76 	function abort(address _beneficiary) public {
     77 	}
     78 
     79 	function period() public view returns (uint256) {
     80 		return block.number / periodLength;
     81 	}
     82 }