If a player is registered multiple times with different rewards, the player only receives the minimum of these rewards, with the remaining amount being redistributed. This results in a loss for the affected player while benefiting other players and the contest manager. Furthermore, if such a situation occurs, a player cannot claim their reward multiple times. Attempting to call claimCut twice by the same player results in a Pot__RewardNotFound() revert.
The vulnerability primarily lies in the following line of code:
Here, the claimCut function lacks a check for address duplication when assigning rewards to a player. As a result, in cases of duplicated addresses, the player receives only the minimum reward assigned to them.
Additionally, consider the following line of code:
https://github.com/Cyfrin/2024-08-MyCut/blob/946231db0fe717039429a11706717be568d03b54/src/Pot.sol#L43
In this line, the reward corresponding to a player is set to zero in the playersToRewards map. Consequently, if a player with a duplicated address has already claimed their reward once, any remaining rewards under their name are set to zero in the map. If they attempt to call the claimCut function again, the transaction reverts, as seen in the following if statement:
To demonstrate this vulnerability, I modified the players and rewards arrays as follows:
Technically, player1 should receive 300+200=500ETH if claimed within 90 days, while player2 should receive 100 ETH.
However, to test the actual behavior, I created the following testDuplicacy function:
In this test, I attempted to call the claimCut function twice for player1, but it resulted in a revert:
Next, I modified the testDuplicacy() function:
This resulted in the following output:
The test demonstrates that player1 is able to claim only once and therefore receives the minimum of the two rewards associated with it's address 200 ETH, while player2 receives their 100 ETH. The remaining 300 ETH is distributed among the players , ContestManagerand the contest contract as shown:-
Loss of ETH for player1
Gain in ETH for ContestManager and other players
Significant amount of ETH remains in the contest contract which neither goes to the players nor to the Contest Manager.
Manual Analysis
Implement a duplicate address check in the claimCut() function to prevent this vulnerability.
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.