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.

  • 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. Jul 16 '19 at 16:36
  • The best answer I can give you is "why not?". I don't think I am asking for much. Jul 17 '19 at 11:04

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.

  • Before accepting, what does it do exactly ? Edit: is it just a random address, or an existing random address or... something else ? Jul 16 '19 at 13:13
  • @DamirOlejar: I'll add an explanation here in a minute. Jul 16 '19 at 13:22
  • goodvibration, Am I right to assume that it takes a current time(stamp) and generates an address from it ? Jul 16 '19 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). Jul 16 '19 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. Jul 16 '19 at 13:39

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))))));

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.

  • 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. Jul 17 '19 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? Jul 17 '19 at 5:47
  • @Rob Hitchens - B9lab, thank you! I have just learned a difference btw block-time and a time-stamp. Jul 17 '19 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 Jul 17 '19 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) Oct 4 '20 at 9:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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