Overview
This Cartridge Verfiable Random Function (VRF) is designed to provide cheap, atomic verfiable randomness for fully onchain games.
Key Features
-
Atomic Execution: The VRF request and response are processed within the same transaction, ensuring synchronous and immediate randomness for games.
-
Efficient Onchain Verification: Utilizes the Stark curve and Poseidon hash for optimized verification on Starknet.
-
Fully Onchain: The entire VRF process occurs onchain, maintaining transparency and verifiability.
-
Improved Player Experience: The synchronous nature of the VRF allows for instant resolution of random events in games, enhancing gameplay fluidity.
How It Works
- A game calls
request_random(caller, source)
as the first call in their multicall. - A game contract calls
consume_random(source)
on the VRF contract. - The VRF server generates a random value using the VRF algorithm for the provided entropy source.
- The Cartridge Paymaster wraps the players multicall with a
submit_random
andassert_consumed
call. - The
submit_random
call submit a VRF Proof for the request, the VRF Proof is verified onchain, ensuring the integrity of the random value which is immediately available and must be used within the same transaction. - The
assert_consumed
call ensures thatconsume_random(source)
has been called, it also reset the storage used to store the random value during the transaction to 0.
Benefits for Game Developers
- Simplicity: Easy integration with existing Starknet smart contracts and Dojo.
- Performance: Synchronous randomness generation without waiting for multiple transactions.
- Cost-effectiveness: Potential cost savings through Paymaster integration.
- Security: Cryptographically secure randomness that's fully verifiable onchain.
Deployments
For detailed implementation and usage, refer to the GitHub repository.
Using the VRF Provider
To integrate the Verifiable Random Function (VRF) into your Starknet contract, follow these steps:
- Import the VRF Provider interface:
use cartridge_vrf::IVrfProviderDispatcher;
use cartridge_vrf::IVrfProviderDispatcherTrait;
use cartridge_vrf::Source;
- Define the VRF Provider address in your contract:
const VRF_PROVIDER_ADDRESS: starknet::ContractAddress = starknet::contract_address_const::<0x123>();
- Create a dispatcher for the VRF Provider:
let vrf_provider = IVrfProviderDispatcher { contract_address: VRF_PROVIDER_ADDRESS };
- To consume random values, use the following pattern in your contract functions:
fn roll_dice(ref self: ContractState) {
// Your game logic here...
// Consume random value
let player_id = get_caller_address();
let random_value = vrf_provider.consume_random(Source::Nonce(player_id));
// Use the random value in your game logic
// ...
}
-
You can use either
Source::Nonce(ContractAddress)
orSource::Salt(felt252)
as the source for randomness:-
Source::Nonce(ContractAddress)
: Uses the provided contract address internal nonce for randomness.
Each request will generate a different seed ensuring unique random values. -
Source::Salt(felt252)
: Uses a provided salt value for randomness.
Two requests with same salts will result in same random value.
-
Executing VRF transactions
In order to execute a transaction that includes a consume_random
call, you need to include a request_random
transaction as the first transaction in the multicall. The request_random
call allows our server to efficiently parse transactions that include a consume_random
call internally.
const call = await account.execute([
// Prefix the multicall with the request_random call
{
contractAddress: VRF_PROVIDER_ADDRESS,
entrypoint: 'request_random',
calldata: CallData.compile({
caller: GAME_CONTRACT,
// Using Source::Nonce(address)
source: {type: 0, address: account.address},
// Using Source::Salt(felt252)
// source: {type: 1, salt: 0x123}
}),
},
{
contractAddress: GAME_CONTRACT,
entrypoint: 'roll_dice',
...
},
]);
consume_random
with the same Source
as used in request_random
.
Important: Adding VRF to Policies
When using the Cartridge Controller with VRF, make sure to add the VRF contract address and the request_random
method to your policies. This allows the controller to pre-approve VRF-related transactions, ensuring a seamless experience for your users.
Add the following policy to your existing policies:
const policies: Policy[] = [
// ... your existing policies ...
{
target: VRF_PROVIDER_ADDRESS,
method: "request_random",
description: "Allows requesting random numbers from the VRF provider",
},
];
This ensures that VRF-related transactions can be executed without requiring additional user approval each time.
By following these steps, you can integrate the VRF Provider into your Starknet contract and generate verifiable random numbers for your onchain game or application.
Security Assumptions
During the Phase 0 deployment, the construction assumes the Provider has not revealed the private key and does not collude with players.
In the future, we plan to move the Provider to a Trusted Execution Environment (TEE) in order to provide a more robust security model without compromising on performance.