Skip to content

Commit

Permalink
Historical voter confidence (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
karonka authored May 1, 2020
1 parent 258fd65 commit 3f5de4a
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 32 deletions.
30 changes: 23 additions & 7 deletions contracts/KingAutomaton.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,22 @@ contract KingAutomaton is KingOfTheHill {
constructor(uint256 _numSlots, uint256 _minDifficultyBits, uint256 _predefinedMask, uint256 _initialDailySupply,
int256 _approvalPct, int256 _contestPct, uint256 _treasuryLimitPct,
uint256 _proposalsInitialPeriod, uint256 _proposalsContestPeriod, uint256 _proposalsMinPeriodLen,
uint256 _timeUnitInSeconds) public {
uint256 _numHistoryPeriods, uint256 _timeUnitInSeconds) public {
require(_approvalPct > _contestPct, "Approval% should be > contest%!");
numSlots = _numSlots;
initMining(_numSlots, _minDifficultyBits, _predefinedMask, _initialDailySupply);
initNames();

require(_approvalPct > _contestPct, "Approval percentage must be bigger than contest percentage!");
proposalsData.approvalPercentage = _approvalPct;
proposalsData.contestPercentage = _contestPct;
proposalsData.treasuryLimitPercentage = _treasuryLimitPct;
proposalsData.ballotBoxIDs = 99; // Ensure special addresses are not already used
proposalsData.numHistoryPeriods = _numHistoryPeriods;
proposalsData.minHistoryPeriod = _timeUnitInSeconds;
proposalsInitialPeriod = _proposalsInitialPeriod * _timeUnitInSeconds;
proposalsContestPeriod = _proposalsContestPeriod * _timeUnitInSeconds;
proposalsMinPeriodLen = _proposalsMinPeriodLen;
timeUnitInSeconds = _timeUnitInSeconds;

initMining(_numSlots, _minDifficultyBits, _predefinedMask, _initialDailySupply);
initNames();
// Check if we're on a testnet (We will not using predefined mask when going live)
if (_predefinedMask != 0) {
// If so, fund the owner for debugging purposes.
Expand Down Expand Up @@ -170,16 +172,27 @@ contract KingAutomaton is KingOfTheHill {
initialPeriod = p.initialPeriod;
contestPeriod = p.contestPeriod;
}

function getProposalData(uint256 _id)
public view returns (uint256 remainingPeriods, uint256 nextPaymentDate,
Proposals.ProposalState state, uint256 initialEndDate, uint256 contestEndDate) {
Proposals.ProposalState state, uint256 initialEndDate, uint256 contestEndDate, uint256[] memory votingHistory,
uint256 historyStartIdx) {
Proposals.Proposal memory p = proposalsData.proposals[_id];

remainingPeriods = p.remainingPeriods;
nextPaymentDate = p.nextPaymentDate;
state = p.state;
initialEndDate = p.initialEndDate;
contestEndDate = p.contestEndDate;

// TODO(Kari): Decide what to do when history is too long - give only first n words starting from current word?
uint256 numWords = (proposalsData.numHistoryPeriods + 31) / 32;
votingHistory = new uint256[](numWords);
Proposals.ProposalVotingHistory storage h = proposalsData.proposals[_id].history;
for(uint256 i = 0; i < numWords; ++i) {
votingHistory[i] = h.words[i];
}
historyStartIdx = h.front;
}

function createBallotBox(uint256 _choices) public returns (uint256) {
Expand Down Expand Up @@ -207,6 +220,8 @@ contract KingAutomaton is KingOfTheHill {
p.initialPeriod = proposalsInitialPeriod;
p.contestPeriod = proposalsContestPeriod;

p.history.front = 1;

transferInternal(treasuryAddress, address(_id), num_periods * budget_per_period);
}

Expand All @@ -228,6 +243,7 @@ contract KingAutomaton is KingOfTheHill {
function castVote(uint256 _id, uint256 _slot, uint8 _choice) public slotOwner(_slot) {
updateProposalState(_id);
proposalsData.castVote(_id, _slot, _choice);
proposalsData.updateProposalHistory(_id);
}

function getVote(uint256 _id, uint256 _slot) public view returns (uint) {
Expand Down Expand Up @@ -327,7 +343,7 @@ contract KingAutomaton is KingOfTheHill {
// Setup predefined mask, useful for testing purposes.
setMask(predefinedMask);
}
rewardPerSlotPerSecond = (1 ether * initialDailySupply) / 1 days / nSlots;
rewardPerSlotPerSecond = (1 ether * initialDailySupply) / timeUnitInSeconds / nSlots;
}

function slotAcquired(uint256 id) internal override {
Expand Down
54 changes: 54 additions & 0 deletions contracts/Proposals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ library Proposals {
mapping (uint256 => uint256) payGas2;
}

struct ProposalVotingHistory {
uint256 lastTime;
uint256 front;
mapping (uint256 => uint256) words;
}

struct Proposal {
address payable contributor;
string title;
Expand All @@ -59,13 +65,17 @@ library Proposals {
uint256 contestEndDate;
uint256 initialPeriod;
uint256 contestPeriod;

ProposalVotingHistory history;
}

struct Data {
int256 approvalPercentage;
int256 contestPercentage;
uint256 treasuryLimitPercentage;
uint256 ballotBoxIDs;
uint256 numHistoryPeriods;
uint256 minHistoryPeriod;

mapping (uint256 => BallotBox) ballotBoxes;
mapping (uint256 => Proposal) proposals;
Expand Down Expand Up @@ -122,6 +132,47 @@ library Proposals {
return (yes - no) * 100 / int256(b.numSlots);
}

function updateProposalHistory(Data storage self, uint256 id) public {
Proposal storage p = self.proposals[id];
if (p.state == ProposalState.Uninitialized) {
return;
}
ProposalVotingHistory storage h = p.history;

// Time passed is less than a period
if (now - h.lastTime < self.minHistoryPeriod) {
return;
}
uint256 periods = self.numHistoryPeriods;
uint256 front = h.front;
uint256 rear = (front + periods - 1) % periods;
uint256 wordIdx = front / 32;
uint256 offset = (front % 32) * 8;
uint256 mask = 255 << offset;
uint256 word = h.words[wordIdx];

uint256 oldVal = (word & mask) >> offset;
uint256 newVal = uint256(calcVoteDifference(self, id) + 100);
if (oldVal == newVal) {
return;
}

if (wordIdx != (rear / 32)) {
wordIdx = rear / 32;
word = h.words[wordIdx];
}

offset = (rear % 32) * 8;
mask = 255 << offset;

word &= (mask ^ UINT256_MAX);
word |= newVal << offset;

h.words[wordIdx] = word;
h.front = rear;
h.lastTime = now;
}

function castVote(Data storage self, uint256 _id, uint256 _slot, uint8 _choice) public validBallotBoxID(self, _id) {
BallotBox storage box = self.ballotBoxes[_id];
uint256 numChoices = box.numChoices;
Expand Down Expand Up @@ -177,6 +228,9 @@ library Proposals {
) public validBallotBoxID(self, _id) returns (bool _return_to_treasury) {
Proposal storage p = self.proposals[_id];
ProposalState p_state = p.state;
if (p_state == ProposalState.Uninitialized) {
return false;
}
uint256 _initialEndDate = p.initialEndDate;
if (p_state == ProposalState.Started) {
BallotBox storage b = self.ballotBoxes[_id];
Expand Down
3 changes: 2 additions & 1 deletion migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ module.exports = function(deployer) {
_proposalsInitialPeriod = 7;
_proposalsContestPeriod = 7;
_proposalsMinPeriodLen = 3;
_proposalsNumHistoryPeriods = 128;
_timeUnitInSeconds = 24 * 60 * 60; // 1 day

deployer.deploy(KingAutomaton, _numSlots, _minDifficultyBits, _predefinedMask, _initialDailySupply, _approvalPct,
_contestPct, _treasuryLimitPct, _proposalsInitialPeriod, _proposalsContestPeriod, _proposalsMinPeriodLen,
_timeUnitInSeconds);
_proposalsNumHistoryPeriods, _timeUnitInSeconds);
};
2 changes: 1 addition & 1 deletion test/KingAutomatonDEX.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('TestKingAutomatonDEX', async (accounts) => {
beforeEach(async () => {
accounts = await web3.eth.getAccounts();
mainAcct = accounts[0];
koh = await KingAutomaton.new(4, 16, "0x010000", "406080000", 10, -10, 2, 7, 7, 3, 24 * 60 * 60);
koh = await KingAutomaton.new(4, 16, "0x010000", "406080000", 10, -10, 2, 7, 7, 3, 128, 24 * 60 * 60);
minOrderAUTO = await koh.minOrderAUTO();
minOrderETH = await koh.minOrderETH();
DEXAddress = "0x0000000000000000000000000000000000000002";
Expand Down
Loading

0 comments on commit 3f5de4a

Please sign in to comment.