[H-5] Function:cancelParticipation only _burn shares, but the others related to shares are left unchanged
Description
In the Function:cancelParticipation user only _burn shares:
function cancelParticipation () public {
if (block.timestamp >= eventStartDate){
revert eventStarted();
}
uint256 refundAmount = stakedAsset[msg.sender];
stakedAsset[msg.sender] = 0;
uint256 shares = balanceOf(msg.sender);
@> _burn(msg.sender, shares);
IERC20(asset()).safeTransfer(msg.sender, refundAmount);
}
But if this user has joined event, Function:joinEvent update some variables related to his shares:
function joinEvent(uint256 countryId) public {
......
userToCountry[msg.sender] = teams[countryId];
uint256 participantShares = balanceOf(msg.sender);
@> userSharesToCountry[msg.sender][countryId] = participantShares;
usersAddress.push(msg.sender);
numberOfParticipants++;
@> totalParticipantShares += participantShares;
emit joinedEvent(msg.sender, countryId);
}
Impact
Assume that userA deposits some assets and attains some share,
then userA join event, if he choose countryId 0, userSharesToCountry[userA][0] = userA's shares,
after that userA cancelParticipation, his balance in briVault is burned,
but userSharesToCountry[userA][0] isn't set 0, and totalParticipantShares is also not set correctly.
Proof of Concepts
Run the test function below in test/briVault.t.sol:
*Scenario:
-user1: deposit and joinEvent
-user2: deposit, joinEvent and cancelParticipation
*Expected:
-user1 withdraw IERC20(address(mockToken)).balanceOf(address(briVault)) back
*Actual:
-user1 only withdraw half of IERC20(address(mockToken)).balanceOf(address(briVault))
*/
function test_cancelParticipation_incorrect_shares_update() public {
uint256 expected_assetToWithdraw;
vm.startPrank(user1);
mockToken.approve(address(briVault), 5 ether);
briVault.deposit(5 ether, user1);
briVault.joinEvent(0);
vm.stopPrank();
vm.startPrank(user2);
mockToken.approve(address(briVault), 5 ether);
briVault.deposit(5 ether, user2);
briVault.joinEvent(0);
briVault.cancelParticipation();
vm.stopPrank();
vm.warp(eventEndDate + 1);
vm.startPrank(owner);
briVault.setWinner(0);
expected_assetToWithdraw = IERC20(address(mockToken)).balanceOf(address(briVault));
vm.expectEmit(address(briVault));
emit BriVault.Withdraw(user1, expected_assetToWithdraw);
vm.startPrank(user1);
briVault.withdraw();
vm.stopPrank();
}
Recommended mitigation
function cancelParticipation () public {
if (block.timestamp >= eventStartDate){
revert eventStarted();
}
//q: maybe need some checks?
uint256 refundAmount = stakedAsset[msg.sender];
stakedAsset[msg.sender] = 0;
uint256 shares = balanceOf(msg.sender);
+ totalParticipantShares -= shares;
+ for (uint256 i = 0; i < teams.length; ++i) {
+ userSharesToCountry[msg.sender][i] = 0;
+ }
_burn(msg.sender, shares);
IERC20(asset()).safeTransfer(msg.sender, refundAmount);
}