Created
February 7, 2018 23:12
-
-
Save udany/068605ced64d7f75b892db72e2768f56 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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