2

EDIT: there is currently no good answer to this question. Solidity is not able to generate anything random, not at this moment at least.

I would like to generate a random 0X address using solidity. It would be the best if it could be an existing address, however, I understand that it might be too complicated to do (it might need an oracle?).

What is the best way of doing it?

My approach would be to simply have an array of characters 0-9, a-z, A-Z and take a random character from it to concat the 0x address. However, I am not sure if that would be the best coding practice with Solidity.

3
  • 1
    It would help if you explained a bit more about why you need a random address, as that would more accurately indicate what properties the system to generate them needs to have. Commented Jul 16, 2019 at 16:36
  • The best answer I can give you is "why not?". I don't think I am asking for much. Commented Jul 17, 2019 at 11:04
  • "why not?" - because your system/application will not be compatible with global systems like Ethereum or Bitcoin where ensuring uniqueness of addresses on a global scale is the a major objective. This is the question you should be asking - (ethereum.stackexchange.com/questions/3542/…) Commented Feb 15, 2022 at 7:38

3 Answers 3

8

It would be the best if it could be an existing address

What you need to understand is that all addresses (all possible combinations of a 40-character long hexadecimal string) exist. In other words, every possible address is a legal address which you can query for balance, send ether to, etc. However, not necessarily for every address does there exist a person who knows its private key.

So sending ether to an address whose private key is not known to anyone, would be equivalent to losing that ether forever, or at least until somebody obtains the private key of that address (and if somebody ever does, then they will be able to withdraw that ether). However, even without knowing the private key of a given address, anyone can still query for its balance and see that the "lost ether" is still there.

Now that we've clarified the "existing address" issue, you may try this:

address addr = address(keccak256(abi.encodePacked(now)));

This compiles well in Solc v0.4.25, and probably in earlier versions as well.

14
  • Before accepting, what does it do exactly ? Edit: is it just a random address, or an existing random address or... something else ? Commented Jul 16, 2019 at 13:13
  • @DamirOlejar: I'll add an explanation here in a minute. Commented Jul 16, 2019 at 13:22
  • goodvibration, Am I right to assume that it takes a current time(stamp) and generates an address from it ? Commented Jul 16, 2019 at 13:23
  • @DamirOlejar: See updated answer. No, you are not right. It takes the current time, hashes it into a 256-bit value, and then returns the lower 160-bits. And so while you could argue that the current time is hardly random (i.e., can be "well anticipated"), once you hash that value, the result is truly randomized (if not, then the entire cryptographic base of the Ethereum system is compromised). Commented Jul 16, 2019 at 13:35
  • Yes, that is what I meant by "generates"... and by existing address I meant, an address recorded on a block-chain. But it doesn't matter, it is pointless to debate an accuracy versus a precision... thank you for an answer, should that be a cost of it. Commented Jul 16, 2019 at 13:39
2

I voted for goodVibration's answer because it contains useful information about the addresses themselves.

You can't really do "random" at this time unless you use an Oracle to inject some randomness, otherwise, this is a deterministic system. Everyone can see the formula and the inputs so there is no doubt about the result.

You have to settle for unpredictable. Even that is tricky. Using "now" as a source of randomness is a step in the right direction, but there are issues:

  1. If two transactions are mined in the same block, they will have the same "now", ergo, the same address. That collision might not be what you want.
  2. A miner has latitude over the timeStamp, so if so motivated, they can play with the time until they generate a favourable "random" address.

You can "spice it up" a little:

address randomish = address(uint160(uint(keccak256(abi.encodePacked(nonce, blockhash(block.number))))));
nonce++;

The wrapping is merely doing explicit type conversions from a hash to an address. The nonce scrambles it up if two transactions go through in the same block. The block hash looks hard to guess because it's in the future. In practice, it is trivial to know. The method of attack would be another question. Suffice it say this is not a safe way to do it.

If there is any incentive to guess the "random" numbers (card game, lottery, etc.) then a popular pattern is commit and reveal. Commit and reveal is a two-step process. In step 1, players lock in their decisions. Then some further randomness is added. After the careful addition of an extra challenge (e.g. next block hash, that clearly cannot be known when the decisions were made), then generate the random(ish) number.

Hope it helps.

5
  • Thank you. I provided the "most random" on-chain way that I could think of. This dude voted for the answer and accepted it, then later retracted both because the code snippet did not compile for him on solc v0.5. (although the question has no mentioning of compiler version, and although you just need a small tweak to get it to compile on v0.5). And his complaints about this compilation issue has led others to vote against it, which is rather annoying considering the effort that I made for this ungrateful fella. Commented Jul 17, 2019 at 5:45
  • With regards to your on-chain suggestion, I believe that once you use hashing (kaccak256), it doesn't really matter whether you choose now or nonce + blockNumber. In fact, thinking about it, if this code is guaranteed to be used from a non-constant function, then the best solution would be a combination of nonce and msg.sender, wouldn't it? Commented Jul 17, 2019 at 5:47
  • @Rob Hitchens - B9lab, thank you! I have just learned a difference btw block-time and a time-stamp. Commented Jul 17, 2019 at 11:01
  • 1
    @goodvibration now is problematic if you want the addresses to be somewhat collision resistant. I agree that nonce+msg.sender is good, but there's really no way to say what "good" means in this case since @Damir hasn't given any sort of threat model Commented Jul 17, 2019 at 12:22
  • This is WRONG!!! blockhash(uint blockNumber) returns (bytes32): hash of the given block - only works for 256 most recent, excluding current, blocks You should never use: blockhash(block.number) instead, you use blockhash(block.number-1) Commented Oct 4, 2020 at 9:00
0

goodvibration's code snippet doesn't work as of v0.8.13. Here is code that will compile.

Note: This address is NOT random

address addr = address(bytes20(keccak256(abi.encode(block.timestamp))));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.