Omniscia Mantissa Finance Audit

MasterMantis Manual Review Findings

MasterMantis Manual Review Findings

MMS-01M: Improper Vote Management of Duplicate Entries

TypeSeverityLocation
Logical FaultMasterMantis.sol:L421-L429

Description:

The MasterMantis::vote function will improperly allow the caller to supply duplicate pid values for the votes they perform.

Given that the second for loop within MasterMantis::vote will overwrite whatever data was present in the userVoteItem entry, it is possible to vote multiple times for the same pid retaining the duplicate votes as the userVoteItem value will be subtracted once during a vote "reset" with the last value voted.

Impact:

It is presently possible to arbitrarily inflate the totalVotes a particular pool has, compromising the voting system of MasterMantis.

Example:

contracts/MasterMantis.sol
409function vote(UserVotePayload calldata payload) external nonReentrant whenNotPaused {
410 require(payload.totalVotes <= IERC20(veMnt).balanceOf(msg.sender), "Votes too high");
411 gaugeUpdate();
412 uint256 userVotedPidsSize = userVotedPids[msg.sender].length;
413 for (uint256 i=0; i < userVotedPidsSize; i++) {
414 uint256 pid = userVotedPids[msg.sender][i];
415 poolInfo[pid].totalVotes -= userVoteItem[msg.sender][pid];
416 delete userVoteItem[msg.sender][pid];
417 }
418 delete userVotedPids[msg.sender];
419 uint256 voteAmount;
420 uint256 numPids = payload.votes.length;
421 for (uint256 i=0; i < numPids; i++) {
422 uint256 amount = payload.votes[i].amount;
423 require(amount > 0, "Cannot vote 0 amount");
424 uint256 pid = payload.votes[i].pid;
425 userVoteItem[msg.sender][pid] = amount;
426 userVotedPids[msg.sender].push(pid);
427 poolInfo[pid].totalVotes += amount;
428 voteAmount += amount;
429 }
430 require(voteAmount == payload.totalVotes, "Vote Mismatch");
431 userVoteTotal[msg.sender] = voteAmount;
432
433 emit UserVoted(msg.sender, payload);
434}

Recommendation:

We advise the MasterMantis::vote function to either disallow duplicate pid entries by ensuring that userVoteItem is 0, or to properly support duplicate entries by incrementing the userVoteItem instead of subtracting it and pushing the pid to the userVotedPids solely when userVoteItem was 0.

We consider either of those two approaches as adequate in alleviating this exhibit.

Alleviation (418ee413ad8e26f7eea383764c19953ff31b2bf3):

The code was fixed by applying the former of the two solutions proposed, ensuring that the userVoteItem entry of a pid being processed is 0 before being set to a non-zero amount and thus guaranteeing that duplicate pid values cannot be utilized when voting.