How to get un-abusable random numbers from VRF?

I’m working on a way to get secure random numbers with VRF. If we use the VRF from “this” block it’s open to abuse, so I’ve been working with way of using a future block, but that still seems abusable. Say you have a game where you send in 1 ETH for a chance to win 100 ETH (imaginary high value random game). If you resolve the random number and payout in the same transaction someone could obviously abuse that. Since they’d be able to try and read the VRF from and submit the collection transaction in the same block, and keep trying until they win.

Instead we split into two transactions. In tx1 on block1 you approve the spend and “commit” to using the VRF from block2, then the user must submit tx2 within 8 minutes (256 blocks) to read the random number from block2 to resolve the wager. This in theory works great… but my issue is what happens if the user misses that 256 block window and can no longer read the random number from block2!

The first idea I had was if you’re past the VRF 256 block window your bet just gets cancelled, but then we’re open to the same type of abuse because the malicious user could just note their random number from block2, determine if they want to collect or not, and just allow the 8min window to pass, allowing them to try again…

How would I be able to get a truly random number from VRF that’s not able to be exploited in this fashion?

You take the token and if the user does not interact in 8 mins, they lose the token

1 Like

In one of my use cases the token in question is a high value NFT, forcing someone to lose a valuable NFT because they didn’t make a click within 8 minutes won’t work for that :-\ way too big a punishment

1 Like

Alternatively, you can have an off chain node to update and store the result so that regardless of when they interact, the result will be the same

hmm okay- so then no-matter-what they’re committed to using the random number from block2 okay good … but then I’d need to run an oracle, and the users would need to trust that oracle. I could abuse it in theory, doesn’t seem like a great solution either

The oracle does not need to be trusted. You create a function inside the contract that just grabs and stores the vrf and that is what the service will call.

You don’t have the vrf as an argument to the function as yes, this would not be trusted.

You keep it on chain in those respects.

If you had at least 1 interaction a minute from users, you could incorporate this into the call but that is a bit risky imo

I was just thinking about this today.
Maybe the way to go is to have rounds,
like if it’s a betting app:
round 1, everybody places bets on whatever
round 2, bets are locked and a random number selected via VRF
round 3, winners pull payments

This way the user only needs to care about placing the bet in time, nobody can abuse the randomness and users can pull the rewards after whenever they want.