There is no revert statement in Voter.sol::poke for first time callers resulting in loss of yield for the epoch
Vulnerability Details
Note - For Immunefi Triage - Do not close this , if you have any doubt then directly ask me through comments, as the boost period is ending it would not be great for this to get closed. It is a legitimate issue, I request you to read the report and POC carefully. Thanks!
The Voter.sol::poke function doesn't revert when _poolCnt = 0 (_poolVote.length = 0), i.e for first time voters.
functionpoke(uint256_tokenId) public {// Previous boost will be taken into account with weights being pulled from the votes mappinguint256 _boost =0;if (msg.sender != admin) {require(IVotingEscrow(veALCX).isApprovedOrOwner(msg.sender, _tokenId),"not approved or owner"); }address[] memory _poolVote = poolVote[_tokenId];@>uint256 _poolCnt = _poolVote.length; //Ideally should revert if 0uint256[] memory _weights =newuint256[](_poolCnt);for (uint256 i =0; i < _poolCnt; i++) { _weights[i] = votes[_tokenId][_poolVote[i]]; }_vote(_tokenId, _poolVote, _weights, _boost); }
So, if a first time voter calls poke function then he will be marked as voted without even voting for anyone because of empty poolVote[_tokenId] array. This will prevent him from getting any yield. The situation becomes even worse because he can't even call vote function also because of onlyNewEpoch modifier.
functionvote(uint256_tokenId,address[] calldata_poolVote,uint256[] calldata_weights,uint256_boost ) externalonlyNewEpoch(_tokenId) { //onlyNewEpoch modifier restricts the user from using this function
He will only be able to vote in the next epoch and all his yield will be lost permanently. This can easily be prevented with a revert statement.
Impact Details
User will lose his yield for the entire epoch.
Recommendation / Suggestion
Modify the function as follows
function poke(uint256 _tokenId) public { // Previous boost will be taken into account with weights being pulled from the votes mapping uint256 _boost = 0; if (msg.sender != admin) { require(IVotingEscrow(veALCX).isApprovedOrOwner(msg.sender, _tokenId), "not approved or owner"); } address[] memory _poolVote = poolVote[_tokenId]; uint256 _poolCnt = _poolVote.length;+ require(_poolCnt > 0, "Vote first" ); uint256[] memory _weights = new uint256[](_poolCnt); for (uint256 i = 0; i < _poolCnt; i++) { _weights[i] = votes[_tokenId][_poolVote[i]]; } _vote(_tokenId, _poolVote, _weights, _boost); }