The RapBattle::goOnStageOrBattle
function allows the second participant in the battle (challenger
) to participate in the battle with non-existence or someone else's tokenId
.
The RapBattle::goOnStageOrBattle
function allows users to battle their Rappers. The function doesn't check if the input argument _tokenId
is a valid ID. If the defender
calls the function with invalid _tokenId
the oneShotNft.transferFrom
function will revert and the transaction will fail. But if a defender
is waiting for a battle and challenger
calls the function with invalid or someone else's _tokenId
, the function will call the internal _battle
function with this _tokenId
as first argument.
The RapBattle::_battle
function also doesn't check the existence and the ownership of the _tokenId
:
The RapBattle::_battle
function calls the RapBattle::getRapperSkill
function with argument _tokenId
to retrive the rapper skills of the defender
and challenger
.
The RapBattle::getRapperSkill
function also doesn't check the validity of the input argument _tokenId
:
The RapBattle::getRapperSkill
function calls the OneShot::getRapperStats
to retrieve the RapperStats
for a given _tokenId
.
We see that the OneShot::getRapperStats
function also doesn't perform a check if the input argument tokenId
is valid. If the tokenId
is non-existing token, the function will return the default values for rapperStats
: RapperStats({weakKnees: false, heavyArms: false, spaghettiSweater: false, calmAndReady: false, battlesWon: 0});
Then the RapBattle::getRapperSkill
function will return finalSkill = BASE_SKILL;
which is 65
. So the challenger
who provided invalid _tokenId
will have challengerRapperSkill
equals to 65
.
The challenger
is the second person of the battle. The challenger
doesn't transfer the rapper token to the RapBattle
contract. And the existence or ownership of the provided tokenId
from challenger
is not checked in the RapBattle::goOnStageOrBattle
function. Therefore, the challenger
can participate in a battle with non-existing token or with tokenId
of someone else. In both cases the challenger
can win the battle and receive the _credBet
without actually to have rapper token.
Let's consider the following scenario: There is user
(Alice) who has minted a rapper token and calls the RapBattle::goOnStageOrBattle
function to participate in a battle. Now the user is waiting for opponent. The challenger
(Slim Shady) calls also the RapBattle::goOnStageOrBattle
function with non-existing tokenId
as first argument. There is no check for that and the battle begins. His rapperSkill
is 65
. The test function testGoOnStageOrBattleOpponentWithNonExistingTokenId
shows the described scenario:
After the execution of the test function we can see that the challenger
has won the battle and received the _credBet
in this example 0
. Here is part of the traces. You can execute the test function using the foundry command:
forge test --match-test "testGoOnStageOrBattleOpponentWithNonExistingTokenId" -vvvvv
Now, let's consider the second scenario: There is user
(Alice) who has minted a rapper token and staked it for 4 days. So the user
has updated rapperStats
and 4 Cred
. Bob
has done the same thing. He also has updated rapperStats
and 4 Cred
. Bob's tokenId
is 1
. Bob calls RapBattle::goOnStageOrBattle
function with his tokenId
and _credBet
equals to 1
. Now Bob is waiting for opponent. Challenger
(Slim Shady) calls the RapBattle::goOnStageOrBattle
function with user's tokenId
and _credBet
equals to 1
. There is no check if the challenger
is the owner of the tokenId
and the battle begins. The challenger
uses the rapperSkill
of someone else's rapper.
The test function testGoOnStageOrBattleOpponentWithStolenTokenId
shows the described scenario:
After the battle is finished and the function is executed we can see that the winner is the challenger
and he received the _credBet
that is equal to 1
. The challenger
won this battle with someone else's rapper token. Part of the traces of the testGoOnStageOrBattleOpponentWithStolenTokenId
test function can be seen below. You can execute the test function using the foundry command:
forge test --match-test "testGoOnStageOrBattleOpponentWithStolenTokenId" -vvvvv
The function RapBattle::goOnStageOrBattle
should not allow to participate in battle with non-existing or someone else's rapper token.
Manual Review, Foundry
Add a check in the RapBattle::goOnStageOrBattle
function to ensure that the msg.sender
is an owner of the provided tokenId
:
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.