In a rap battle, if the challenger doesn't approve credibility tokens to the RapBattle contract, the battle reverts if the defender is picked as the winner. However, if the challenger wins, he/she gets the credibility token bet placed by the defender. The challenger may enter the battle over and over again until he/she wins. This is a serious disruption of what the protocol intends to achieve.
The defender enters the battle by calling RapBattle::goOnStageOrBattle
, transferring his/her rapper tokenId, and credibility token bet to the RapBattle contract. When a challenger enters next, he/she doesn't need to transfer his/her credibility token bet to the RapBattle contract. This allows the challenger to enter a rap battle without approving credibility tokens to the RapBattle contract. If the defender is picked as the winner, the defender never gets the part of credibility token bet from the challenger, because the transaction reverts. This is because the challenger never approved credibility tokens to the contract, so the following line fails in RapBattle::_battle
function:
The challenger can keep calling RapBattle::goOnStageOrBattle
over and over again, until he/she wins and receives the defender's credibility token bet.
The challenger is guaranteed a win if he/she enters the battle over and over again without approving credibility token bet to the RapBattle contract. This also means that the challenger can enter rap battle without having any credibility tokens whatsoever. The rappers who enter the battle first are doomed to lose their credibility tokens with this exploit.
Defender enters the rap battle by approving his/her rapper tokenId and credibility token bet to the RapBattle contract. The RapBattle contract transfers the tokenId and credibility token bet to itself.
The challenger enters the battle with his/her tokenId, and without approving any credibility tokens to the RapBattle contract. It is also possible that the challenger doesn't have any credibility tokens at all.
If the defender wins, the transaction reverts because the contract failed to transfer tokens from challenger to the defender.
If the challenger wins, he/she gets the credibility token bet placed by the defender.
Add the following function to your test contract in your Foundry test file.
With the randomized time and difficulty in the fuzz test, the challenger was able to successfully win 210 times (using the seed "0x1"). The fuzz test reverted after 210 runs when the defender actually won, and the contract failed to transfer the credibility token bet from the challenger to the defender.
Foundry, VSCodium.
When the challenger goes to battle, the RapBattle::goOnStageOrBattle
function should transfer the credibility token bet from the challenger to the contract. Only then the random winner should be picked.
Or, the RapBattle::goOnStageOrBattle
function should check if the challenger has approved credibility token bet to the contract before picking a random winner.
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.