SIP-152: Spartan Council Dilution Bug


Simple Summary

This SIP proposes to fix up a bug identified in the contracts introduced by SIP-104 "Spartan Council Dilution", in the current contracts, when a new election is logged, dApps are unable to access historical election data.


This proposal will redeploy the fixed version of Synthetix: Spartan Council Dilution which will allow dApps to access previous election data, especially when dealing with SIPs/SCCPs voted on by ex-council members.


For the Spartan Council Dilution contract to work successfully, it needs to show the correct dilution weight NOT only for current proposals created within the election epoch but for proposals made in previous election epochs.



This SIP documents the changes made to the contract that will solve this issue. Although it is a small code change, this SIP aims to track the context of Spartan Council Dilution changes.


After the first election epoch concluded, the Staking dApp's ( governance page was experiencing troubles loading up the SIP/SCCP previous created. Upon investigation, it was found that the contract had some incorrect logic in one of the non-mutative functions. Since this is an error that can cause issues later if not fixed, I propose to fix this function.

Since historical data such as the number of votes of a council member, is stored in the contract via ElectionLog, the most simple and effective way to get previous data was to map ProposalLog to the electionHash of the election epoch that was active when the proposal was created. This then allows the view function to access historical voting data.

Technical Specification

The failing line in the non-mutative function called getDilutedWeightForProposal would not return the weight if the councilMember passed in was not a current council member anymore

function getDilutedWeightForProposal(string memory proposalHash, address councilMember) public view returns (uint) {
            "address must be a nominated council member"

The proposed fixes

  • Adding the electionHash when a proposal is created so we can access the election epoch in which a proposal was created within
    struct ProposalLog {
        // @notice The ipfs hash of a particular SCCP/SIP proposal
        string proposalHash;
        // @notice The election hash of the current epoch when the proposal was made
        string electionHash;
        //  @notice The timestamp which the voting period begins
        uint start;
        // @notice The timestamp which the voting period of the proposal ends
        uint end;
        // @notice A boolean value to check whether a proposal log exists
        bool exist;

  • Adding in the latestElectionHash on proposal creation
    ProposalLog memory newProposalLog = ProposalLog(proposalHash, latestElectionHash, start, end, true);
  • Modifiying the view function
    function getDilutedWeightForProposal(string memory proposalHash, address councilMember) public view returns (uint) {
        require(proposalHashToLog[proposalHash].exist, "proposal does not exist");

        string memory electionHash = proposalHashToLog[proposalHash].electionHash;

        require(electionHashToLog[electionHash].councilMembers[councilMember], "address must be a nominated council member");

        uint originalWeight = electionHashToLog[electionHash].votesForMember[councilMember];
        uint penaltyValue = proposalHashToMemberDilution[proposalHash][councilMember].totalDilutionValue;

        return (originalWeight - penaltyValue).divideDecimal(originalWeight);

Test Cases

Case 1:

  1. Create an election
  2. Create a proposal
  3. Dilute the current council members
  4. Get the diluted weight of the current council members
  5. Log a new election with new council members
  6. Get the diluted weight of the previous council members
  7. Values 4. and 6. should equal and be accessible

Configurable Values (Via SCCP)

Copyright and related rights waived via CC0.