Add initial and final kdf, allow multiple verifications.

/// This contract can be used (with some small additions to create an economic
/// incentive for the claimant to answer) to claim computation results for
/// scrypt and interactively convict a false claim.
/// Scrypt starts and ends with a certain key derivation function that can be
/// more or less directly computed by the EVM. The computation in the middle
/// is much more complicated and needs interactive verification.
/// Here, scrypt applies a certain hash function to the input in 1024 iterations.
/// Then it applies the hash function another 1024 times but looks up an
/// additional input in the table of the first 1024 values where the look
/// up index depends on the first input.
/// Formally: Assume that H computes the salsa8 hash function as defined below.
/// If value[0] is the input and value[2048] is the output, we have the following
/// relation:
/// value[i] = H(value[i-1]) for 0 < i <= 1024
/// value[i] = H(value[i-1] ^ value[value[i-1] % 1024]) for 1024 < i <= 2048
/// Strictly, not the lowermost byte in value[i-1] is used for addressing,
/// but that does not matter here.
///
/// In this contract, a challenger can ask for each of the value[i]. If the
/// claimant was wrong and the challenger asks in a clever way, she can
/// force the claimant to commit to values for a certain step that do not
/// match the computation done in the actual step.
///
/// The strategy is as follows:
/// We start with a binary search for a point where value[i] is correct but
/// value[i+1] is incorrect (if the response is correct we go up, if it is
/// incorrect we go down).
/// If i <= 1024, the challenger can directly call convict because
/// the commited values do not match the computation.
/// If this ends up at a point i > 1024 it is more complicated because of
/// the second auxiliary input. The challenger has to compute the index
/// of the auxiliary input (value[i] % 1024) and query that. If it is correct,
/// we can again call convict because the output will not match the committed
/// value. If the auxiliary input value is incorrect, it might be that the
/// computation still matches. In this case, we cannot directly call convict
/// but we found an incorrect value at an index smaller than i. This means
/// that we can continue our binary search inside the first half and
/// will end up at a point i' <= 1024 where we can directyl call convict.
///
/// Overall, this should take not more than 22 rounds. Each round costs approximately
/// 140000 gas and a call to convict is about 80000 gas.
/// This means in total, convicting a false claim should not cost more than
/// around three million gas.
/// Of course, as usual, having to convict a false claimant is only a matter
/// of last resort, because every claimant knows that a false claim can be
/// detected and if this is connected with deposits from both sides that
/// go to the winning party, a false claim will probably not be attempted.
///
/// Disclaimer: This has not been tested and is only meant as a proof of concept
/// and a way to compute the gas costs.
contract ScryptVerifier {

    struct VerificationSession {
        address claimant;
        address challenger;
        bytes data;
        bytes32 hash;
        uint16[] queries;
        uint[4][] values;
    }
    VerificationSession[] sessions;

    /// Claim that scrypt(data) == hash. With reference to above,
    /// values[0] = pbkdf2(data) (the "input") and
    /// pbkdf2(values[2048]) should be equal to hash, values[2048] is called "output".
    function claimComputation(bytes _data, bytes32 _hash) {
        sessions.push(VerificationSession({
            claimant: msg.sender,
            challenger: address(0),
            data: _data,
            hash: _hash,
            queries: new uint16[](0),
            values: new uint[4][](0)
        }));
        NewClaim(sessions.length - 1);
    }
    event NewClaim(uint sessionId);
    event Convicted(uint sessionId);
    event NewQuery(uint sessionId);
    event NewResponse(uint sessionId);

    modifier onlyClaimant(uint id) { if (msg.sender != sessions[id].claimant) throw; _ }
    modifier onlyChallenger(uint id) {
        var session = sessions[id];
        if (session.challenger == 0) session.challenger = msg.sender;
        else if (msg.sender != session.challenger) throw;
        _
    }

    /// Challenger queries claimant for the value on a wire `_i`.
    /// Value 0 is the input, value 1024 is the first input to the second
    /// half of the computation, value 2048 is the output.
    function query(uint session, uint16 _i) onlyChallenger(session) {
        if (_i > 2048) throw;
        sessions[session].queries.push(_i);
        NewQuery(session);
    }

    /// Claimant responds to challenge, committing to a value.
    function respond(uint session, uint[4] _value) onlyClaimant(session) {
        var s = sessions[session];
        if (s.values.length >= s.queries.length) throw;
        s.values.push(_value);
        NewResponse(session);
    }

    /// Convicts the claimant to have provided inputs and outputs for a single
    /// step that do not match the computation of the step.
    /// q1, q2 and q3 are query indices providing the relevant values.
    /// q1 is the query index of the first input, q2 the query index of
    /// the output and q2 is the query index of the auxiliary input only
    /// used in the second half of the scrypt computation.
    function convict(uint session, uint q1, uint q2, uint q3) onlyChallenger(session) {
        var s = sessions[session];
        var i = s.queries[q1];
        if (s.queries[q2] != i + 1) throw;
        var input = s.values[q1];
        var output = s.values[q2];
        if (i < 1024) {
            if (!verifyFirstHalf(input, output))
                Convicted(session);
        } else {
            var auxIndex = s.queries[q3];
            if (auxIndex != (input[2] / 0x100000000000000000000000000000000000000000000000000000000) % 1024)
                throw;
            var auxInput = s.values[q3];
            if (!verifySecondHalf(input, auxInput, output))
                Convicted(session);
        }
    }

    /// Convicts the claimant to have provided an incorrect value for value[0].
    function convictInitial(uint session, uint q) onlyChallenger(session) {
        var s = sessions[session];
        if (s.queries[q] != 0) throw;
        var v = s.values[q];
        var h = KeyDeriv.pbkdf2(s.data, s.data, 128);
        if (uint(h[0]) != v[0] || uint(h[1]) != v[1] || uint(h[2]) != v[2] || uint(h[3]) != v[3])
            Convicted(session);
    }

    /// Convicts the claimant to have provided an incorrect value for value[2048].
    function convictFinal(uint session, uint q) onlyChallenger(session) {
        var s = sessions[session];
        if (s.queries[q] != 2048) throw;
        var v = s.values[q];
        bytes memory val = new bytes(128);
        for (uint i = 0; i < 128; i ++)
            val[i] = byte(uint8(v[i / 32] / 2**((32 - (i % 32)) * 8)));
        var h = KeyDeriv.pbkdf2(val, val, 32);
        if (h[0] != s.hash)
            Convicted(session);
    }

    /// Verifies a salsa step in the first half of the scrypt computation.
    function verifyFirstHalf(uint[4] input, uint[4] output) constant returns (bool) {
        var (a, b, c, d) = Salsa8.round(input[0], input[1], input[2], input[3]);
        return (a == output[0] && b == output[1] && c == output[2] && d == output[3]);
    }
    /// Verifies a salsa step in the second half of the scrypt computation.
    function verifySecondHalf(uint[4] input, uint[4] vinput, uint[4] output) constant returns (bool) {
        input[0] ^= vinput[0];
        input[1] ^= vinput[1];
        input[2] ^= vinput[2];
        input[3] ^= vinput[3];
        return verifyFirstHalf(input, output);
    }

    // /// This function can be used to compute the correct response to a
    // /// challenge. It is only intended to be called without a transaction
    // /// because it consumes tremendous amounts of gas.
    // function computeResponse(uint16 _i) constant returns (uint[4]) {
    //     if (_i <= 1024)
    //         return computeResponseFirstHalf(_i);
    //     else
    //         return computeResponseSecondHalf(_i);
    // }
    // function computeResponseSecondHalf(uint16 _i) constant returns (uint[4]) {
    //     uint[4 * 1024] memory lookup;
    //     uint a = values[0][0];
    //     uint b = values[0][1];
    //     uint c = values[0][2];
    //     uint d = values[0][3];
    //     uint l = 0;
    //     lookup[l++] = a;
    //     lookup[l++] = b;
    //     lookup[l++] = c;
    //     lookup[l++] = d;
    //     for (uint16 i = 1; i <= 1024; i++) {
    //         (a, b, c, d) = Salsa8.round(a, b, c, d);
    //         lookup[l++] = a;
    //         lookup[l++] = b;
    //         lookup[l++] = c;
    //         lookup[l++] = d;
    //     }
    //     for (; i <= _i; i++) {
    //         uint auxIndex = ((c / 0x100000000000000000000000000000000000000000000000000000000) % 1024) * 4;
    //         (a, b, c, d) = Salsa8.round(a ^ lookup[auxIndex], b ^ lookup[auxIndex + 1], c ^ lookup[auxIndex + 2], d ^ lookup[auxIndex + 3]);
    //     }
    //     return [a, b, c, d];
    // }
    // function computeResponseFirstHalf(uint16 _i) constant internal returns (uint[4]) {
    //     uint a = values[0][0];
    //     uint b = values[0][1];
    //     uint c = values[0][2];
    //     uint d = values[0][3];
    //     for (uint16 i = 1; i <= _i; i++)
    //         (a, b, c, d) = Salsa8.round(a, b, c, d);
    //     return [a, b, c, d];
    // }
}

library Salsa8 {
    uint constant m0 = 0x100000000000000000000000000000000000000000000000000000000;
    uint constant m1 = 0x1000000000000000000000000000000000000000000000000;
    uint constant m2 = 0x10000000000000000000000000000000000000000;
    uint constant m3 = 0x100000000000000000000000000000000;
    uint constant m4 = 0x1000000000000000000000000;
    uint constant m5 = 0x10000000000000000;
    uint constant m6 = 0x100000000;
    uint constant m7 = 0x1;
    function quarter(uint32 y0, uint32 y1, uint32 y2, uint32 y3)
        internal returns (uint32, uint32, uint32, uint32)
    {
        uint32 t;
        t = y0 + y3;
        y1 = y1 ^ ((t * 2**7) | (t / 2**(32-7)));
        t = y1 + y0;
        y2 = y2 ^ ((t * 2**9) | (t / 2**(32-9)));
        t = y2 + y1;
        y3 = y3 ^ ((t * 2**13) | (t / 2**(32-13)));
        t = y3 + y2;
        y0 = y0 ^ ((t * 2**18) | (t / 2**(32-18)));
        return (y0, y1, y2, y3);
    }
    function get(uint data, uint word) internal returns (uint32 x)
    {
        return uint32(data / 2**(256 - word * 32 - 32));
    }
    function put(uint x, uint word) internal returns (uint) {
        return x * 2**(256 - word * 32 - 32);
    }
    function rowround(uint first, uint second) internal returns (uint f, uint s)
    {
        var (a,b,c,d) = quarter(uint32(first / m0), uint32(first / m1), uint32(first / m2), uint32(first / m3));
        f = (((((uint(a) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
        (b,c,d,a) = quarter(uint32(first / m5), uint32(first / m6), uint32(first / m7), uint32(first / m4));
        f = (((((((f * 2**32) | uint(a)) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
        (c,d,a,b) = quarter(uint32(second / m2), uint32(second / m3), uint32(second / m0), uint32(second / m1));
        s = (((((uint(a) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
        (d,a,b,c) = quarter(uint32(second / m7), uint32(second / m4), uint32(second / m5), uint32(second / m6));
        s = (((((((s * 2**32) | uint(a)) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
    }
    function columnround(uint first, uint second) internal returns (uint f, uint s)
    {
        var (a,b,c,d) = quarter(uint32(first / m0), uint32(first / m4), uint32(second / m0), uint32(second / m4));
        f = (uint(a) * m0) | (uint(b) * m4);
        s = (uint(c) * m0) | (uint(d) * m4);
        (a,b,c,d) = quarter(uint32(first / m5), uint32(second / m1), uint32(second / m5), uint32(first / m1));
        f |= (uint(a) * m5) | (uint(d) * m1);
        s |= (uint(b) * m1) | (uint(c) * m5);
        (a,b,c,d) = quarter(uint32(second / m2), uint32(second / m6), uint32(first / m2), uint32(first / m6));
        f |= (uint(c) * m2) | (uint(d) * m6);
        s |= (uint(a) * m2) | (uint(b) * m6);
        (a,b,c,d) = quarter(uint32(second / m7), uint32(first / m3), uint32(first / m7), uint32(second / m3));
        f |= (uint(b) * m3) | (uint(c) * m7);
        s |= (uint(a) * m7) | (uint(d) * m3);
    }
    function salsa20_8(uint _first, uint _second) internal returns (uint rfirst, uint rsecond) {
        uint first = _first;
        uint second = _second;
        for (uint i = 0; i < 8; i += 2)
        {
            (first, second) = columnround(first, second);
            (first, second) = rowround(first, second);
        }
        for (i = 0; i < 8; i++)
        {
            rfirst |= put(get(_first, i) + get(first, i), i);
            rsecond |= put(get(_second, i) + get(second, i), i);
        }
    }
    function round(uint _a, uint _b, uint _c, uint _d) constant returns (uint, uint, uint, uint) {
        (_a, _b) = salsa20_8(_a ^ _c, _b ^ _d);
        (_c, _d) = salsa20_8(_a ^ _c, _b ^ _d);
        return (_a, _b, _c, _d);
    }
}
library KeyDeriv {
    function hmacsha256(bytes key, bytes message) constant returns (bytes32) {
        bytes32 keyl;
        bytes32 keyr;
        uint i;
        if (key.length > 64) {
            keyl = sha256(key);
        } else {
            for (i = 0; i < key.length && i < 32; i++)
                keyl |= bytes32(uint(key[i]) * 2**(8 * (31 - i)));
            for (i = 32; i < key.length && i < 64; i++)
                keyr |= bytes32(uint(key[i]) * 2**(8 * (63 - i)));
        }
        bytes32 threesix = 0x3636363636363636363636363636363636363636363636363636363636363636;
        bytes32 fivec = 0x5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c;
        return sha256(fivec ^ keyl, fivec ^ keyr, sha256(threesix ^ keyl, threesix ^ keyr, message));
    }
    /// PBKDF2 restricted to c=1, hash = hmacsha256 and dklen being a multiple of 32 not larger than 128
    function pbkdf2(bytes key, bytes salt, uint dklen) constant returns (bytes32[4] r) {
        var msg = new bytes(salt.length + 4);
        for (uint i = 0; i < salt.length; i++)
            msg[i] = salt[i];
        for (i = 0; i * 32 < dklen; i++) {
            msg[msg.length - 1] = bytes1(uint8(i + 1));
            r[i] = hmacsha256(key, msg);
        }
    }
}

/// This contract can be used (with some small additions to create an economic
/// incentive for the claimant to answer) to claim computation results for
/// scrypt (actually only the part where we do not have precompiled contracts)
/// and interactively convict a false claim.
/// Scrypt first applies a certain hash function to the input in 1024 iterations.
/// Then it applies the hash function another 1024 times but looks up an
/// additional input in the table of the first 1024 values where the look
/// up index depends on the first input.
/// Formally: Assume that H computes the salsa8 hash function as defined below.
/// If value[0] is the input and value[2048] is the output, we have the following
/// relation:
/// value[i] = H(value[i-1]) for 0 < i <= 1024
/// value[i] = H(value[i-1] ^ value[value[i-1] % 1024]) for 1024 < i <= 2048
/// Strictly, not the lowermost byte in value[i-1] is used for addressing,
/// but that does not matter here.
///
/// In this contract, a challenger can ask for each of the value[i]. If the
/// claimant was wrong and the challenger asks in a clever way, she can
/// force the claimant to commit to values for a certain step that do not
/// match the computation done in the actual step.
///
/// The strategy is as follows:
/// We start with a binary search for a point where value[i] is correct but
/// value[i+1] is incorrect (if the response is correct we go up, if it is
/// incorrect we go down).
/// If i <= 1024, the challenger can directly call convict because
/// the commited values do not match the computation.
/// If this ends up at a point i > 1024 it is more complicated because of
/// the second auxiliary input. The challenger has to compute the index
/// of the auxiliary input (value[i] % 1024) and query that. If it is correct,
/// we can again call convict because the output will not match the committed
/// value. If the auxiliary input value is incorrect, it might be that the
/// computation still matches. In this case, we cannot directly call convict
/// but we found an incorrect value at an index smaller than i. This means
/// that we can continue our binary search inside the first half and
/// will end up at a point i' <= 1024 where we can directyl call convict.
///
/// Overall, this should take not more than 22 rounds. Each round costs approximately
/// 140000 gas and a call to convict is about 80000 gas.
/// This means in total, convicting a false claim should not cost more than
/// around three million gas.
/// Of course, as usual, having to convict a false claimant is only a matter
/// of last resort, because every claimant knows that a false claim can be
/// detected and if this is connected with deposits from both sides that
/// go to the winning party, a false claim will probably not be attempted.
///
/// Disclaimer: This has not been tested and is only meant as a proof of concept
/// and a way to compute the gas costs.
contract Scrypt {
    address claimant;
    address challenger;

    function Scrypt(uint[4] _input, uint[4] _output) {
        claimant = msg.sender;
        queries.length = 2;
        queries.push(0);
        queries.push(2048);
        values.push(_input);
        values.push(_output);
    }
    event Convicted();

    modifier onlyClaimant() { if (msg.sender != claimant) throw; _ }
    modifier onlyChallenger() {
        if (challenger == 0) challenger = msg.sender;
        else if (msg.sender != challenger) throw;
        _
    }

    uint16[] public queries;
    /// Challenger queries claimant for the value on a wire `_i`.
    /// Value 0 is the input, value 1024 is the first input to the second
    /// half of the computation, value 2048 is the output.
    function query(uint16 _i) onlyChallenger {
        if (_i > 2048) throw;
        queries.push(_i);
    }

    uint[4][] public values;
    /// Claimant responds to challenge, committing to a value.
    function respond(uint[4] _value) onlyClaimant {
        if (values.length >= queries.length) throw;
        values.push(_value);
    }

    /// Convicts the claimant to have provided inputs and outputs for a single
    /// step that do not match the computation of the step.
    /// q1, q2 and q3 are query indices providing the relevant values.
    /// q1 is the query index of the first input, q2 the query index of
    /// the output and q2 is the query index of the auxiliary input only
    /// used in the second half of the scrypt computation.
    function convict(uint q1, uint q2, uint q3) {
        var i = queries[q1];
        if (queries[q2] != i + 1) throw;
        var input = values[q1];
        var output = values[q2];
        if (i < 1024) {
            if (!verifyFirstHalf(input, output))
                Convicted();
        } else {
            var auxIndex = queries[q3];
            if (auxIndex != (input[2] / 0x100000000000000000000000000000000000000000000000000000000) % 1024)
                throw;
            var auxInput = values[q3];
            if (!verifySecondHalf(input, auxInput, output))
                Convicted();
        }
    }

    /// Verifies a salsa step in the first half of the scrypt computation.
    function verifyFirstHalf(uint[4] input, uint[4] output) constant returns (bool) {
        var (a, b, c, d) = Salsa8.round(input[0], input[1], input[2], input[3]);
        return (a == output[0] && b == output[1] && c == output[2] && d == output[3]);
    }
    /// Verifies a salsa step in the second half of the scrypt computation.
    function verifySecondHalf(uint[4] input, uint[4] vinput, uint[4] output) constant returns (bool) {
        input[0] ^= vinput[0];
        input[1] ^= vinput[1];
        input[2] ^= vinput[2];
        input[3] ^= vinput[3];
        return verifyFirstHalf(input, output);
    }

}

library Salsa8 {
    uint constant m0 = 0x100000000000000000000000000000000000000000000000000000000;
    uint constant m1 = 0x1000000000000000000000000000000000000000000000000;
    uint constant m2 = 0x10000000000000000000000000000000000000000;
    uint constant m3 = 0x100000000000000000000000000000000;
    uint constant m4 = 0x1000000000000000000000000;
    uint constant m5 = 0x10000000000000000;
    uint constant m6 = 0x100000000;
    uint constant m7 = 0x1;
    function quarter(uint32 y0, uint32 y1, uint32 y2, uint32 y3)
        internal returns (uint32, uint32, uint32, uint32)
    {
        uint32 t;
        t = y0 + y3;
        y1 = y1 ^ ((t * 2**7) | (t / 2**(32-7)));
        t = y1 + y0;
        y2 = y2 ^ ((t * 2**9) | (t / 2**(32-9)));
        t = y2 + y1;
        y3 = y3 ^ ((t * 2**13) | (t / 2**(32-13)));
        t = y3 + y2;
        y0 = y0 ^ ((t * 2**18) | (t / 2**(32-18)));
        return (y0, y1, y2, y3);
    }
    function get(uint data, uint word) internal returns (uint32 x)
    {
        return uint32(data / 2**(256 - word * 32 - 32));
    }
    function put(uint x, uint word) internal returns (uint) {
        return x * 2**(256 - word * 32 - 32);
    }
    function rowround(uint first, uint second) internal returns (uint f, uint s)
    {
        var (a,b,c,d) = quarter(uint32(first / m0), uint32(first / m1), uint32(first / m2), uint32(first / m3));
        f = (((((uint(a) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
        (b,c,d,a) = quarter(uint32(first / m5), uint32(first / m6), uint32(first / m7), uint32(first / m4));
        f = (((((((f * 2**32) | uint(a)) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
        (c,d,a,b) = quarter(uint32(second / m2), uint32(second / m3), uint32(second / m0), uint32(second / m1));
        s = (((((uint(a) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
        (d,a,b,c) = quarter(uint32(second / m7), uint32(second / m4), uint32(second / m5), uint32(second / m6));
        s = (((((((s * 2**32) | uint(a)) * 2**32) | uint(b)) * 2 ** 32) | uint(c)) * 2**32) | uint(d);
    }
    function columnround(uint first, uint second) internal returns (uint f, uint s)
    {
        var (a,b,c,d) = quarter(uint32(first / m0), uint32(first / m4), uint32(second / m0), uint32(second / m4));
        f = (uint(a) * m0) | (uint(b) * m4);
        s = (uint(c) * m0) | (uint(d) * m4);
        (a,b,c,d) = quarter(uint32(first / m5), uint32(second / m1), uint32(second / m5), uint32(first / m1));
        f |= (uint(a) * m5) | (uint(d) * m1);
        s |= (uint(b) * m1) | (uint(c) * m5);
        (a,b,c,d) = quarter(uint32(second / m2), uint32(second / m6), uint32(first / m2), uint32(first / m6));
        f |= (uint(c) * m2) | (uint(d) * m6);
        s |= (uint(a) * m2) | (uint(b) * m6);
        (a,b,c,d) = quarter(uint32(second / m7), uint32(first / m3), uint32(first / m7), uint32(second / m3));
        f |= (uint(b) * m3) | (uint(c) * m7);
        s |= (uint(a) * m7) | (uint(d) * m3);
    }
    function salsa20_8(uint _first, uint _second) internal returns (uint rfirst, uint rsecond) {
        uint first = _first;
        uint second = _second;
        for (uint i = 0; i < 8; i += 2)
        {
            (first, second) = columnround(first, second);
            (first, second) = rowround(first, second);
        }
        for (i = 0; i < 8; i++)
        {
            rfirst |= put(get(_first, i) + get(first, i), i);
            rsecond |= put(get(_second, i) + get(second, i), i);
        }
    }
    function round(uint _a, uint _b, uint _c, uint _d) constant returns (uint, uint, uint, uint) {
        (_a, _b) = salsa20_8(_a ^ _c, _b ^ _d);
        (_c, _d) = salsa20_8(_a ^ _c, _b ^ _d);
        return (_a, _b, _c, _d);
    }
}


Set lastStateTransitionRound if delegator is bonding for first time

pragma solidity ^0.4.8;

import "./LivepeerToken.sol";
import "./TranscoderPools.sol";
import "./Node.sol";
import '../installed_contracts/zeppelin/contracts/SafeMath.sol';

contract LivepeerProtocol is SafeMath {
    using TranscoderPools for TranscoderPools.TranscoderPools;

    // Token address
    LivepeerToken public token;

    // Truebit address
    address public truebitAddress;

    /* Token constants */

    // 1 LPT == 10^18th units
    uint8 decimals = 18;

    // Start with 10M tokens
    uint256 public initialTokenSupply = 10000000 * (10 ** 18);

    // Fixed inflation rate of 26%
    uint8 public initialYearlyInflation = 26;

    /* Protocol Parameters */

    // Segment length
    uint64 public t;

    // Number of active transcoders
    uint64 public n;

    // Time between blocks. For testing purposes
    uint256 public blockTime;

    // Round length in blocks
    uint256 public roundLength;

    // Current round
    uint256 public currentRound;

    // Number of times each transcoder is expected to call Reward() in a round
    uint256 public cyclesPerRound;

    // Time before the start of a round that the transcoders rates lock
    uint64 public rateLockDeadline;

    // Time between unbonding and possible withdrawl in rounds
    uint64 public unbondingPeriod;

    // Time that data must be guaranteed in storage for verification
    uint64 public persistenceLength;

    // % of segments to be verified. 1 / verificationRate == % to be verified
    uint64 public verificationRate;

    // Slash % in the case of failed verification
    uint64 public failedVerificationSlashAmount;

    // Slash % in the case of failing to call Reward()
    uint64 public missedRewardSlashAmount;

    // Slash % in the case of missing a call to verification
    uint64 public missedVerificationSlashAmount;

    // % of tolerance for failing to do proper share of work
    uint64 public competitivenessTolerance;

    // % of verifications you can fail before being slashed
    uint64 public verificationFailureThreshold;

    // Represents a transcoder's current state
    struct Transcoder {
        address transcoderAddress;      // The address of this transcoder.
        uint256 bondedAmount;           // The amount they have bonded themselves
        uint256 delegatorWithdrawRound; // The round at which delegators to this transcoder can withdraw if this transcoder resigns
        uint256 rewardRound;            // Last round that the transcoder called reward()
        uint256 rewardCycle;            // Last cycle of the last round that the transcoder called reward()
        uint8 blockRewardCut;           // Percentage of token reward that delegators pay the transcoder
        bool active;                    // Is this transcoder active. Also will be false if uninitialized

        // TODO: add all the state information about pricing, fee split, etc.
    }

    // Active and candidate transcoder pools
    TranscoderPools.TranscoderPools transcoderPools;

    // The various states a delegator can be in
    enum DelegatorStatus { Inactive, Pending, Bonded, Unbonding }

    // Represents a delegator's current state
    struct Delegator {
        address delegatorAddress;          // The ethereum address of this delegator
        uint256 bondedAmount;              // The amount they have bonded
        address transcoderAddress;         // The ethereum address of the transcoder they are delgating towards
        uint256 roundStart;                // The round the delegator transitions to bonded phase
        uint256 withdrawRound;             // The round at which a delegator can withdraw
        uint256 lastStateTransitionRound;  // The last round the delegator transitioned states
        bool initialized;                  // Is this delegator initialized
    }

    // Keep track of the known transcoders and delegators
    // Note: Casper style implementation would have us using arrays and bitmaps to index these
    mapping (address => Delegator) public delegators;
    mapping (address => Transcoder) public transcoders;

    // Current active transcoders for current round
    Node.Node[] currentActiveTranscoders;
    // Mapping to track which addresses are in the current active transcoder set
    mapping (address => bool) isCurrentActiveTranscoder;
    // Mapping to track the index position of an address in the current active transcoder set
    mapping (address => uint256) currentActiveTranscoderPositions;

    // Mapping to track transcoder's reward multiplier for a round
    // rewardMultiplier[0] -> total minted tokens for round
    // rewardMultiplier[1] -> transcoder's cumulative stake for round
    mapping (address => mapping (uint256 => uint256[2])) public rewardMultiplierPerTranscoderAndRound;

    // Update delegator and transcoder stake with rewards from past rounds when a delegator calls bond() or unbond()
    modifier updateStakesWithRewards() {
        // Check if delegator bonded to a transcoder
        if (delegators[msg.sender].initialized && delegators[msg.sender].transcoderAddress != address(0)) {
            // Iterate from round that delegator last transitioned states to current round
            // If the delegator is bonded to a transcoder, it has been bonded to the transcoder since lastStateTransitionRound
            for (uint256 i = delegators[msg.sender].lastStateTransitionRound; i <= block.number / roundLength; i++) {
                uint256[2] rewardMultiplier = rewardMultiplierPerTranscoderAndRound[delegators[msg.sender].transcoderAddress][i];

                // Check if transcoder has a reward multiplier for this round (total minted tokens for round > 0)
                if (rewardMultiplier[0] > 0) {
                    // Calculate delegator's token reward reward multiplier
                    uint256 tokenReward = (rewardMultiplier[0] * delegators[msg.sender].bondedAmount) / rewardMultiplier[1];
                    // Calculate transcoder's share of reward
                    uint256 transcoderRewardShare = (tokenReward * transcoders[delegators[msg.sender].transcoderAddress].blockRewardCut) / 100;

                    // Update transcoder stake with transcoder share of reward
                    transcoders[delegators[msg.sender].transcoderAddress].bondedAmount = safeAdd(transcoders[delegators[msg.sender].transcoderAddress].bondedAmount, transcoderRewardShare);
                    // Update transcoder cumulative stake with delegator's total token reward (delegator's share + transcoder's share)
                    transcoderPools.increaseTranscoderStake(delegators[msg.sender].transcoderAddress, tokenReward);
                    // Update delegator stake with delegator's share of reward
                    delegators[msg.sender].bondedAmount = safeAdd(delegators[msg.sender].bondedAmount, tokenReward - transcoderRewardShare);
                }
            }
        }

        delegators[msg.sender].lastStateTransitionRound = block.number / roundLength;

        _;
    }

    // Initialize protocol
    function LivepeerProtocol(uint64 _n, uint256 _roundLength, uint256 _cyclesPerRound) {
        // Deploy new token contract
        token = new LivepeerToken();

        // Set truebit address
        truebitAddress = 0x647167a598171d06aecf0f5fa1daf3c5cc848df0;

        // Initialize parameters
        // Segment length of 2 seconds
        t = 2;

        // Start with provided number of transcoders parameter
        // Current value is for testing purposes
        n = _n;

        // Set block time to 1 second for testing purposes
        blockTime = 1;

        // Round length of ~1 day assuming ~17 second block time on main net
        // Current value is for testing purposes
        roundLength = _roundLength;
        currentRound = block.number / roundLength;

        // Transcoder expected to call reward every ~10 minutes assuming ~17 second block time on main net
        // Current value is for testing purposes
        cyclesPerRound = _cyclesPerRound;

        // Lock rate changes 2 hours before round
        rateLockDeadline = 2 hours;

        // Unbond for ~10 days assuming ~17 second block time on main net
        // Current value is for testing purposes
        unbondingPeriod = 2;

        // Keep data in storage for 6 hours
        persistenceLength = 6 hours;

        // Verify 1/500 segments
        verificationRate = 500;

        // Slash percentages
        failedVerificationSlashAmount = 5;
        missedRewardSlashAmount = 3;
        missedVerificationSlashAmount = 10;

        // Expect transcoders to be 90% competitive
        competitivenessTolerance = 90;

        // Fail no more than 1% of the time
        verificationFailureThreshold = 1;

        // Initialize transcoder pools - size of candidate pool subject to change
        transcoderPools.init(n, n);

        // Do initial token distribution - currently clearly fake, minting 3 LPT to the contract creator
        token.mint(msg.sender, 3000000000000000000);
    }

    /*
     * Computes delegator status
     * @param _delegator Address of delegator
     */
    function delegatorStatus(address _delegator) constant returns (DelegatorStatus) {
        // Check if this is an initialized delegator
        if (delegators[_delegator].initialized == false) throw;

        if (delegators[_delegator].withdrawRound > 0 ||
            (delegators[_delegator].transcoderAddress != address(0)
             && transcoders[delegators[_delegator].transcoderAddress].delegatorWithdrawRound > 0)) {
            // Delegator called unbond() or transcoder resigned
            // In unbonding phase
            return DelegatorStatus.Unbonding;
        } else if (delegators[_delegator].roundStart > block.number / roundLength) {
            // Delegator round start is in the future
            // In pending phase
            return DelegatorStatus.Pending;
        } else if (delegators[_delegator].roundStart <= block.number / roundLength) {
            // Delegator round start is now or in the past
            // In bonded phase
            return DelegatorStatus.Bonded;
        } else {
            // Delegator in inactive phase
            return DelegatorStatus.Inactive;
        }
    }

    /*
     * Checks if delegator unbonding period is over
     * @param _delegator Address of delegator
     */
    function unbondingPeriodOver(address _delegator) constant returns (bool) {
        // Check if this is an initialized delegator
        if (delegators[_delegator].initialized == false) throw;

        if (delegators[_delegator].withdrawRound > 0) {
            // Delegator called unbond()
            return block.number / roundLength >= delegators[_delegator].withdrawRound;
        } else if (delegators[_delegator].transcoderAddress != address(0)
                   && transcoders[delegators[_delegator].transcoderAddress].delegatorWithdrawRound > 0) {
            // Transcoder resigned
            return block.number / roundLength >= transcoders[delegators[_delegator].transcoderAddress].delegatorWithdrawRound;
        } else {
            // Delegator not in unbonding state
            return false;
        }
    }

    /**
     * Delegate stake towards a specific address.
     * @param _amount The amount of LPT to stake.
     * @param _to The address of the transcoder to stake towards.
     */
    function bond(uint _amount, address _to) updateStakesWithRewards returns (bool) {
        // Check if this is a valid transcoder who is active
        if (transcoders[_to].active == false) throw;

        if (_amount > 0) {
            // Only transfer tokens if _amount is greater than 0
            // Transfer the token. This call throws if it fails.
            token.transferFrom(msg.sender, this, _amount);
        }

        // Amount to be staked to transcoder
        uint256 stakeForTranscoder = _amount;

        if (transcoders[msg.sender].active == true && _to == msg.sender) {
            // Sender is a registered transcoder and is delegating to self
            transcoders[msg.sender].bondedAmount = safeAdd(transcoders[msg.sender].bondedAmount, _amount);
        } else {
            // Sender is not a registered transcoder
            // Update or create this delegator
            Delegator del = delegators[msg.sender];

            if (del.initialized == false ||
                (del.transcoderAddress != address(0) && transcoders[del.transcoderAddress].active == false)) {
                // Set round start if creating delegator for first time or if
                // delegator was bonded to an inactive transcoder
                del.roundStart = (block.number / roundLength) + 1;
            }

            if (del.transcoderAddress != address(0) && _to != del.transcoderAddress) {
                // Delegator is moving bond
                // Set round start if delegator moves bond to another active transcoder
                del.roundStart = (block.number / roundLength) + 1;
                // Decrease former transcoder cumulative stake
                transcoderPools.decreaseTranscoderStake(del.transcoderAddress, del.bondedAmount);
                // Stake amount includes delegator's total bonded amount since delegator is moving its bond
                stakeForTranscoder = safeAdd(stakeForTranscoder, del.bondedAmount);
            }

            del.delegatorAddress = msg.sender;
            del.transcoderAddress = _to;
            del.bondedAmount = safeAdd(del.bondedAmount, _amount);
            del.withdrawRound = 0;
            del.initialized = true;
            delegators[msg.sender] = del;

        }

        if (transcoderPools.isInPools(_to)) {
            // Target transcoder is in a pool
            // Increase transcoder cumulative stake
            transcoderPools.increaseTranscoderStake(_to, stakeForTranscoder);
        } else {
            // Target transcoder is not in a pool
            // Add transcoder
            transcoderPools.addTranscoder(_to, stakeForTranscoder);
        }

        return true;
    }

    /**
     * Unbond your current stake. This will enter the unbonding phase for
     * the unbondingPeriod.
     */
    function unbond() updateStakesWithRewards returns (bool) {
        // Check if this is an initialized delegator
        if (delegators[msg.sender].initialized == false) throw;
        // Check if delegator is in bonded status
        if (delegatorStatus(msg.sender) != DelegatorStatus.Bonded) throw;

        // Transition to unbonding phase
        delegators[msg.sender].withdrawRound = safeAdd(block.number / roundLength, unbondingPeriod);

        // Decrease transcoder cumulative stake
        transcoderPools.decreaseTranscoderStake(delegators[msg.sender].transcoderAddress, delegators[msg.sender].bondedAmount);

        return true;
    }

    /**
     * Withdraws withdrawable funds back to the caller after unbonding period.
     */
    function withdraw() returns (bool) {
        // Check if this is an initialized delegator
        if (delegators[msg.sender].initialized == false) throw;
         // Check if delegator is in unbonding phase
        if (delegatorStatus(msg.sender) != DelegatorStatus.Unbonding) throw;
        // Check if delegator's unbonding period is over
        if (!unbondingPeriodOver(msg.sender)) throw;

        // Transfer token. This call throws if it fails.
        token.transfer(msg.sender, delegators[msg.sender].bondedAmount);

        // Delete delegator
        delete delegators[msg.sender];

        return true;
    }

    /**
     * Active transcoders call this once per cycle when it is their turn.
     * Distribute the token rewards to transcoder and delegates.
     */
    function reward() returns (bool) {
        // Check if in current round active transcoder set
        if (!isCurrentActiveTranscoder[msg.sender]) throw;

        // Check if already called for current cycle
        if (transcoders[msg.sender].rewardRound == block.number / roundLength && transcoders[msg.sender].rewardCycle == cycleNum()) throw;

        // Check if in a valid transcoder reward time window
        if (!validRewardTimeWindow(msg.sender)) throw;

        // Set last round that transcoder called reward()
        transcoders[msg.sender].rewardRound = block.number / roundLength;
        // Set last cycle of last round that transcoder called reward()
        transcoders[msg.sender].rewardCycle = cycleNum();

        // Reward calculation
        // Calculate number of tokens to mint
        uint256 mintedTokens = mintedTokensPerReward();
        // Mint token reward and allocate to this protocol contract
        token.mint(this, mintedTokens);
        // Add minted tokens for the current cycle of the current round to reward multipler numerator
        uint256[2] rewardMultiplier = rewardMultiplierPerTranscoderAndRound[msg.sender][block.number / roundLength];
        rewardMultiplier[0] = safeAdd(rewardMultiplier[0], mintedTokens);

        if (cycleNum() == 0 || rewardMultiplier[1] == 0) {
            // First cycle of current round or reward multiplier denominator has not been set yet
            // Set transcoder cumulative stake for current round as denominator of reward multiplier for current round
            rewardMultiplier[1] = currentActiveTranscoders[currentActiveTranscoderPositions[msg.sender]].key;
        }

        rewardMultiplierPerTranscoderAndRound[msg.sender][block.number / roundLength] = rewardMultiplier;

        return true;
    }

    function mintedTokensPerReward() constant returns (uint256) {
        uint256 rewardsPerYear = ((365 * 24 * 60 * 60) / blockTime / roundLength) * cyclesPerRound * n;
        return ((initialTokenSupply * initialYearlyInflation) / 100) / rewardsPerYear;
    }

    /**
     * The sender is declaring themselves as a candidate for active transcoding.
     */
    function transcoder(uint8 _blockRewardCut) returns (bool) {
        Transcoder t = transcoders[msg.sender];
        t.transcoderAddress = msg.sender;
        t.delegatorWithdrawRound = 0;
        t.rewardRound = 0;
        t.rewardCycle = 0;
        t.blockRewardCut = _blockRewardCut;
        t.active = true;
        transcoders[msg.sender] = t;

        return true;
    }

    /*
     * Remove the sender as a transcoder
     */
    function resignAsTranscoder() returns (bool) {
        // Check if active transcoder
        if (transcoders[msg.sender].active == false) throw;

        // Go inactive
        transcoders[msg.sender].active = false;
        // Set withdraw round for delegators
        transcoders[msg.sender].delegatorWithdrawRound = safeAdd(block.number / roundLength, unbondingPeriod);
        // Zero out bonded amount
        transcoders[msg.sender].bondedAmount = 0;
        // Remove transcoder from pools
        transcoderPools.removeTranscoder(msg.sender);
    }

    /*
     * Checks if a transcoder is in active pool
     * @param _transcoder Address of transcoder
     */
    function isActiveTranscoder(address _transcoder) constant returns (bool) {
        return transcoderPools.activeTranscoders.ids[_transcoder];
    }

    /*
     * Checks if a transcoder is in candidate pool
     * @param _transcoder Address of transcoder
     */
    function isCandidateTranscoder(address _transcoder) constant returns (bool) {
        return transcoderPools.candidateTranscoders.ids[_transcoder];
    }

    /**
     * Called once at the start of any round
     */
    function initializeRound() returns (bool) {
        // Check if already called for the current round
        // Will exit here to avoid large gas consumption if it has been called for the current round already
        if (currentRound == block.number / roundLength) return false;
        // Set the current round
        currentRound = block.number / roundLength;

        // Set current round active transcoders
        setCurrentActiveTranscoders();

        return true;
    }

    /*
     * Set current active transcoder set for the current round
     */
    function setCurrentActiveTranscoders() internal returns (bool) {
        if (currentActiveTranscoders.length != transcoderPools.activeTranscoders.nodes.length) {
            // Set length of array if it has not already been set
            currentActiveTranscoders.length = transcoderPools.activeTranscoders.nodes.length;
        }

        for (uint256 i = 0; i < transcoderPools.activeTranscoders.nodes.length; i++) {
            if (currentActiveTranscoders[i].initialized) {
                // Set address of old node to not be present in current active transcoder set
                isCurrentActiveTranscoder[currentActiveTranscoders[i].id] = false;
            }
            // Copy node
            currentActiveTranscoders[i] = transcoderPools.activeTranscoders.nodes[i];
            // Set address of node to be present in current active transcoder set
            isCurrentActiveTranscoder[currentActiveTranscoders[i].id] = true;
            // Set index position of node in current active transcoder set
            currentActiveTranscoderPositions[currentActiveTranscoders[i].id] = i;
        }

        return true;
    }

    /*
     * Pseudorandomly elect an active transcoder. Currently a placeholder
     * TODO: take into account pricing, etc.
     */
    function electCurrentActiveTranscoder() constant returns (address) {
        return currentActiveTranscoders[uint(block.blockhash(block.number - 1)) % currentActiveTranscoders.length].id;
    }

    /*
     * Return start block of current round
     */
    function currentRoundStartBlock() constant returns (uint256) {
        return (block.number / roundLength) * roundLength;
    }

    /*
     * Return length in blocks of a time window for calling reward()
     */
    function rewardTimeWindowLength() constant returns (uint256) {
        return roundLength / (n * cyclesPerRound);
    }

    /*
     * Return length in blocks of a cycle
     */
    function cycleLength() constant returns (uint256) {
        return rewardTimeWindowLength() * n;
    }

    /*
     * Return number of cycles since the start of the round
     */
    function cycleNum() constant returns (uint256) {
        return (block.number - currentRoundStartBlock()) / cycleLength();
    }

    /*
     * Checks if a transcoder is calling reward() in the correct range of blocks
     * for its time window
     * @param _transcoder Address of transcoder
     */
    function validRewardTimeWindow(address _transcoder) internal returns (bool) {
        // Check if transcoder is present in current active transcoder set
        if (!isCurrentActiveTranscoder[_transcoder]) throw;

        // Use index position of address in current active transcoder set as its place in the order for calling reward()
        uint256 transcoderIdx = currentActiveTranscoderPositions[_transcoder];

        // Compute start block of reward time window for this cycle
        uint256 rewardTimeWindowStartBlock = currentRoundStartBlock() + (cycleNum() * cycleLength()) + (transcoderIdx * rewardTimeWindowLength());
        // Compute end block of reward time window for this cycle
        uint256 rewardTimeWindowEndBlock = rewardTimeWindowStartBlock + rewardTimeWindowLength();

        return block.number >= rewardTimeWindowStartBlock && block.number < rewardTimeWindowEndBlock;
    }

    /*
     * Returns cumulative stake for a transcoder
     * @param _transcoder Address of transcoder
     */
    function transcoderStake(address _transcoder) constant returns (uint256) {
        return transcoderPools.transcoderStake(_transcoder);
    }
}

pragma solidity ^0.4.8;

import "./LivepeerToken.sol";
import "./TranscoderPools.sol";
import "./Node.sol";
import '../installed_contracts/zeppelin/contracts/SafeMath.sol';

contract LivepeerProtocol is SafeMath {
    using TranscoderPools for TranscoderPools.TranscoderPools;

    // Token address
    LivepeerToken public token;

    // Truebit address
    address public truebitAddress;

    /* Token constants */

    // 1 LPT == 10^18th units
    uint8 decimals = 18;

    // Start with 10M tokens
    uint256 public initialTokenSupply = 10000000 * (10 ** 18);

    // Fixed inflation rate of 26%
    uint8 public initialYearlyInflation = 26;

    /* Protocol Parameters */

    // Segment length
    uint64 public t;

    // Number of active transcoders
    uint64 public n;

    // Time between blocks. For testing purposes
    uint256 public blockTime;

    // Round length in blocks
    uint256 public roundLength;

    // Current round
    uint256 public currentRound;

    // Number of times each transcoder is expected to call Reward() in a round
    uint256 public cyclesPerRound;

    // Time before the start of a round that the transcoders rates lock
    uint64 public rateLockDeadline;

    // Time between unbonding and possible withdrawl in rounds
    uint64 public unbondingPeriod;

    // Time that data must be guaranteed in storage for verification
    uint64 public persistenceLength;

    // % of segments to be verified. 1 / verificationRate == % to be verified
    uint64 public verificationRate;

    // Slash % in the case of failed verification
    uint64 public failedVerificationSlashAmount;

    // Slash % in the case of failing to call Reward()
    uint64 public missedRewardSlashAmount;

    // Slash % in the case of missing a call to verification
    uint64 public missedVerificationSlashAmount;

    // % of tolerance for failing to do proper share of work
    uint64 public competitivenessTolerance;

    // % of verifications you can fail before being slashed
    uint64 public verificationFailureThreshold;

    // Represents a transcoder's current state
    struct Transcoder {
        address transcoderAddress;      // The address of this transcoder.
        uint256 bondedAmount;           // The amount they have bonded themselves
        uint256 delegatorWithdrawRound; // The round at which delegators to this transcoder can withdraw if this transcoder resigns
        uint256 rewardRound;            // Last round that the transcoder called reward()
        uint256 rewardCycle;            // Last cycle of the last round that the transcoder called reward()
        uint8 blockRewardCut;           // Percentage of token reward that delegators pay the transcoder
        bool active;                    // Is this transcoder active. Also will be false if uninitialized

        // TODO: add all the state information about pricing, fee split, etc.
    }

    // Active and candidate transcoder pools
    TranscoderPools.TranscoderPools transcoderPools;

    // The various states a delegator can be in
    enum DelegatorStatus { Inactive, Pending, Bonded, Unbonding }

    // Represents a delegator's current state
    struct Delegator {
        address delegatorAddress;          // The ethereum address of this delegator
        uint256 bondedAmount;              // The amount they have bonded
        address transcoderAddress;         // The ethereum address of the transcoder they are delgating towards
        uint256 roundStart;                // The round the delegator transitions to bonded phase
        uint256 withdrawRound;             // The round at which a delegator can withdraw
        uint256 lastStateTransitionRound;  // The last round the delegator transitioned states
        bool initialized;                  // Is this delegator initialized
    }

    // Keep track of the known transcoders and delegators
    // Note: Casper style implementation would have us using arrays and bitmaps to index these
    mapping (address => Delegator) public delegators;
    mapping (address => Transcoder) public transcoders;

    // Current active transcoders for current round
    Node.Node[] currentActiveTranscoders;
    // Mapping to track which addresses are in the current active transcoder set
    mapping (address => bool) isCurrentActiveTranscoder;
    // Mapping to track the index position of an address in the current active transcoder set
    mapping (address => uint256) currentActiveTranscoderPositions;

    // Mapping to track transcoder's reward multiplier for a round
    // rewardMultiplier[0] -> total minted tokens for round
    // rewardMultiplier[1] -> transcoder's cumulative stake for round
    mapping (address => mapping (uint256 => uint256[2])) public rewardMultiplierPerTranscoderAndRound;

    // Update delegator and transcoder stake with rewards from past rounds when a delegator calls bond() or unbond()
    modifier updateStakesWithRewards() {
        // Check if delegator bonded to a transcoder
        if (delegators[msg.sender].initialized && delegators[msg.sender].transcoderAddress != address(0)) {
            // Iterate from round that delegator last transitioned states to current round
            // If the delegator is bonded to a transcoder, it has been bonded to the transcoder since lastStateTransitionRound
            for (uint256 i = delegators[msg.sender].lastStateTransitionRound; i <= block.number / roundLength; i++) {
                uint256[2] rewardMultiplier = rewardMultiplierPerTranscoderAndRound[delegators[msg.sender].transcoderAddress][i];

                // Check if transcoder has a reward multiplier for this round (total minted tokens for round > 0)
                if (rewardMultiplier[0] > 0) {
                    // Calculate delegator's token reward reward multiplier
                    uint256 tokenReward = (rewardMultiplier[0] * delegators[msg.sender].bondedAmount) / rewardMultiplier[1];
                    // Calculate transcoder's share of reward
                    uint256 transcoderRewardShare = (tokenReward * transcoders[delegators[msg.sender].transcoderAddress].blockRewardCut) / 100;

                    // Update transcoder stake with transcoder share of reward
                    transcoders[delegators[msg.sender].transcoderAddress].bondedAmount = safeAdd(transcoders[delegators[msg.sender].transcoderAddress].bondedAmount, transcoderRewardShare);
                    // Update transcoder cumulative stake with delegator's total token reward (delegator's share + transcoder's share)
                    transcoderPools.increaseTranscoderStake(delegators[msg.sender].transcoderAddress, tokenReward);
                    // Update delegator stake with delegator's share of reward
                    delegators[msg.sender].bondedAmount = safeAdd(delegators[msg.sender].bondedAmount, tokenReward - transcoderRewardShare);
                }
            }

            delegators[msg.sender].lastStateTransitionRound = block.number / roundLength;
        }
        _;
    }

    // Initialize protocol
    function LivepeerProtocol(uint64 _n, uint256 _roundLength, uint256 _cyclesPerRound) {
        // Deploy new token contract
        token = new LivepeerToken();

        // Set truebit address
        truebitAddress = 0x647167a598171d06aecf0f5fa1daf3c5cc848df0;

        // Initialize parameters
        // Segment length of 2 seconds
        t = 2;

        // Start with provided number of transcoders parameter
        // Current value is for testing purposes
        n = _n;

        // Set block time to 1 second for testing purposes
        blockTime = 1;

        // Round length of ~1 day assuming ~17 second block time on main net
        // Current value is for testing purposes
        roundLength = _roundLength;
        currentRound = block.number / roundLength;

        // Transcoder expected to call reward every ~10 minutes assuming ~17 second block time on main net
        // Current value is for testing purposes
        cyclesPerRound = _cyclesPerRound;

        // Lock rate changes 2 hours before round
        rateLockDeadline = 2 hours;

        // Unbond for ~10 days assuming ~17 second block time on main net
        // Current value is for testing purposes
        unbondingPeriod = 2;

        // Keep data in storage for 6 hours
        persistenceLength = 6 hours;

        // Verify 1/500 segments
        verificationRate = 500;

        // Slash percentages
        failedVerificationSlashAmount = 5;
        missedRewardSlashAmount = 3;
        missedVerificationSlashAmount = 10;

        // Expect transcoders to be 90% competitive
        competitivenessTolerance = 90;

        // Fail no more than 1% of the time
        verificationFailureThreshold = 1;

        // Initialize transcoder pools - size of candidate pool subject to change
        transcoderPools.init(n, n);

        // Do initial token distribution - currently clearly fake, minting 3 LPT to the contract creator
        token.mint(msg.sender, 3000000000000000000);
    }

    /*
     * Computes delegator status
     * @param _delegator Address of delegator
     */
    function delegatorStatus(address _delegator) constant returns (DelegatorStatus) {
        // Check if this is an initialized delegator
        if (delegators[_delegator].initialized == false) throw;

        if (delegators[_delegator].withdrawRound > 0 ||
            (delegators[_delegator].transcoderAddress != address(0)
             && transcoders[delegators[_delegator].transcoderAddress].delegatorWithdrawRound > 0)) {
            // Delegator called unbond() or transcoder resigned
            // In unbonding phase
            return DelegatorStatus.Unbonding;
        } else if (delegators[_delegator].roundStart > block.number / roundLength) {
            // Delegator round start is in the future
            // In pending phase
            return DelegatorStatus.Pending;
        } else if (delegators[_delegator].roundStart <= block.number / roundLength) {
            // Delegator round start is now or in the past
            // In bonded phase
            return DelegatorStatus.Bonded;
        } else {
            // Delegator in inactive phase
            return DelegatorStatus.Inactive;
        }
    }

    /*
     * Checks if delegator unbonding period is over
     * @param _delegator Address of delegator
     */
    function unbondingPeriodOver(address _delegator) constant returns (bool) {
        // Check if this is an initialized delegator
        if (delegators[_delegator].initialized == false) throw;

        if (delegators[_delegator].withdrawRound > 0) {
            // Delegator called unbond()
            return block.number / roundLength >= delegators[_delegator].withdrawRound;
        } else if (delegators[_delegator].transcoderAddress != address(0)
                   && transcoders[delegators[_delegator].transcoderAddress].delegatorWithdrawRound > 0) {
            // Transcoder resigned
            return block.number / roundLength >= transcoders[delegators[_delegator].transcoderAddress].delegatorWithdrawRound;
        } else {
            // Delegator not in unbonding state
            return false;
        }
    }

    /**
     * Delegate stake towards a specific address.
     * @param _amount The amount of LPT to stake.
     * @param _to The address of the transcoder to stake towards.
     */
    function bond(uint _amount, address _to) updateStakesWithRewards returns (bool) {
        // Check if this is a valid transcoder who is active
        if (transcoders[_to].active == false) throw;

        if (_amount > 0) {
            // Only transfer tokens if _amount is greater than 0
            // Transfer the token. This call throws if it fails.
            token.transferFrom(msg.sender, this, _amount);
        }

        // Amount to be staked to transcoder
        uint256 stakeForTranscoder = _amount;

        if (transcoders[msg.sender].active == true && _to == msg.sender) {
            // Sender is a registered transcoder and is delegating to self
            transcoders[msg.sender].bondedAmount = safeAdd(transcoders[msg.sender].bondedAmount, _amount);
        } else {
            // Sender is not a registered transcoder
            // Update or create this delegator
            Delegator del = delegators[msg.sender];

            if (del.initialized == false ||
                (del.transcoderAddress != address(0) && transcoders[del.transcoderAddress].active == false)) {
                // Set round start if creating delegator for first time or if
                // delegator was bonded to an inactive transcoder
                del.roundStart = (block.number / roundLength) + 1;
            }

            if (del.transcoderAddress != address(0) && _to != del.transcoderAddress) {
                // Delegator is moving bond
                // Set round start if delegator moves bond to another active transcoder
                del.roundStart = (block.number / roundLength) + 1;
                // Decrease former transcoder cumulative stake
                transcoderPools.decreaseTranscoderStake(del.transcoderAddress, del.bondedAmount);
                // Stake amount includes delegator's total bonded amount since delegator is moving its bond
                stakeForTranscoder = safeAdd(stakeForTranscoder, del.bondedAmount);
            }

            del.delegatorAddress = msg.sender;
            del.transcoderAddress = _to;
            del.bondedAmount = safeAdd(del.bondedAmount, _amount);
            del.withdrawRound = 0;
            del.initialized = true;
            delegators[msg.sender] = del;

        }

        if (transcoderPools.isInPools(_to)) {
            // Target transcoder is in a pool
            // Increase transcoder cumulative stake
            transcoderPools.increaseTranscoderStake(_to, stakeForTranscoder);
        } else {
            // Target transcoder is not in a pool
            // Add transcoder
            transcoderPools.addTranscoder(_to, stakeForTranscoder);
        }

        return true;
    }

    /**
     * Unbond your current stake. This will enter the unbonding phase for
     * the unbondingPeriod.
     */
    function unbond() updateStakesWithRewards returns (bool) {
        // Check if this is an initialized delegator
        if (delegators[msg.sender].initialized == false) throw;
        // Check if delegator is in bonded status
        if (delegatorStatus(msg.sender) != DelegatorStatus.Bonded) throw;

        // Transition to unbonding phase
        delegators[msg.sender].withdrawRound = safeAdd(block.number / roundLength, unbondingPeriod);

        // Decrease transcoder cumulative stake
        transcoderPools.decreaseTranscoderStake(delegators[msg.sender].transcoderAddress, delegators[msg.sender].bondedAmount);

        return true;
    }

    /**
     * Withdraws withdrawable funds back to the caller after unbonding period.
     */
    function withdraw() returns (bool) {
        // Check if this is an initialized delegator
        if (delegators[msg.sender].initialized == false) throw;
         // Check if delegator is in unbonding phase
        if (delegatorStatus(msg.sender) != DelegatorStatus.Unbonding) throw;
        // Check if delegator's unbonding period is over
        if (!unbondingPeriodOver(msg.sender)) throw;

        // Transfer token. This call throws if it fails.
        token.transfer(msg.sender, delegators[msg.sender].bondedAmount);

        // Delete delegator
        delete delegators[msg.sender];

        return true;
    }

    /**
     * Active transcoders call this once per cycle when it is their turn.
     * Distribute the token rewards to transcoder and delegates.
     */
    function reward() returns (bool) {
        // Check if in current round active transcoder set
        if (!isCurrentActiveTranscoder[msg.sender]) throw;

        // Check if already called for current cycle
        if (transcoders[msg.sender].rewardRound == block.number / roundLength && transcoders[msg.sender].rewardCycle == cycleNum()) throw;

        // Check if in a valid transcoder reward time window
        if (!validRewardTimeWindow(msg.sender)) throw;

        // Set last round that transcoder called reward()
        transcoders[msg.sender].rewardRound = block.number / roundLength;
        // Set last cycle of last round that transcoder called reward()
        transcoders[msg.sender].rewardCycle = cycleNum();

        // Reward calculation
        // Calculate number of tokens to mint
        uint256 mintedTokens = mintedTokensPerReward();
        // Mint token reward and allocate to this protocol contract
        token.mint(this, mintedTokens);
        // Add minted tokens for the current cycle of the current round to reward multipler numerator
        uint256[2] rewardMultiplier = rewardMultiplierPerTranscoderAndRound[msg.sender][block.number / roundLength];
        rewardMultiplier[0] = safeAdd(rewardMultiplier[0], mintedTokens);

        if (cycleNum() == 0 || rewardMultiplier[1] == 0) {
            // First cycle of current round or reward multiplier denominator has not been set yet
            // Set transcoder cumulative stake for current round as denominator of reward multiplier for current round
            rewardMultiplier[1] = currentActiveTranscoders[currentActiveTranscoderPositions[msg.sender]].key;
        }

        rewardMultiplierPerTranscoderAndRound[msg.sender][block.number / roundLength] = rewardMultiplier;

        return true;
    }

    function mintedTokensPerReward() constant returns (uint256) {
        uint256 rewardsPerYear = ((365 * 24 * 60 * 60) / blockTime / roundLength) * cyclesPerRound * n;
        return ((initialTokenSupply * initialYearlyInflation) / 100) / rewardsPerYear;
    }

    /**
     * The sender is declaring themselves as a candidate for active transcoding.
     */
    function transcoder(uint8 _blockRewardCut) returns (bool) {
        Transcoder t = transcoders[msg.sender];
        t.transcoderAddress = msg.sender;
        t.delegatorWithdrawRound = 0;
        t.rewardRound = 0;
        t.rewardCycle = 0;
        t.blockRewardCut = _blockRewardCut;
        t.active = true;
        transcoders[msg.sender] = t;

        return true;
    }

    /*
     * Remove the sender as a transcoder
     */
    function resignAsTranscoder() returns (bool) {
        // Check if active transcoder
        if (transcoders[msg.sender].active == false) throw;

        // Go inactive
        transcoders[msg.sender].active = false;
        // Set withdraw round for delegators
        transcoders[msg.sender].delegatorWithdrawRound = safeAdd(block.number / roundLength, unbondingPeriod);
        // Zero out bonded amount
        transcoders[msg.sender].bondedAmount = 0;
        // Remove transcoder from pools
        transcoderPools.removeTranscoder(msg.sender);
    }

    /*
     * Checks if a transcoder is in active pool
     * @param _transcoder Address of transcoder
     */
    function isActiveTranscoder(address _transcoder) constant returns (bool) {
        return transcoderPools.activeTranscoders.ids[_transcoder];
    }

    /*
     * Checks if a transcoder is in candidate pool
     * @param _transcoder Address of transcoder
     */
    function isCandidateTranscoder(address _transcoder) constant returns (bool) {
        return transcoderPools.candidateTranscoders.ids[_transcoder];
    }

    /**
     * Called once at the start of any round
     */
    function initializeRound() returns (bool) {
        // Check if already called for the current round
        // Will exit here to avoid large gas consumption if it has been called for the current round already
        if (currentRound == block.number / roundLength) return false;
        // Set the current round
        currentRound = block.number / roundLength;

        // Set current round active transcoders
        setCurrentActiveTranscoders();

        return true;
    }

    /*
     * Set current active transcoder set for the current round
     */
    function setCurrentActiveTranscoders() internal returns (bool) {
        if (currentActiveTranscoders.length != transcoderPools.activeTranscoders.nodes.length) {
            // Set length of array if it has not already been set
            currentActiveTranscoders.length = transcoderPools.activeTranscoders.nodes.length;
        }

        for (uint256 i = 0; i < transcoderPools.activeTranscoders.nodes.length; i++) {
            if (currentActiveTranscoders[i].initialized) {
                // Set address of old node to not be present in current active transcoder set
                isCurrentActiveTranscoder[currentActiveTranscoders[i].id] = false;
            }
            // Copy node
            currentActiveTranscoders[i] = transcoderPools.activeTranscoders.nodes[i];
            // Set address of node to be present in current active transcoder set
            isCurrentActiveTranscoder[currentActiveTranscoders[i].id] = true;
            // Set index position of node in current active transcoder set
            currentActiveTranscoderPositions[currentActiveTranscoders[i].id] = i;
        }

        return true;
    }

    /*
     * Pseudorandomly elect an active transcoder. Currently a placeholder
     * TODO: take into account pricing, etc.
     */
    function electCurrentActiveTranscoder() constant returns (address) {
        return currentActiveTranscoders[uint(block.blockhash(block.number - 1)) % currentActiveTranscoders.length].id;
    }

    /*
     * Return start block of current round
     */
    function currentRoundStartBlock() constant returns (uint256) {
        return (block.number / roundLength) * roundLength;
    }

    /*
     * Return length in blocks of a time window for calling reward()
     */
    function rewardTimeWindowLength() constant returns (uint256) {
        return roundLength / (n * cyclesPerRound);
    }

    /*
     * Return length in blocks of a cycle
     */
    function cycleLength() constant returns (uint256) {
        return rewardTimeWindowLength() * n;
    }

    /*
     * Return number of cycles since the start of the round
     */
    function cycleNum() constant returns (uint256) {
        return (block.number - currentRoundStartBlock()) / cycleLength();
    }

    /*
     * Checks if a transcoder is calling reward() in the correct range of blocks
     * for its time window
     * @param _transcoder Address of transcoder
     */
    function validRewardTimeWindow(address _transcoder) internal returns (bool) {
        // Check if transcoder is present in current active transcoder set
        if (!isCurrentActiveTranscoder[_transcoder]) throw;

        // Use index position of address in current active transcoder set as its place in the order for calling reward()
        uint256 transcoderIdx = currentActiveTranscoderPositions[_transcoder];

        // Compute start block of reward time window for this cycle
        uint256 rewardTimeWindowStartBlock = currentRoundStartBlock() + (cycleNum() * cycleLength()) + (transcoderIdx * rewardTimeWindowLength());
        // Compute end block of reward time window for this cycle
        uint256 rewardTimeWindowEndBlock = rewardTimeWindowStartBlock + rewardTimeWindowLength();

        return block.number >= rewardTimeWindowStartBlock && block.number < rewardTimeWindowEndBlock;
    }

    /*
     * Returns cumulative stake for a transcoder
     * @param _transcoder Address of transcoder
     */
    function transcoderStake(address _transcoder) constant returns (uint256) {
        return transcoderPools.transcoderStake(_transcoder);
    }
}


adding notes

adding notes

pragma solidity ^0.4.0;

// TODO BUILD TEST!
library MathLib {

    function multiply(uint256 a, uint256 b) internal constant returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }

    function subtract(uint256 a, uint256 b) internal constant returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) internal constant returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }

    function sign(int a) internal constant returns (int8) {
        if(a > 0) {
            return 1;
        } else if (a < 0) {
            return -1;
        }
        return 0;
    }

    function isSameSign(int a, int b) internal constant returns (bool) {
        return ( a == b || a * b > 0);
    }

}

pragma solidity ^0.4.0;

library MathLib {

    function multiply(uint256 a, uint256 b) internal constant returns (uint256) {
        uint256 c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }

    function subtract(uint256 a, uint256 b) internal constant returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    function add(uint256 a, uint256 b) internal constant returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }

    function sign(int a) internal constant returns (int8) {
        if(a > 0) {
            return 1;
        } else if (a < 0) {
            return -1;
        }
        return 0;
    }

    function isSameSign(int a, int b) internal constant returns (bool) {
        return ( a == b || a * b > 0);
    }

}


fix ERC20.sol#L174 and ERC20.sol#L187 should be casted to an address type. (#1470)

pragma solidity ^0.4.24;

import "./IERC20.sol";
import "../../math/SafeMath.sol";

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
 * Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract ERC20 is IERC20 {
  using SafeMath for uint256;

  mapping (address => uint256) private _balances;

  mapping (address => mapping (address => uint256)) private _allowed;

  uint256 private _totalSupply;

  /**
  * @dev Total number of tokens in existence
  */
  function totalSupply() public view returns (uint256) {
    return _totalSupply;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param owner The address to query the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address owner) public view returns (uint256) {
    return _balances[owner];
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param owner address The address which owns the funds.
   * @param spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(
    address owner,
    address spender
   )
    public
    view
    returns (uint256)
  {
    return _allowed[owner][spender];
  }

  /**
  * @dev Transfer token for a specified address
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function transfer(address to, uint256 value) public returns (bool) {
    _transfer(msg.sender, to, value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param spender The address which will spend the funds.
   * @param value The amount of tokens to be spent.
   */
  function approve(address spender, uint256 value) public returns (bool) {
    require(spender != address(0));

    _allowed[msg.sender][spender] = value;
    emit Approval(msg.sender, spender, value);
    return true;
  }

  /**
   * @dev Transfer tokens from one address to another
   * @param from address The address which you want to send tokens from
   * @param to address The address which you want to transfer to
   * @param value uint256 the amount of tokens to be transferred
   */
  function transferFrom(
    address from,
    address to,
    uint256 value
  )
    public
    returns (bool)
  {
    require(value <= _allowed[from][msg.sender]);

    _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
    _transfer(from, to, value);
    return true;
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param addedValue The amount of tokens to increase the allowance by.
   */
  function increaseAllowance(
    address spender,
    uint256 addedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].add(addedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseAllowance(
    address spender,
    uint256 subtractedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].sub(subtractedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
  * @dev Transfer token for a specified addresses
  * @param from The address to transfer from.
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function _transfer(address from, address to, uint256 value) internal {
    require(value <= _balances[from]);
    require(to != address(0));

    _balances[from] = _balances[from].sub(value);
    _balances[to] = _balances[to].add(value);
    emit Transfer(from, to, value);
  }

  /**
   * @dev Internal function that mints an amount of the token and assigns it to
   * an account. This encapsulates the modification of balances such that the
   * proper events are emitted.
   * @param account The account that will receive the created tokens.
   * @param value The amount that will be created.
   */
  function _mint(address account, uint256 value) internal {
    require(account != address(0));
    _totalSupply = _totalSupply.add(value);
    _balances[account] = _balances[account].add(value);
    emit Transfer(address(0), account, value);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account.
   * @param account The account whose tokens will be burnt.
   * @param value The amount that will be burnt.
   */
  function _burn(address account, uint256 value) internal {
    require(account != address(0));
    require(value <= _balances[account]);

    _totalSupply = _totalSupply.sub(value);
    _balances[account] = _balances[account].sub(value);
    emit Transfer(account, address(0), value);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account, deducting from the sender's allowance for said account. Uses the
   * internal burn function.
   * @param account The account whose tokens will be burnt.
   * @param value The amount that will be burnt.
   */
  function _burnFrom(address account, uint256 value) internal {
    require(value <= _allowed[account][msg.sender]);

    // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
    // this function needs to emit an event with the updated approval.
    _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(
      value);
    _burn(account, value);
  }
}

pragma solidity ^0.4.24;

import "./IERC20.sol";
import "../../math/SafeMath.sol";

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
 * Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract ERC20 is IERC20 {
  using SafeMath for uint256;

  mapping (address => uint256) private _balances;

  mapping (address => mapping (address => uint256)) private _allowed;

  uint256 private _totalSupply;

  /**
  * @dev Total number of tokens in existence
  */
  function totalSupply() public view returns (uint256) {
    return _totalSupply;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param owner The address to query the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address owner) public view returns (uint256) {
    return _balances[owner];
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param owner address The address which owns the funds.
   * @param spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(
    address owner,
    address spender
   )
    public
    view
    returns (uint256)
  {
    return _allowed[owner][spender];
  }

  /**
  * @dev Transfer token for a specified address
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function transfer(address to, uint256 value) public returns (bool) {
    _transfer(msg.sender, to, value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param spender The address which will spend the funds.
   * @param value The amount of tokens to be spent.
   */
  function approve(address spender, uint256 value) public returns (bool) {
    require(spender != address(0));

    _allowed[msg.sender][spender] = value;
    emit Approval(msg.sender, spender, value);
    return true;
  }

  /**
   * @dev Transfer tokens from one address to another
   * @param from address The address which you want to send tokens from
   * @param to address The address which you want to transfer to
   * @param value uint256 the amount of tokens to be transferred
   */
  function transferFrom(
    address from,
    address to,
    uint256 value
  )
    public
    returns (bool)
  {
    require(value <= _allowed[from][msg.sender]);

    _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
    _transfer(from, to, value);
    return true;
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param addedValue The amount of tokens to increase the allowance by.
   */
  function increaseAllowance(
    address spender,
    uint256 addedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].add(addedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseAllowance(
    address spender,
    uint256 subtractedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].sub(subtractedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
  * @dev Transfer token for a specified addresses
  * @param from The address to transfer from.
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function _transfer(address from, address to, uint256 value) internal {
    require(value <= _balances[from]);
    require(to != address(0));

    _balances[from] = _balances[from].sub(value);
    _balances[to] = _balances[to].add(value);
    emit Transfer(from, to, value);
  }

  /**
   * @dev Internal function that mints an amount of the token and assigns it to
   * an account. This encapsulates the modification of balances such that the
   * proper events are emitted.
   * @param account The account that will receive the created tokens.
   * @param value The amount that will be created.
   */
  function _mint(address account, uint256 value) internal {
    require(account != 0);
    _totalSupply = _totalSupply.add(value);
    _balances[account] = _balances[account].add(value);
    emit Transfer(address(0), account, value);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account.
   * @param account The account whose tokens will be burnt.
   * @param value The amount that will be burnt.
   */
  function _burn(address account, uint256 value) internal {
    require(account != 0);
    require(value <= _balances[account]);

    _totalSupply = _totalSupply.sub(value);
    _balances[account] = _balances[account].sub(value);
    emit Transfer(account, address(0), value);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account, deducting from the sender's allowance for said account. Uses the
   * internal burn function.
   * @param account The account whose tokens will be burnt.
   * @param value The amount that will be burnt.
   */
  function _burnFrom(address account, uint256 value) internal {
    require(value <= _allowed[account][msg.sender]);

    // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
    // this function needs to emit an event with the updated approval.
    _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(
      value);
    _burn(account, value);
  }
}


Adding initial ballot solidity contract file


Improve wording of recommendation in Initializable

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be used in certain kinds of exploits since it may allow an attacker to take control of
 * the contract. This includes the implementation contract behind a proxy. You can either invoke the initializer
 * manually, independently of initialization of the proxy, or you can include a constructor to automatically mark it as
 * initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}