# Cartridge Vrng

> Integrate Cartridge's verifiable random number generator (vRNG) into onchain games.

- Skill: `cartridge-gg/cartridge-vrng` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cartridge-gg/cartridge-vrng`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cartridge-gg/cartridge-vrng/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cartridge-gg (https://skillmd.com/u/cartridge-gg)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cartridge-gg/cartridge-vrng

---


# Cartridge vRNG

Cartridge's Verifiable Random Number Generator provides cheap, atomic, verifiable randomness for onchain games.
Randomness is generated and verified within a single transaction.

## Contract Addresses

| Network | Address |
|---------|---------|
| Mainnet | `0x051fea4450da9d6aee758bdeba88b2f665bcbf549d2c61421aa724e9ac0ced8f` |
| Sepolia | `0x051fea4450da9d6aee758bdeba88b2f665bcbf549d2c61421aa724e9ac0ced8f` |

## Cairo Interface

```rust
#[starknet::interface]
trait IVrfProvider<TContractState> {
    fn request_random(self: @TContractState, caller: ContractAddress, source: Source);
    fn consume_random(ref self: TContractState, source: Source) -> felt252;
}

#[derive(Drop, Copy, Clone, Serde)]
pub enum Source {
    Nonce: ContractAddress,
    Salt: felt252,
}
```

### Source Types

- `Source::Nonce(ContractAddress)`: Uses the address's internal nonce.
Each request generates a different seed.
- `Source::Salt(felt252)`: Uses a provided salt.
Same salt = same random value.

## Usage in Contracts

```rust
const VRF_PROVIDER_ADDRESS: starknet::ContractAddress =
    starknet::contract_address_const::<0x051fea4450da9d6aee758bdeba88b2f665bcbf549d2c61421aa724e9ac0ced8f>();

fn roll_dice(ref self: ContractState) {
    let vrf_provider = IVrfProviderDispatcher { contract_address: VRF_PROVIDER_ADDRESS };
    let player_id = get_caller_address();
    let random_value = vrf_provider.consume_random(Source::Nonce(player_id));
    // Use random_value in game logic
}
```

## Executing vRNG Transactions

`request_random` must be the first call in the multicall.
The Cartridge Paymaster wraps the multicall with `submit_random` and `assert_consumed`.

```js
const call = await account.execute([
  // First: request_random
  {
    contractAddress: VRF_PROVIDER_ADDRESS,
    entrypoint: 'request_random',
    calldata: CallData.compile({
      caller: GAME_CONTRACT,
      // Source::Nonce(address)
      source: { type: 0, address: account.address },
      // Or Source::Salt(felt252)
      // source: { type: 1, salt: 0x123 },
    }),
  },
  // Then: your game call
  {
    contractAddress: GAME_CONTRACT,
    entrypoint: 'roll_dice',
    // ...
  },
]);
```

The `source` in `request_random` must match the `source` in `consume_random`.

## Controller Policy

Add the vRNG contract to your Controller policies:

```typescript
const policies: Policy[] = [
  // ... your existing policies ...
  {
    target: VRF_PROVIDER_ADDRESS,
    method: "request_random",
    description: "Allows requesting random numbers from the VRF provider",
  },
];
```

## Security

Phase 0 assumes the Provider has not revealed the private key and does not collude with players.
Future plans include moving the Provider to a Trusted Execution Environment (TEE).

