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.

Damir Olejar
  • 828
  • 3
  • 11
  • 25
  • 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. – Tjaden Hess 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. – Damir Olejar Jul 17 '19 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 - (https://ethereum.stackexchange.com/questions/3542/how-are-ethereum-addresses-generated) – Udo E. Feb 15 '22 at 07:38

3 Answers3

7

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.

goodvibration
  • 26,003
  • 5
  • 46
  • 86
  • Before accepting, what does it do exactly ? Edit: is it just a random address, or an existing random address or... something else ? – Damir Olejar Jul 16 '19 at 13:13
  • @DamirOlejar: I'll add an explanation here in a minute. – goodvibration 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 ? – Damir Olejar 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). – goodvibration 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. – Damir Olejar Jul 16 '19 at 13:39
  • @DamirOlejar: Is the answer incorrect? – goodvibration Jul 16 '19 at 15:14
  • the answer does not work for solidity 5... Explicit type conversion not allowed from "bytes32" to "address". address addr – Damir Olejar Jul 16 '19 at 16:49
  • @DamirOlejar: 1. You did not specify compiler version. 2. You can easily solve that small issue, by casting to uint256 first, and then to address. 3. I pretty much covered every bit of your question in the answer above! – goodvibration Jul 16 '19 at 17:04
  • It doesn't work with other versions either. – Damir Olejar Jul 16 '19 at 17:39
  • @DamirOlejar: It compiles and works well with solc v0.4.25. I strongly recommend that you check your own arguments, in particularly towards someone who has made the effort to give you an answer, let alone a working one!!! – goodvibration Jul 16 '19 at 19:11
  • No, seriously, if you'd like to approach with pedantry, lack of understanding without being considerate, and with disrespect, then do not expect anything else in return. The solution compiles with 4.25, did not compile with other 4.x such as 4.18 neither it did with 5.0. I cannot accept this as an answer, but I appreciate your effort. – Damir Olejar Jul 16 '19 at 22:02
  • @DamirOlejar: "lack of understanding without being considerate, and with disrespect" - seriously??? You're one ungrateful dude, I'd tell you that! Your question has no mentioning of compiler-version whatsoever!!! And in addition to that, you just needed a small tweak to get it to work on your compiler version! You've also received a thorough explanation to help you with your lack of understanding about addresses, as reflected in your It would be the best if it could be an existing address statement from the question!!! – goodvibration Jul 17 '19 at 05:52
  • @goodvibrations the best case scenario, all of this is just a misunderstanding and completely pointless. If pedantry works for you, great! It doesn't work for me and never did, it only created useless tensions. I will stop right here. – Damir Olejar Jul 17 '19 at 10:58
  • Since: 0.5.0 --> TypeError: Explicit type conversion not allowed from "bytes32" to "address" --> Try: address(bytes20(sha256(abi.encodePacked(msg.sender,block.timestamp)))); – Extrange planet Sep 04 '22 at 12:31
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.

Rob Hitchens
  • 55,151
  • 11
  • 89
  • 145
  • 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. – goodvibration Jul 17 '19 at 05: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? – goodvibration Jul 17 '19 at 05:47
  • @Rob Hitchens - B9lab, thank you! I have just learned a difference btw block-time and a time-stamp. – Damir Olejar 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 – Tjaden Hess 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)

    – Miao ZhiCheng Oct 04 '20 at 09: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))));
NNNComplex
  • 23
  • 3