Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

`RapBattle::_battle()` uses weak randomness to determine a winner

Summary

RapBattle::_battle() uses the hash of block.timestamp, block.prevrandao, msg.sender, and totalBattleSkill to determine a winner but this is known to be predictable.

Vulnerability Details

Inside of RapBattle::_battle() it declares a local variable of type uint256 called random:

function _battle(uint256 _tokenId, uint256 _credBet) internal {
address _defender = defender;
require(defenderBet == _credBet, "RapBattle: Bet amounts do not match");
uint256 defenderRapperSkill = getRapperSkill(defenderTokenId);
uint256 challengerRapperSkill = getRapperSkill(_tokenId);
uint256 totalBattleSkill = defenderRapperSkill + challengerRapperSkill;
uint256 totalPrize = defenderBet + _credBet;
@> uint256 random =
@> uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % totalBattleSkill;
// Reset the defender
defender = address(0);
emit Battle(msg.sender, _tokenId, random < defenderRapperSkill ? _defender : msg.sender);
// If random <= defenderRapperSkill -> defenderRapperSkill wins, otherwise they lose
if (random <= defenderRapperSkill) {
// We give them the money the defender deposited, and the challenger's bet
credToken.transfer(_defender, defenderBet);
credToken.transferFrom(msg.sender, _defender, _credBet);
} else {
// Otherwise, since the challenger never sent us the money, we just give the money in the contract
credToken.transfer(msg.sender, _credBet);
}
totalPrize = 0;
// Return the defender's NFT
oneShotNft.transferFrom(address(this), _defender, defenderTokenId);
}

The value of random is assigned by hashing block.timestamp, block.prevrandao, msg.sender, and totalBattleSkill. Since block.timestamp, block.prevrandao, msg.sender, and totalBattleSkill can all be known at the time of execution, this allows a user to know the value of random and ultimately the outcome of who wins the battle.

Impact

  • A user can know the outcome of the battle and call the function for a guaranteed win.

Tools Used

VS Code, Slither

Recommendations

Consider using Chainlink VRF for true randomness.

Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Weak Randomness

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.