EGP #001 Update to VoteCheckpoints

Eco Governance Proposal #001

This post briefly summarizes the Eco Governance Proposal submitted on Nov 13th, 2022 and enacted on Nov 17th, 2022 during the second Eco Generation. Due to the details of the vulnerabilities, this post was published after the proposal had already been enacted.


Two bugs were discovered through Immunefi bug bounty submissions:

  1. When using delegateAmount on an attacker address who has (or later sets) a primary delegate, the attacker could self transfer to cause the voting power given by delegateAmount to be transferred to the primary delegate. This not only violated the principles of delegation, but disallowed the victim from calling undelegate in any form, leaving the amount untransferable. The offending code was in _afterTokenTransfer in VoteCheckpoints.sol which used _balances[from] + amount to calculate the pre-transfer balance of from.

This issue was fixed by an early exit of _afterTokenTransfer on self transfers as there would be no need to re-calculate delegation. We acknowledge that this would allow a user to self transfer funds that would not be transferrable to any other address (in the case of them being locked by using delegateAmount), but would have no further effect on the system.

  1. If an attacker is able to atomically call the incrementGeneration call, they would have access to the new clone of PolicyProposals.sol for that generation in a block that was equal to blockNumber where the voting power is measured. This would allow the user to submit a proposal, support it, transfer tokens to another address, and then support it again with the same tokens. This process could be extended as far as gas and contract size limits would allow for the sandwich transaction. This attack is detailed in the test contract InfiniteVote.sol.

This issue was fixed by restricting the voting calculation. Two offending functions created this vulnerability: getPastVotingGons and getPastTotalSupply. These functions are used in VotingPower.sol to determine voting power during the community governance process. They were changed to respect their respective names and require the block submitted to be strictly before the current block. This means that any attempts to perform the exploit above will fail in the calculation of the addresses’s voting power. If someone did want to see voting power for the current block, they could use getVotingGons or totalSupply. Note that getPastLinearInflation was not changed in this update, as it did not have a corresponding function for the current block and therefore is used in a number of places to access the amount of linear inflation in the current block.

Additionally the ECOxStaking contract was proxied to allow for easy upgradeability.

Status: Resolved :white_check_mark:

These issues were addressed in generation 1002 via the proposal VoteCheckpointsUpgrade.propo.sol whose deployment can be found here . The PR for updating the codebase with this fix can be found here. The proposal can also be seen in Eco Community Governance Interface linked here.