Skip to content

Instantly share code, notes, and snippets.

@alexvandesande
Last active June 24, 2016 20:49
Show Gist options
  • Save alexvandesande/14ac3d15fc955b56ca40ab278b91cf7a to your computer and use it in GitHub Desktop.
Save alexvandesande/14ac3d15fc955b56ca40ab278b91cf7a to your computer and use it in GitHub Desktop.
Hard Fork Stake Vote
contract HardForkVote {
/*
There is a very important debate on the Ethereum Community on either
contracts should be truly immutable, or if there should be a social
consensus that allows some to be changed on extreme circunstances.
This contract allows the network to signal support for the decision
by having those in favor of a change commit not to move any funds
for a year, to prove their long term commitment to the project.
*/
// This variable can only be changed by a hard fork.
// If no hard fork is in place it will stay at 0;
uint public networkId = 0;
// This variable sets the date of the vote
uint public dateOfDecision;
// This keeps the balance of voters
mapping (address => mapping (uint => uint)) public votes;
function HardForkVote() {
// The decision takes place 30 days after this contract is uploaded
dateOfDecision = now + 30 days;
}
function vote(uint supportedNetwork) {
// add the amount sent to the vote
votes[msg.sender][supportedNetwork] += msg.value;
}
function withdraw(uint supportedNetwork) {
// If the decision date has arrived and you voted for it don't allow withdrawals
if (supportedNetwork == networkId
&& (now > dateOfDecision - 1 days && now < dateOfDecision + 1 years))
throw;
// check the current balance
uint balance = votes[msg.sender][supportedNetwork];
// makes it zero to prevent recursion
votes[msg.sender][supportedNetwork] = 0;
// withdraws
msg.sender.send(balance);
}
function () {
throw;
}
}
@chevdor
Copy link

chevdor commented Jun 23, 2016

In the end, reading such contract is way quicker than a reddit :)
Well done and thanks for sharing. I fixed however a rather big bug. In your version, the votes all go to the CURRENT network instead of the voted one.

I modified also very slightly and deployed it to morden with short time locks (few days max just for testing).
On morden: 0x6fAfCc0F809be60Ad996F7326315Db177D9550Bf
Json Interface:
[{"constant":false,"inputs":[{"name":"supportedNetwork","type":"uint256"}],"name":"vote","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"supportedNetwork","type":"uint256"}],"name":"withdraw","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"dateOfDecision","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"networkId","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"votes","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"inputs":[],"type":"constructor"}]

Deployed contract:

/// @title Reject calls to the default function
contract RejectingEth{
    function () {
        throw;
    }
}

/// @title Suggestion concept: https://gist.github.com/alexvandesande/14ac3d15fc955b56ca40ab278b91cf7a
/// @author @avsa
contract HardForkVote is RejectingEth {
    /*
    There is a very important debate on the Ethereum Community on either 
    contracts should be truly immutable, or if there should be a social 
    consensus that allows some to be changed on extreme circunstances.

    This contract allows the network to signal support for the decision
    by having those in favor of a change commit not to move any funds
    for a year, to prove their long term commitment to the project.
    */

    // This variable can only be changed by a hard fork. 
    // If no hard fork is in place it will stay at 0;
    uint public networkId = 0;

    // This variable sets the date of the vote
    uint public dateOfDecision;

    // This keeps the balance of voters
    mapping (address => mapping (uint => uint)) public votes;

    function HardForkVote() {
        // The decision takes place 1 days after this contract is uploaded
        dateOfDecision = now + 1 days;
    }

    function vote(uint supportedNetwork) {
        // add the amount sent to the vote
        votes[msg.sender][supportedNetwork] += msg.value;
    }

    // initial 1 year brought down to 3 days for testing
    function withdraw(uint supportedNetwork) {
        // If the decision date has arrived and you voted for it don't allow withdrawals
        if (supportedNetwork == networkId
            && (now > dateOfDecision - 1 days && now < dateOfDecision + 3 days))
            throw;

        // check the current balance
        uint balance = votes[msg.sender][networkId];

        // makes it zero to prevent recursion
        votes[msg.sender][networkId] = 0;

        // withdraws
        msg.sender.send(balance);
    }
}

@AustP
Copy link

AustP commented Jun 23, 2016

Not only should line 29 use supportedNetwork instead of networkId as pointed out by @chevdor, but lines 39 and 42 as well.

Take the scenario that someone votes against a hard fork (by voting for network 0). Then the network hard forks and updates networkId to be 1. Now the person would have no way of withdrawing their ether. But if lines 39 and 42 were updated, then the person could withdraw their ether.

@chevdor
Copy link

chevdor commented Jun 23, 2016

@AustP I was think about that too but I guess the idea of @alexvandesande is that only the funds on the legit fork can be withdrawn and not the rest. If that´s the case, the contract is ok. That´s a bit mean though :)
If this is not the case and we agree that everyone should be able to get back his money, just after 1 year, then you are right and the contract should be fixed.
I don´t want to speak for him though.

It seems that, even if the code is clear, the intend of the contract´s author may not.

If the ETH of the 'loser' bets is lost, why not splitting (I feel I should stay away from that word for a while) or sending it as bonus between the users who supported the right fork :) ? That would be an incentive to voting but once again, I think the goal of the contract was not to implement a betting game but to show serious support to an option or another.

An issue I see as well is: how can we be sure of what the networkId will be in a year?
It could be 0 or 1 but also anything else in case of other forks...

I would also probably change the part around line 34 into something less ambiguous to read such as:

if (supportedNetwork != networkId)
   throw;

if (now > dateOfDecision - 1 days && now < dateOfDecision + 3 days))
   throw;

additionally, I am not sure if the "now > dateOfDecision - 1 days" brings much since we just want to lock until the 1y date is reached.
But I guess this is already going too far as Alex probably just wanted to illustrate the idea.

I just fixed some of the issues because I deployed to testnet and wanted to have something working.

@larspensjo
Copy link

As your ether is going to be stuck for one year, you will not be able to participate again in another vote in that period.

@alexvandesande
Copy link
Author

alexvandesande commented Jun 24, 2016

@chevdor @AustP you're right. I just wrote yesterday and didn't even test it. Updated it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment