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 }