Randomness for NFT packs on Flow

Hi all,

I’m currently working on an NFT Marketplace on the flow blockchain. I am hoping to find a way to implement a pack that returns a random NFT (similar to NBA Topshot). I have seen the Cadence documentation for unsafeRandom() but I am not sure how to implement it (also the playground doesn’t support it).

I would appreciate any input.


It isn’t safe because a user could revert the transaction and retry as many times as they want until they get the random number that they want.

Check out the docs for how to use it: Built-in Functions - Flow Documentation

It is called “unsafeRandom”, from these two words, only “unsafe” is correct, unfortunately.
Because it is not random for sure. It is not uniform, you have better luck with xkcd random. [1]

Even if you sign the transaction yourself it is not safe. Don’t use in any condition.


unsafeRandom isn’t flagged as unsafe for the reasons you are stating. It is probably easier to explain with an example.

It is very easy and very likely for a contract writer to write a contract where the randomness is generated in the same transaction where the value is delivered. Say in a pack situation if what was in the pack was decided at random during the purchase, I could in theory write a transaction that buys the pack, opens it, and only completes the transaction if the delivered nft serial numbers are to my liking. I could then run that transaction say 10 or even 100 times at once, so that I am more likely to receive a valuable pack and guarantee a bag of valuable nfts at the small additional cost of gas for transactions that weren’t up to my get rich quick standards.

You can then say, well just make it so the randomness is decided in a different transaction to the delivery of the value, so that the sale can’t be stopped if the purchaser doesn’t like the outcome. Which is correct, and I believe the answer to the question @zach8302 asked.

Be super super super careful with randomness and blockchains.

I understand the transaction cancel and retry part. It is the obvious probable attack.

This is also unsafe imo, consider this:

  • Imagine I am distributing TS packs with single moment inside (let’s say 100k packs), and in each pack you have chance to get 1/100k odds Lebron Moment

  • I am making lets say 100 transactions per block to speed up delivery.


  • all those 100 transactions (in the same block which blockID is the seed), will have the same pack content. So instead of different packs, you will give 100x same pack

  • if one of the packs (1/1000) has Lebron, 1/100 chance, you will give away 100 Lebron. So instead of expected value of 1 Lebron in 100k packs, you will either have 100 Lebron with 1% chance, or No Lebron at all 99%

This variance is usually not good from a business perspective too.

Also, I didn’t check how blockID is calculated, but potentially I am guessing, the malicious users can also affect that part.

Have there been any new developments of randomness on Flow?

I am curious about your idea here about generating the random in a different transaction than delivery. My understanding is you are saying 1 transaction would pay for and request a pack. Then a second transaction would ask for the pack to be delivered? Couldn’t I just cancel either transaction once the randomness is revealed but before it is sealed?

Would a verifiable random oracle work on Flow? A service will generate crypto-random values ahead of time, hash the value, and publicly publish the upcoming hashes and times they will be published - ideally 1 for every block. The service will continuously publish transactions wherein the next random number is set in the contract. There could be a consumer function that mutates the number after each use so that each transaction in the block gets a different number. Auditors can use the hash history with the published numbers to ensure the oracle is fair.

I suppose this is still susceptible to someone repeatedly making transactions and cancelling until they get their desired outcome but with try-and-panic until you get your desired outcome you could theoretically never get your outcome and be beaten by another user.

Yes, there has :smiley:

You can check this thread out in the discord:

Rather than requiring a second transaction it just uses a future block hash for the seed…
which avoids the panic if unhappy problem.

It uses an LCG instead of unsaferandom for the reasons @bluesign described