I am constructing some nft metadat on-chain, and need to grab pseudo random number for each of the traits, these numbers need to be different.
So far best I came up with is following
function getRandomNumbers(string memory seed) private view returns (uint256[8] memory) {
return [
randomise(string(abi.encodePacked("property 1", seed)), property1Arr.length),
randomise(string(abi.encodePacked("property 2", seed)), property2Arr.length),
randomise(string(abi.encodePacked("property 3", seed)), property3Arr.length),
randomise(string(abi.encodePacked("property 4", seed)), property4Arr.length)
];
}
function randomise(string memory seed, uint256 range) private view returns (uint256) {
return uint256(keccak256(abi.encodePacked(seed, block.difficulty, block.timestamp, block.number))) % range;
}
So brief explanation, getRandomNumbers
takes in "seed" from client and combines it with property string, this is repeated multiple times for each property. Then resulting combined string is used as "seed" for randomise
that returns random integer by further randomising it using some block data and returning number that is in range for the array of properties.
This does decent job, but doesn't scale well, so I am wondering if there is a better approach here that I might be missing.
Best Answer
Maybe the following approach will work for you. The basic idea is that instead of "throwing away" most of the random number after doing "% range", you continue using it.
Here a,b,c,d are the lengths of the various propertyArrs.
This is just a proof of concept. You can perhaps also use bit operations for this.