An absolute sh*tbox. You have a better chance at winning the lottery than getting something good out of it.
Just kidding.
But seriously, what are these loot boxes? I can’t really say what’ll be inside of them quite yet, but I can explain how it works. Yes, it’s all happening on-chain. Randomly. RNG loot boxes on-chain. And here you thought loot boxes were just a simple metadata upgrade.
To those who don’t know, randomness isn’t possible on a blockchain by default. Computers generate randomness using atmospheric noise or other integrated hardware solutions, but because blockchains are virtual machines without any hardware, you don’t have any true randomness available to you. This is where pseudo-randomness and VRFs (verifiable random functions) come in to play.
Over time, thanks to elite minds, such as those at Switchboard, it’s gotten somewhat simpler to take advantage of on-chain verifiable randomness to randomly select loot plopping out of a loot box. Simple doesn’t mean easy, however. Usage of such programs may get convoluted to the untrained Solana developer, and honestly, I also got stuck a couple times myself. Hopefully this will help you (both the techies and non-techies) understand how it all works.
A quick disclaimer—the program featured in this article is still a work-in-progress and may get updated over time.
Every provider of verifiable randomness will have their own methods of providing you with RNG. I’ve worked with Switchboard before, know their oracles are top-class, and can safely expect the same from their VRF.
Since Switchboard specializes in oracles and providing off-chain data to on-chain consumers, their VRF uses this tech to prove or verify the generated randomness result. In their own words:
“…we can use a cryptographic keypair to generate a random number with a proof, which can then be validated by anyone to ensure the value was calculated correctly without the possibility of leaking the producer’s secret key”.
A keypair is exactly what it sounds like—the combination of a public key (which is also considered a public wallet address on Solana) and its private key. This result is then proven and/or validated using their oracle network, and the proof is posted on-chain. If you’re interested, you can read more in the article below.
Verifiable Randomness (VRF)on Solana
What’s actually going on in the VRF? Switchboard's VRF essentially computes a mathematical proof that the randomness was generated fairly and returns 32 bytes of randomness (also called a buffer). But how does the flow look like on the program side? Well, a couple things need to happen for this to work properly.
result_buffer
.result_buffer
on the VRF account you initialized, and so you can then use this as a randomness source for whatever you need to do.There’s a kicker here, though. Notice how the third step uses oracles to do stuff off-chain. How can all of this be done in a single instruction or transaction if we need to reach outside of the blockchain? That’s the thing—it can’t.
I didn’t realize this at first when working with the VRF, but it actually does a callback into your own program after the proof is verified and posted on-chain. In other words, the VRF behaves like a user. You need to provide it with a program instruction that it can call after verification, so your own program can then process the newly-generated result_buffer
from the VRF account you initialized. Pretty wild, huh?
A basic example of the program flow is provided on Switchboard’s GitHub.
But V, why do we need to know all of this?
https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi2.wp.com%2Fgifrific.com%2Fwp-content%2Fuploads%2F2017%2F10%2Fgal-gadot-youll-see-boat-scene-wonder-woman-2017.gif%3Fssl%3D1&f=1&nofb=1&ipt=8851b51ee87c75688bc7ef79825d0972b7e61df4e461446494839a37275c91c7&ipo=images
Let’s start with the basics of the Degenerate Loot Program. You’ll first need a loot box and loot key. Yes, another alpha piece which you probably know by now—we will have loot keys. Not to be used for anything sexual. I hope. Please.
Assuming you know what SFTs (semi-fungible tokens) are and how they differ from NFTs (non-fungible tokens), both the loot box and loot key are SFTs. The items you receive from the loot box are also SFTs and are therefore stackable. You could open 50 loot boxes and end up with 50 common rarity items, 40 of which are the exact same item. Sucks to suck. This functions very much like an Apex Legends Apex Pack or a Black Lion Chest from Guild Wars 2, just on-chain. You’re probably wondering “why SFT?”, but don’t worry—you’ll find out soon enough.
The Degenerate Loot Program uses a series of instructions and program accounts (shown below) to interact with Switchboard’s VRF to then give you a loot box item at random. Note that the math and algorithms used here are intentionally simple. We’re Degenerates, of course.
use anchor_lang::prelude::*;
#[account]
pub struct Generator {
pub authority: Pubkey, // 32 bytes
pub bump: u8, // 1 byte
}
#[account]
pub struct Loot {
pub authority: Pubkey, // 32 bytes
pub name: String, // 32 bytes
pub box_mint: Pubkey, // 32 bytes
pub key_mint: Pubkey, // 32 bytes
pub contents: Vec<Pubkey>, // 1024 bytes
pub weights: Vec<u8>, // 32 bytes
pub uses: u16, // 2 bytes
}
#[account]
pub struct Claim {
pub owner: Pubkey, // 32 bytes
pub winning: Pubkey, // 32 bytes
pub used: bool // 1 byte
}
#[account]
// We'll hold a pool of VRF accounts here.
pub struct VrfPool {
pub nomination: u8, // 1 byte
pub instances: Vec<Pubkey>, // 32 bytes
}
#[repr(packed)]
#[account(zero_copy)]
// This is our "VRF account".
pub struct VrfInstance {
pub bump: u8, // 1 byte
pub max_result: u64, // 8 bytes
pub result_buffer: [u8; 32], // 32 bytes
pub result: u128, // 16 bytes
pub last_timestamp: i64, // 8 bytes
pub authority: Pubkey, // 32 bytes
pub vrf: Pubkey, // 32 bytes
}
The first two accounts we’ll need to deal with are VrfPool
and VrfInstance
. VrfInstance
is basically the VRF account we discussed in the previous section, meaning it’ll contain all the information Switchboard’s VRF needs, including an initial result
and result_buffer
state.
To create a VRF account, however, the VRF program requires you to pay around 0.2 SOL for setup due to the computation complexity of the randomness function. Not every user will want to pay an initial 0.2 SOL fee to even be able to open loot boxes. To bypass this, instead of having the individual user create a VRF account for themself, we (the admin) can initialize a number of VRF accounts and add them to a pool that we can pass into our program instruction when requesting randomness.
This is what the VrfPool
account is for, or more specifically, the instances
field of the VrfPool
account. The nomination
field is just the index of the current selected VrfInstance
we’re using (i.e. when nomination
is 1
, we use the second VrfInstance
in the instances
vector of VrfPool
). When one user requests randomness using a particular VrfInstance
, we increment nomination
so that the next transaction uses the next VrfInstance
in the pool. We proceed in order until the end of the instances
array is reached, then start back at 0. In essence, we’re cycling through available pre-initialized “rent-able” instances, and the user never has to pay for creating their own VrfInstance
.
The remaining accounts we need to deal with are Generator
, Loot
, and Claim
. To start, the Loot
account is responsible for assigning the contents and percentage chances of this content appearing out of the loot box. Think of it as a Token Metadata account. We’re essentially assigning Loot
, as metadata, to an existing loot box. Remember that loot boxes are SFTs, so there’s only one token mint for each kind of loot box. Therefore, for a single type of loot box, we only need to assign one Loot
account.
The Loot
account has multiple fields, including the authority
(a DAA address), the name
of the loot box, token mint of the loot box, token mint of the loot key, the contents
in the loot box, and the weights
for each item in contents
. Only the authority
can create or alter a Loot
account. The box_mint
and key_mint
accounts are used to tie Loot
accounts to a specific loot box token mint, and to ensure that only a specific loot key token mint can be used to open said loot box.