Normally when a player cancels they are completely removed from the tournament and refunded their deposit (minus participation fee).
Currently, cancelled players are refunded but are still counted in the usersAddress array with stale userSharesToCountry mappings. This corrupts winner share calculations and dilutes payouts.
Likelihood:
This occurs whenever cancelParticipation() is called. The function refunds assets and burns shares
but fails to remove users from usersAddress or clear userSharesToCountry mappings. When setWinner()
calls _getWinnerShares(), it loops through usersAddress and sums
userSharesToCountry[user][winnerCountryId], including cancelled users' stale values. Every
cancellation creates ghost participants whose phantom shares inflate the payout denominator. This
occurs in normal operations without special conditions.
Impact:
Ghost shares inflate totalWinnerShares (the denominator in payout calculations), causing proportional
dilution - one cancellation among two winners yields 50% loss, ten among one hundred yields 10%
loss. Diluted funds lock permanently. Attackers can cheaply grief by creating multiple accounts,
joining the likely winner, then cancelling to dilute payouts at only gas cost.
Add this test to test/briVault.t.sol
Add these helper functions to the briVault.sol file. These helper functions expose the array metadata required for comprehensive test verification of state cleanup operations.
Run the test:
forge test --mt test_cancelledUser_doesNotAffectWinnerShares -vv
The test demonstrates that the cancelled participant remains in totalWinnerShares, causing user1 to
receive only 50% of their rightful payout (2.4625 ETH instead of 4.925 ETH). The remaining half is permanently locked in the contract. In this two-participant scenario, one cancellation
results in 50% fund loss; with more participants, the loss is proportional to the cancellation rate.
Explanation:
When a user cancels their participation, the contract should remove them from the usersAddress
array and clear their userSharesToCountry mapping. Adding the _removeUserFromArray() helper
function, invoking it within the updated cancelParticipation() function, and clearing
participant counters prevents cancelled users from remaining as ghost participants whose phantom
shares inflate totalWinnerShares, and dilute legitimate winners' payouts.
Include this helper function in the briVault.sol file. This function ensures cancelled participants are completely removed from the usersAddress array.
Update the cancelParticipation() function with the following additional lines
CancelParticipation burns shares but leaves the address inside usersAddress and keeps userSharesToCountry populated.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.