commit 7c4aa1bf50cf550bfe5219f57357ff97c045ac27
Author: lash <dev@holbrook.no>
Date: Sat, 12 Nov 2022 11:57:14 +0000
Initial commit
Diffstat:
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/
+