evm-granularvoter

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

commit 7c4aa1bf50cf550bfe5219f57357ff97c045ac27
Author: lash <dev@holbrook.no>
Date:   Sat, 12 Nov 2022 11:57:14 +0000

Initial commit

Diffstat:
Asolidity/GranularVoter.sol | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asolidity/Makefile | 10++++++++++
2 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/solidity/GranularVoter.sol b/solidity/GranularVoter.sol @@ -0,0 +1,82 @@ +pragma solidity >0.6.11; + +// Author: Louis Holbrook <dev@holbrook.no> 0826EDA1702D1E87C6E2875121D2E7BB88C2A746 +// SPDX-License-Identifier: GPL-3.0-or-later +// File-version: 1 +// Description: Granular voting contract to be used as backend for calculating (and sealing) ratios of rewards for other contracts + +contract GranularVoter { + + uint256 public periodLength; + address public owner; + uint16 constant mintValue = 1000; + + mapping (address => mapping(address => uint16)) public voteCount; + 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 + mapping (address => uint256) public voteHave; + mapping (address => mapping(address => uint256)) public lastPeriod; + mapping (address => bool) lock; + + constructor(uint256 _periodLength) { + owner = msg.sender; + periodLength = _periodLength; + } + + function register(address _voter) public returns (bool) { + require(msg.sender == owner); + + voteCount[_voter][_voter] = mintValue; + + return true; + } + + // same interface as erc20/erc721 + function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { + require (!lock[_from]); + require (_value > 0); + if (voteCount[msg.sender][_from] > 0) { + require (lastPeriod[msg.sender][_from] >= period()); + } + require (voteCount[msg.sender][_from] > _value); + + // handle the vote decrement + voteCount[msg.sender][_from] -= uint16(_value); + if (voteCount[msg.sender][_from] == 0) { + voteHave[_from] -= 1; + } + if (_value > votes[_from]) { + votes[_from] = 0; + } else { + votes[_from] -= _value; + } + + // handle the vote increment + voteCount[msg.sender][_to] += uint16(_value); + votes[_to] += _value; + voteHave[_to] += 1; + + return true; + } + + // lock is reentrancy guard across querying the calculated value of vote ratio + // should there be two locks? one for entering, then one for execution of the call code? + function begin(address _beneficiary, uint256 _value) public returns(uint256) { + lock[_beneficiary] = true; + return (_value * votes[_beneficiary]) / mintValue; + } + + // lock released here, unless it is called period cannot advance + function finish(address _beneficiary) public { + require(lock[_beneficiary]); + lastPeriod[msg.sender][_beneficiary] += 1; + lock[_beneficiary] = false; + } + + // if something went wrong with start, can cancel and revert the effects here. + function abort(address _beneficiary) public { + } + + function period() public view returns (uint256) { + return block.number / periodLength; + } +} diff --git a/solidity/Makefile b/solidity/Makefile @@ -0,0 +1,10 @@ +SOLC = /usr/bin/solc + +all: + $(SOLC) --bin GranularVoter.sol --evm-version byzantium | awk 'NR>3' > GranularVoter.bin + truncate -s -1 GranularVoter.bin + $(SOLC) --abi GranularVoter.sol --evm-version byzantium | awk 'NR>3' > GranularVoter.json + +install: all + cp -v *{json,bin} ../python/eth_granular_voter/data/ +