Solidity how to get random number with ratio - solidity

I want to create my own NFT according to ERC1155 standard.
My hero has 6 parts, each part has 4 types as shown in the picture.
Now I want to create a function that takes a random number with the ratio shown in the image.
Here is simple function return random number. With _mod = 10^n it will return number of length n-1.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract RandomNumbers{
function random(uint _mod) public view returns(uint){
return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty,
msg.sender))) % _mod;
}
}
I've been struggling with this for a whole day.
Thanks for help.

Just so you know. You shouldn't use keccak256(abi.encodePacked(block.timestamp,block.difficulty,msg.sender)) to generate a random number because that actually creates a pseudo-random guessable number. Take a look at Chainlink VRF.
For the ratio you could try to check out this Data structure (GitHub): you manually set values for the leaves and then when you have your random number you can call the draw function to set the different stats.

Related

Why does this solidity function run into gas errors?

I'm trying to figure out some strange behavior. The function below takes in an array like [1,2,3,4,5], loops through it, and looks at another contract to verify ownership. I wrote it like this (taking in a controlled / limited array) to limit the amount of looping required (to avoid gas issues). The weird part (well, to me) is that I can run this a few times and it works great, mapping the unmapped values. It will always process as expected until I run about 50 items through it. After that, the next time it will gas out even if the array includes only one value. So, I'm wondering what's going on here...
function claimFreeNFTs (uint[] memory _IDlist) external payable noReentrant {
IERC721 OGcontract = IERC721(ERC721_contract);
uint numClaims = 0;
for (uint i = 0; i < _IDlist.length; i++) {
uint thisID = _IDlist[i];
require(OGcontract.ownerOf(thisID)==msg.sender, 'Must own token.' );
if ( !claimedIDList(thisID) ) { // checks mapping here...
claimIDset(thisID); // maps unmapped values here;
numClaims++;
}
}
if ( numClaims > 0 ) {
_safeMint(msg.sender, numClaims);
emit Mint(msg.sender, totalSupply());
}
}
Any thoughts / directions appreciated. :-)
Well, there was a bit more to the function, actually. I'd edited out some of what I thought was extraneous, but it turned out my error was in the extra stuff. The above does actually work. (Sorry.) After doing the mint, I was also reducing the supply of a reserve wallet on the contract -- one that held (suprise!) 50 NFTs. So, after this function processed 50, it was making that wallet hold negative NFTs, which screwed things up. Long story, but on Remix, I'd forgotten to set values in the constructor in the proper order, which is how I screwed it up in the first place. Anyway, solved.

how to use the solidity shift for non binary numbers?

I wanted to pop some zeros of a number without having to use division.(from 1000 to 10).
I checked out the operand << and i know it's only for bit shifts but I was wondering if there is a way I can use shift in solidity to do that?
You can't.
Everything solidity can do efficiently maps directly to an ethereum EVM op code (listed here: evm.codes/). The only shift operations listed are for binary bits. If the goal is to save gas, then multiply or divide by ten inside an unchecked block (but be sure you won't have issues with underflow and overflow).

Solidity code for getting raw data from blockchain based on blocknumber/Hash

will you please make a video/code or any samples for solidity code based on block number/Hash to get Raw data which is stored in Blockchain.And also please help if anyone knows.
There are no such functions in solidity to get raw block data.
But have a look on this Official documentation link which will help to get block info
blockhash(uint blockNumber) returns (bytes32): hash of the given block
block.coinbase (address payable): current block miner’s address
block.difficulty (uint): current block difficulty
block.gaslimit (uint): current block gaslimit block.number
(uint): current block number block.timestamp (uint): current
block timestamp as seconds since unix epoch

Multiplication and Division with contract value

I am trying to insert a if-clause in the following contract to check if the withdrawal (it is a sample bank contract) is less than the 10% of the whole contracts value, i.e. of the complete bank.
When I insert the code as below it gives me an error such as
"UnimplementedFeatureError: Not yet implemented - FixedPointType."
What am I doing wrong?
Can you help me?
Many thanks in advance!!
pragma solidity ^0.4.24;
contract bank{
mapping (address => uint) private balance;
address public Owner;
function WithDrawMoreMoney(uint a) public{
require (balance[msg.sender]>=0);
require (address(this).balance>=0);
require ((a) =< (address (this).balance)*(uint(1.1))); // The problematic line
balance[msg.sender]-=a;
(msg.sender).transfer(a);
check if the withdrawal ... is less than [10%] of the whole [contract's] value
I think you just want this:
require(a <= address(this).balance / 10);
Your code multiplied by 1.1 when I think you meant 0.1, but either way Solidity only has integers. Dividing by 10 works. You also had a typo: =< instead of <=.
If you want to check some other percentage, like 23%:
require(a <= address(this).balance * 23 / 100);
Make sure to do the multiplication first, and always remember to guard against integer overflows.

How to make rand() more likely to select certain numbers?

Is it possible to use rand() or any other pseudo-random generator to pick out random numbers, but have it be more likely that it will pick certain numbers that the user feeds it? In other words, is there a way, with rand() or something else, to pick a pseudo random number, but be able to adjust the odds of getting certain outcomes, and how do you do that if it is possible.
BTW, I'm just asking how to change the numbers that rand() outputs, not how to get the user input.
Well, your question is a bit vague... but if you wanted to pick a number from 0-100 but with a bias for (say) 43 and 27, you could pick a number in the range [0, 102] and map 101 to 43 and 102 to 27. It will really depend on how much bias you want to put in, what your range is etc.
You want a mapping function between uniform density of rand() and the probability density that you desire. The mapping function can be done lots of different ways.
You can certainly use any random number generator to skew the results. Example in C#, since I don't know objective-c syntax. I assume that rand() return a number tween 0 and 1, 0 inclusive and 1 exclusive. It should be quite easy to understand the idear and convert the code to any other language.
/// <summary>
/// Dice roll with a double chance of rolling a 6.
/// </summary>
int SkewedDiceRoll()
{
// Set diceRool to a value from 1 to 7.
int diceRool = Math.Floor(7 * rand()) + 1;
// Treat a value of 7 as a 6.
if (diceRoll == 7)
{
diceRoll = 6;
}
return diceRoll;
}
This is not too difficult..
simply create an array of all possible numbers, then pad the array with extra numbers of which you want to result more often.
ie:
array('1',1','1','1','2','3','4','4');
Obviously when you query that array, it will call "1" the most, followed by "4"
In other words, is there a way, with rand() or something else, to pick a pseudo random number, but be able to adjust the odds of getting certain outcomes, and how do you do that if it is possible.
For simplicity sake, let's use the drand48() which returns "values uniformly distributed over the interval [0.0,1.0)".
To make the values close to one more likely to appear, apply skew function log2():
log2( drand48() + 1.0 ); // +1 since log2() in is [0.0, 1.0) for values in [1.0, 2.0)
To make the values close to zero more likely to appear, use the e.g. exp():
(exp(drand48()) - 1.0) * (1/(M_E-1.0)); // exp(0)=1, exp(1)=e
Generally you need to crate a function which would map the uniformly distributed values from the random function into values which are distributed differently, non-uniformly.
You can use the follwing trick
This example has a 50 percent chance of producing one of your 'favourite' numbers
int[] highlyProbable = new int[]{...};
public int biasedRand() {
double rand = rand();
if (rand < 0.5) {
return highlyProbable[(int)(highlyProbable.length * rand())];
} else {
return (int)YOUR_RANGE * rand();
}
}
In addition to what Kevin suggested, you could have your regular group of numbers (the wide range) chopped into a number of smaller ranges, and have the RNG pick from the ranges you find favorable. You could access these ranges in a particular order, or, you can access them in some random order (but I can assume this wouldn't be what you want.) Since you're using manually specified ranges to be accessed within the wide range of elements, you're likely to see the numbers you want pop up more than others. Of course, this is just how I'd approach it, and it may not seem all that rational.
Good luck.
By definition the output of a random number generator is random, which means that each number is equally likely to occur next (1/10 chance) and you should not be able to affect the outcome.
Of-course, a pseudo-random generator creates an output that will always follow the same pattern for a given input seed. So if you know the seed, then you may have some idea of the output sequence. You can, of-course, use the modulus operator to play around with the set of numbers being output from the generator (eg. %5 + 2 to generate numbers from 2 to 7).