Manipulation of governance voting result deviating from voted outcome and resulting in a direct change from intended effect of original results
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
There is an infinite mint vulnerability for the FLUX token using the poke functionality of the Voter contract.
Vulnerability Details
In the _vote function of the Voter contract, it calls into FLUX.accrueFlux, which increases the user's unclaimed FLUX balance from the VotingEscrow balance. It later calls FLUX.updateFlux to decrease it, but only with the amount of boost, which can simply be 0:
function _vote(uint256 _tokenId, address[] memory _poolVote, uint256[] memory _weights, uint256 _boost) internal {
_;
IFluxToken(FLUX).accrueFlux(_tokenId);
_;
// Update flux balance of token if boost was used
if (_boost > 0) {
IFluxToken(FLUX).updateFlux(_tokenId, _boost);
}
}
The function FLUX.accrueFlux increases the balance using VotingEscrow.claimableFlux(tokenId), which is a view function and stays the same depending on the amount and lock duration of the token ID:
VotingEscrow.claimableFlux does not depend on the amount of unclaimed FLUX in FluxToken for the user, and so the value returned from claimableFlux remains the same.
One can therefore simply call Voter.poke() over and over again, as this calls FluxToken.accrueFlux each time and uses a boost of 0. The user's unclaimedFlux in FluxToken would grow with the entire balance each time.
The user can then call FluxToken.claimFlux to turn the unclaimed FLUX into real ERC20 tokens that can be traded.
Impact Details
The impact is an infinite mint of FLUX. This is a critical impact to not only the governance process (since FLUX can be used to boost), but also to the market and TVL of FLUX.
The vulnerability can be exploited by anyone and in the time frame of the same transaction.