Skip to content

Instantly share code, notes, and snippets.

@udany
Created February 7, 2018 23:12
Show Gist options
  • Save udany/068605ced64d7f75b892db72e2768f56 to your computer and use it in GitHub Desktop.
Save udany/068605ced64d7f75b892db72e2768f56 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.19;
contract LeakCHain {
struct Voter {
address addr;
uint256 reputation;
uint256 balance;
}
uint256 baseReputation = 1000000;
uint256 totalReputation = 0;
uint256 totalBalance = 0;
struct Vote {
address addr;
bool value;
uint256 stake;
uint time;
}
struct Leak {
uint id;
address submiter;
uint256 stake;
string name;
string fileHash;
//mapping (address => Vote) votes;
Vote[] votes;
uint stakeFor;
uint votesFor;
uint wVotesFor;
uint stakeAgainst;
uint votesAgainst;
uint wVotesAgainst;
uint time;
uint lastVote;
bool approved;
bool declined;
}
uint256 minLeakStake = 10;
uint256 voteStake = 10;
mapping (address => Voter) voters;
Leak[] leaks;
event newLeak(uint256 _id);
event leakApproved(uint256 _id);
event leakDeclined(uint256 _id);
function LeakCHain() public {}
function postLeak(string name, string fileHash) payable public returns(uint) {
// May not pay with balance for submissions
require(msg.value >= minLeakStake);
getVoter(msg.sender);
Leak memory l = Leak({
id: leaks.length,
submiter: msg.sender,
stake: msg.value,
name: name,
fileHash: fileHash,
time: now
});
leaks.push(l);
newLeak(l.id);
totalBalance += msg.value;
return l.id;
}
function createVoter(address addr) internal {
voters[addr] = Voter(addr, baseReputation, 0);
totalReputation += baseReputation;
}
function getVoter(address addr) internal returns(Voter) {
Voter storage v = voters[msg.sender];
if (v.addr == 0) {
createVoter(msg.sender);
v = voters[msg.sender];
}
return v;
}
function vote(uint leakId, bool value) payable public returns(uint) {
Voter storage v = getVoter(msg.sender);
// Verify voter has or has sent funds nough to vote
if (v.balance == 0){
require(msg.value == voteStake);
} else {
uint dif = voteStake - msg.value;
if (dif > 0) {
require(v.balance >= dif);
v.balance -= dif;
}
}
require(leakId < leaks.length);
Leak storage l = leaks[leakId];
require(now <= getLeakCloseTime(l.id));
Vote vote = Vote({
addr: v.addr,
value: value,
stake: msg.value,
time: now
});
l.votes.push(vote);
if (value) {
l.votesFor += 1;
l.wVotesFor += v.reputation;
l.stakeFor += voteStake;
} else {
l.votesAgainst += 1;
l.wVotesAgainst += v.reputation;
l.stakeAgainst += voteStake;
}
l.lastVote = now;
totalBalance += msg.value;
return getLeakCloseTime(l.id);
}
uint baseLeakCloseTime = 604800; // One week
uint dayInSeconds = 86400;
function getLeakCloseTime(uint id) public view returns(uint) {
Leak storage l = leaks[id];
// No votes
if (l.lastVote == 0) return l.time + baseLeakCloseTime;
uint winningVotes = 0;
if (l.wVotesFor > l.wVotesAgainst) {
winningVotes = l.wVotesFor;
}
if (l.wVotesFor < l.wVotesAgainst) {
winningVotes = l.wVotesAgainst;
}
// Tie
if (winningVotes == 0) return l.time + baseLeakCloseTime;
// Normal formula
uint winnerPercent = winningVotes / (l.wVotesFor + l.wVotesAgainst);
uint daysPassed = ((now - l.time) / dayInSeconds) + 1;
uint p5 = ((winnerPercent - 50) / 5) + 1;
return l.lastVote + ((baseLeakCloseTime / (daysPassed*daysPassed)) / (p5*p5));
}
function endVoting(uint id) public returns (bool) {
Leak storage l = leaks[id];
require(now > getLeakCloseTime(l.id));
if (l.wVotesFor >= l.wVotesAgainst) {
l.approved = true;
leakApproved(l.id);
refundSubmitter(l.id);
} else {
l.declined = true;
leakDeclined(l.id);
}
}
function refundSubmitter(uint id) internal {
Leak storage l = leaks[id];
Voter storage v = getVoter(l.submiter);
v.balance += l.stake;
v.reputation += baseReputation;
}
function refundVoters(uint id) internal {
Leak storage l = leaks[id];
bool winner;
uint winnerVoteCount;
uint loserStakes;
if (l.wVotesFor >= l.wVotesAgainst) {
winner = true;
winnerVoteCount = l.votesFor;
loserStakes = l.stakeAgainst;
} else {
winner = false;
winnerVoteCount = l.votesAgainst;
loserStakes = l.stakeFor;
}
uint bonus = loserStakes / (winnerVoteCount * 2);
uint bonusReputation = baseReputation / winnerVoteCount;
if (bonusReputation == 0) bonusReputation = 1;
for (int i; i < l.votes.length; i++ {
Vote storage v = l.votes[i];
Voter storage voter = getVoter(v.addr);
if (v.value == winner) {
//Refund and bonus
voter.balance += v.stake + bonus;
voter.reputation += bonusReputation;
totalReputation += bonusReputation;
} else {
// Lose half reputation
uint penalty = voter.reputation / 2;
voter.reputation -= penalty;
totalReputation -= penalty;
}
}
tx.origin.transfer(bonus);
totalBalance -= bonus;
}
function getLeakCount() public view returns(uint) {
return leaks.length;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment