Values used for generating random number are predetermined, which can be used by user or organiser to get the result in there favor.
Where values like block.timestamp, msg.sender, block.prevrandao are being used to generate randomess.
function test_weakRandomnessMakeItEasyToKnowWinnerBeforehand() public participants {
vm.startPrank(player1);
vm.warp(1728363903);
choosingRam.increaseValuesOfParticipants(0,1);
choosingRam.increaseValuesOfParticipants(0,1);
choosingRam.increaseValuesOfParticipants(0,1);
choosingRam.increaseValuesOfParticipants(0,1);
choosingRam.increaseValuesOfParticipants(0,1);
console.log("player1:", player1);
console.log("player2:", player2);
console.log("Selected Ram:", choosingRam.selectedRam());
}
function test_weakRandomnessByOrganiserPickingWinner () public participants{
vm.startPrank(organiser);
console.log("player1:", player1);
console.log("player2:", player2);
vm.warp(1728691203);
vm.prevrandao(bytes32(uint256(1)));
choosingRam.selectRamIfNotSelected();
console.log("Ram will be:", choosingRam.selectedRam());
}
it will print the following results, user or organiser can easily simulate the results beforehand and execute things accordingly.
Weak Randomness can be utilized to select particular nft as a Ram. Which is not fair with other participants
Consider using chainlink VRF to generate random number as given below. (it's not available on zksync though, works on remaining chains).
I am using chainlink v2.0 as it's available on most chain, v2.5 is still early and available on few chains yet.
using 1.1.1 version of contracts
pragma solidity 0.8.20;
import {RamNFT} from "./RamNFT.sol";
+ import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
+ import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
- contract ChoosingRam {
+ contract ChoosingRam is VRFConsumerBaseV2 {
error ChoosingRam__InvalidTokenIdOfChallenger();
error ChoosingRam__InvalidTokenIdOfPerticipent();
error ChoosingRam__TimeToBeLikeRamFinish();
error ChoosingRam__CallerIsNotChallenger();
error ChoosingRam__TimeToBeLikeRamIsNotFinish();
error ChoosingRam__EventIsFinished();
+ error ChoosingRam__RandomNumberNotFulfilled();
bool public isRamSelected;
RamNFT public ramNFT;
address public selectedRam;
+ VRFCoordinatorV2Interface COORDINATOR;
+
+ uint64 s_subscriptionId;
+ bytes32 keyHash;
+ uint32 callbackGasLimit;
+ uint16 requestConfirmations;
+ uint32 numWords;
+
+ uint256 public randomValueProvidedByChainlink;
modifier RamIsNotSelected() {
require(!isRamSelected, "Ram is selected!");
_;
}
modifier OnlyOrganiser() {
require(ramNFT.organiser() == msg.sender, "Only organiser can call this function!");
_;
}
- constructor(address _ramNFT) {
+ constructor(
+ address _ramNFT,
+ uint64 subscriptionId,
+ address vrfCoordinator,
+ bytes32 vrfKeyHash,
+ uint32 vrfCallbackGasLimit,
+ uint16 vrfRequestConfirmations,
+ uint32 vrfNumWords
+ )
+ VRFConsumerBaseV2(vrfCoordinator)
+ {
isRamSelected = false;
ramNFT = RamNFT(_ramNFT);
+ COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
+ s_subscriptionId = subscriptionId;
+ keyHash = vrfKeyHash;
+ callbackGasLimit = vrfCallbackGasLimit;
+ requestConfirmations = vrfRequestConfirmations;
+ numWords = vrfNumWords;
}
function increaseValuesOfParticipants(uint256 tokenIdOfChallenger, uint256 tokenIdOfAnyPerticipent)
public
RamIsNotSelected
{
if (tokenIdOfChallenger > ramNFT.tokenCounter()) {
revert ChoosingRam__InvalidTokenIdOfChallenger();
}
if (tokenIdOfAnyPerticipent > ramNFT.tokenCounter()) {
revert ChoosingRam__InvalidTokenIdOfPerticipent();
}
if (ramNFT.getCharacteristics(tokenIdOfChallenger).ram != msg.sender) {
revert ChoosingRam__CallerIsNotChallenger();
}
if (block.timestamp > 1728691200) {
revert ChoosingRam__TimeToBeLikeRamFinish();
}
+ requestRandomWords();
+ if (randomValueProvidedByChainlink == 0) {
+ revert ChoosingRam__RandomNumberNotFulfilled();
+ }
- uint256 random =
- uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % 2;
+ uint256 random = randomValueProvidedByChainlink % 2;
if (random == 0) {
if (ramNFT.getCharacteristics(tokenIdOfChallenger).isJitaKrodhah == false){
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, false, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isDhyutimaan == false){
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isVidvaan == false){
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isAatmavan == false){
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, true, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isSatyavaakyah == false){
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, true, true);
selectedRam = ramNFT.getCharacteristics(tokenIdOfChallenger).ram;
}
} else {
if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isJitaKrodhah == false){
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, false, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isDhyutimaan == false){
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isVidvaan == false){
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isAatmavan == false){
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, true, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isSatyavaakyah == false){
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, true, true);
selectedRam = ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).ram;
}
}
}
function selectRamIfNotSelected() public RamIsNotSelected OnlyOrganiser {
if (block.timestamp < 1728691200) {
revert ChoosingRam__TimeToBeLikeRamIsNotFinish();
}
if (block.timestamp > 1728777600) {
revert ChoosingRam__EventIsFinished();
}
+ requestRandomWords();
+ if (randomValueProvidedByChainlink == 0) {
+ revert ChoosingRam__RandomNumberNotFulfilled();
+ }
- uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % ramNFT.tokenCounter();
+ uint256 random = randomValueProvidedByChainlink % ramNFT.tokenCounter();
selectedRam = ramNFT.getCharacteristics(random).ram;
isRamSelected = true;
}
+ function requestRandomWords() internal {
+ COORDINATOR.requestRandomWords(
+ keyHash,
+ s_subscriptionId,
+ requestConfirmations,
+ callbackGasLimit,
+ numWords
+ );
+ }
+ function fulfillRandomWords(uint256, uint256[] memory randomWords) internal override {
+ randomValueProvidedByChainlink = randomWords[0];
+ }
}