BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

`cancelParticipation` Leaves Stale Winner Data

Description

  • After cancellation, a user should not contribute any shares to the winner denominator.

  • cancelParticipation burns shares but leaves the address inside usersAddress and keeps userSharesToCountry populated.

// src/briVault.sol:275-289
function cancelParticipation() public {
...
uint256 shares = balanceOf(msg.sender);
@> _burn(msg.sender, shares); // user still tracked elsewhere
IERC20(asset()).safeTransfer(msg.sender, refundAmount);
}

Risk

Likelihood:

  • Anyone cancelling before the event will encounter this bug; cancellations are expected behavior.

  • Multiple cancellations accumulate stale data over time.

Impact:

  • totalWinnerShares includes cancelled users, so real winners receive less.

  • Locked funds remain in the vault with no withdrawal path.

Proof of Concept

alice.deposit(...); alice.joinEvent(1);
bob.deposit(...); bob.joinEvent(1);
bob.cancelParticipation();
owner.setWinner(1);
// totalWinnerShares still includes bob’s shares
alice.withdraw(); // Receives roughly half instead of the full pool

Recommended Mitigation

+ mapping(address => uint256) private userIndex;
function joinEvent(uint256 countryId) public {
...
+ userIndex[msg.sender] = usersAddress.length;
usersAddress.push(msg.sender);
}
function cancelParticipation() public {
...
+ uint256 i = userIndex[msg.sender];
+ uint256 last = usersAddress.length - 1;
+ if (i != last) {
+ address swap = usersAddress[last];
+ usersAddress[i] = swap;
+ userIndex[swap] = i;
+ }
+ usersAddress.pop();
+ delete userIndex[msg.sender];
+ delete userToCountry[msg.sender];
+ for (uint256 j; j < teams.length; j++) {
+ delete userSharesToCountry[msg.sender][j];
+ }
+ hasJoinedEvent[msg.sender] = false;
}
Updates

Appeal created

bryanconquer Lead Judge 16 days ago
Submission Judgement Published
Validated
Assigned finding tags:

`cancelParticipation` Leaves Stale Winner Data

CancelParticipation burns shares but leaves the address inside usersAddress and keeps userSharesToCountry populated.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!