Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions src/pages/arcade/starter-packs.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ description: Create and register starter packs on the Arcade registry to distrib
# Starter Packs

Starter packs let you bundle game assets and distribute them to players through a purchase flow integrated with [Cartridge Controller](/controller/starter-packs).
The Arcade starter pack registry is a permissionless onchain system anyone can register a starter pack by deploying an implementation contract and calling `register`.
The Arcade starter pack registry is a permissionless onchain system --- anyone can register a starter pack by deploying an implementation contract and calling `register`.

## How It Works

The registry follows a two-contract pattern:

1. **Implementation contract** a contract you deploy that implements the `IStarterpackImplementation` interface.
1. **Implementation contract** --- a contract you deploy that implements the `IStarterpackImplementation` interface.
When a player purchases your starter pack, the registry calls your contract's `on_issue` function to distribute assets.
2. **Registry contract** the Arcade registry where you register your implementation, set pricing, and configure options.
2. **Registry contract** --- the Arcade registry where you register your implementation, set pricing, and configure options.

```
Player purchases → Registry collects payment → Registry calls on_issue → Your contract distributes assets
Expand Down Expand Up @@ -100,8 +100,8 @@ The returned ID is what players use to purchase the starter pack via [`controlle

Controls whether the same player can purchase the starter pack more than once.

- `false` each player can only purchase once, and `quantity` is forced to 1
- `true` players can purchase multiple times with any quantity
- `false` --- each player can only purchase once, and `quantity` is forced to 1
- `true` --- players can purchase multiple times with any quantity

### `referral_percentage`

Expand All @@ -113,7 +113,7 @@ Self-referrals (referrer == payer) are ignored.

Where the base price (minus any referral fee) is sent.
If `None`, payment goes to the starter pack owner (the address that called `register`).
If `Some(address)`, payment goes to that address instead useful for treasury contracts or revenue sharing.
If `Some(address)`, payment goes to that address instead --- useful for treasury contracts or revenue sharing.

### `conditional`

Expand Down Expand Up @@ -146,17 +146,17 @@ let metadata = MetadataTrait::new(

After registration, the owner can manage the starter pack:

- **`update`** change implementation, pricing, referral percentage, or other parameters
- **`update_metadata`** update the display metadata
- **`pause`** / **`resume`** temporarily disable or re-enable purchases
- **`update`** --- change implementation, pricing, referral percentage, or other parameters
- **`update_metadata`** --- update the display metadata
- **`pause`** / **`resume`** --- temporarily disable or re-enable purchases

## Payment Flow

When a player purchases a starter pack, the registry handles payment distribution:

1. **Referral fee** if a referrer is provided, their percentage is deducted from the base price and sent to them
2. **Protocol fee** a fee is added on top of the base price and sent to the Arcade fee receiver
3. **Owner payment** the remaining base price (after referral fee) is sent to the `payment_receiver` or owner
4. **Asset distribution** the registry calls `on_issue` on the implementation contract
1. **Referral fee** --- if a referrer is provided, their percentage is deducted from the base price and sent to them
2. **Protocol fee** --- a fee is added on top of the base price and sent to the Arcade fee receiver
3. **Owner payment** --- the remaining base price (after referral fee) is sent to the `payment_receiver` or owner
4. **Asset distribution** --- the registry calls `on_issue` on the implementation contract

If `price` is zero, all payment steps are skipped and `on_issue` is called directly.
6 changes: 3 additions & 3 deletions src/pages/services/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ title: Services Overview

Cartridge offers a set of platform services for onchain games and applications:

- **[Paymaster](/services/paymaster)** sponsor transaction fees so your users don't need to hold STRK for gas.
- **[RPC](/services/rpc)** Starknet RPC endpoints for mainnet and Sepolia, with API token and CORS-based authentication.
- **[vRNG](/services/vrng)** atomic, verifiable randomness for fully onchain games via EC-VRF on the Stark curve.
- **[Paymaster](/services/paymaster)** --- sponsor transaction fees so your users don't need to hold STRK for gas.
- **[RPC](/services/rpc)** --- Starknet RPC endpoints for mainnet and Sepolia, with API token and CORS-based authentication.
- **[vRNG](/services/vrng)** --- atomic, verifiable randomness for fully onchain games via EC-VRF on the Stark curve.

Each service is self-served via the CLI and can be used independently or together.
50 changes: 25 additions & 25 deletions src/pages/services/vrng/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ title: How vRNG Works

## The Onchain Randomness Problem

Blockchains are deterministic by design every node must compute the same result for every transaction.
Blockchains are deterministic by design --- every node must compute the same result for every transaction.
This makes genuine randomness impossible to produce from within a smart contract alone.

Common workarounds and their weaknesses:
Expand All @@ -18,26 +18,26 @@ Common workarounds and their weaknesses:
| Block hash / timestamp | Miners/sequencers can influence or predict these values |
| Commit-reveal schemes | Require multiple transactions across multiple blocks, adding latency and cost |
| Hash of onchain state | Anyone can compute the same hash and predict the outcome before submitting |
| External oracles (e.g. Chainlink VRF) | Randomness arrives in a *separate* transaction, breaking atomicity your game action resolves in one tx, but the random outcome arrives later |
| External oracles (e.g. Chainlink VRF) | Randomness arrives in a *separate* transaction, breaking atomicity --- your game action resolves in one tx, but the random outcome arrives later |

For onchain games, these tradeoffs are unacceptable.
A dice roll that takes two transactions and 30 seconds breaks the gameplay loop.
A sequencer that can predict outcomes breaks the game's integrity.

## The Core Idea

The [Cartridge Paymaster](/services/paymaster) already acts as an offchain executor it wraps player transactions for gas sponsorship and submits them onchain via Starknet's [SNIP-9](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-9.md) `execute_from_outside` protocol.
The [Cartridge Paymaster](/services/paymaster) already acts as an offchain executor --- it wraps player transactions for gas sponsorship and submits them onchain via Starknet's [SNIP-9](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-9.md) `execute_from_outside` protocol.

The vRNG extends this existing role.
In addition to sponsoring gas, the paymaster holds a **secret key** and uses it to generate a verifiable random number as part of the same execution flow.
The random value and its cryptographic proof are injected into the transaction *before* the player's game action executes, so the game contract can consume verified randomness atomically no extra transactions, no waiting.
The random value and its cryptographic proof are injected into the transaction *before* the player's game action executes, so the game contract can consume verified randomness atomically --- no extra transactions, no waiting.

This works because the paymaster is already in the transaction path.
The vRNG is not a separate oracle service; it's a natural extension of the execution infrastructure that's already there.

## Why Not Just Hash?

A hash function like `hash(seed)` is deterministic and publicly computable anyone with the seed can compute the output.
A hash function like `hash(seed)` is deterministic and publicly computable --- anyone with the seed can compute the output.
Since seeds are derived from onchain state, a player could predict the outcome before submitting their transaction.

A **Verifiable Random Function (VRF)** adds a secret key to the computation: `VRF(secret_key, seed) → (output, proof)`.
Expand All @@ -46,24 +46,24 @@ Only the key holder can compute the output, but anyone can *verify* it was compu
| | Hash | VRF |
| --- | --- | --- |
| **Who can compute** | Anyone with the input | Only the secret key holder |
| **Predictable?** | Yes inputs are public | No requires the secret key |
| **Verifiable?** | Trivially (recompute it) | Yes via cryptographic proof |
| **Manipulable?** | No (but predictable = exploitable) | No deterministic for a given seed and key |
| **Predictable?** | Yes --- inputs are public | No --- requires the secret key |
| **Verifiable?** | Trivially (recompute it) | Yes --- via cryptographic proof |
| **Manipulable?** | No (but predictable = exploitable) | No --- deterministic for a given seed and key |

The "verifiable" part is what distinguishes a VRF from simple encryption the proof ensures the key holder can't lie about what the output should be for a given input.
The "verifiable" part is what distinguishes a VRF from simple encryption --- the proof ensures the key holder can't lie about what the output should be for a given input.

## Cryptographic Details

Cartridge's vRNG uses an **Elliptic Curve VRF (EC-VRF)** built on the Stark curve the native curve of Starknet, which enables efficient onchain verification via Poseidon hashing.
Cartridge's vRNG uses an **Elliptic Curve VRF (EC-VRF)** built on the Stark curve --- the native curve of Starknet, which enables efficient onchain verification via Poseidon hashing.

### Proof Structure

The VRF provider generates a proof consisting of:

- **gamma** a point on the Stark curve (the core VRF output)
- **c** a scalar challenge value
- **s** a scalar response value
- **sqrt_ratio_hint** an optimization hint for efficient onchain verification
- **gamma** --- a point on the Stark curve (the core VRF output)
- **c** --- a scalar challenge value
- **s** --- a scalar response value
- **sqrt_ratio_hint** --- an optimization hint for efficient onchain verification

The random value is derived from `gamma` via hashing.
The `(c, s)` pair constitutes a Schnorr-like proof that `gamma` was correctly computed from the seed and the provider's secret key.
Expand Down Expand Up @@ -118,27 +118,27 @@ The paymaster intercepts it, generates the VRF proof, and wraps everything into

### Step by Step

1. **Player signs their game action** the player's wallet signs a multicall containing `request_random` + the game call (e.g. `roll_dice`).
1. **Player signs their game action** --- the player's wallet signs a multicall containing `request_random` + the game call (e.g. `roll_dice`).
This is the inner SNIP-9 outside execution.

2. **Paymaster intercepts** the paymaster sees the `request_random` call, computes the seed from the source parameters, and generates the VRF proof using its secret key.
2. **Paymaster intercepts** --- the paymaster sees the `request_random` call, computes the seed from the source parameters, and generates the VRF proof using its secret key.

3. **Paymaster wraps with proof injection** the paymaster constructs an outer SNIP-9 execution signed by the VRF Account that prepends `submit_random(seed, proof)` before executing the player's calls.
3. **Paymaster wraps with proof injection** --- the paymaster constructs an outer SNIP-9 execution signed by the VRF Account that prepends `submit_random(seed, proof)` before executing the player's calls.

4. **Onchain verification** `submit_random` verifies the EC-VRF proof against the VRF Account's stored public key.
4. **Onchain verification** --- `submit_random` verifies the EC-VRF proof against the VRF Account's stored public key.
If valid, the derived random value is stored for this transaction.

5. **Game consumes randomness** when the game contract calls `consume_random(source)`, it reads the verified value from the VRF provider's storage.
5. **Game consumes randomness** --- when the game contract calls `consume_random(source)`, it reads the verified value from the VRF provider's storage.

6. **Cleanup** `assert_consumed` ensures the random value was actually used and clears storage, preventing stale values from persisting.
6. **Cleanup** --- `assert_consumed` ensures the random value was actually used and clears storage, preventing stale values from persisting.

### Why Nested Execution?

The nesting serves two purposes:

- **Proof injection without player awareness** the player only signs their game action.
- **Proof injection without player awareness** --- the player only signs their game action.
The VRF proof is added by the paymaster in the outer layer, invisible to the player.
- **Atomic execution** proof verification and consumption happen in the same transaction.
- **Atomic execution** --- proof verification and consumption happen in the same transaction.
There is no window where the random value exists but hasn't been used, and no second transaction to wait for.

## Security Model
Expand All @@ -148,9 +148,9 @@ There is no window where the random value exists but hasn't been used, and no se
The security assumption is that the **paymaster has not revealed its VRF secret key** and does not collude with players.

Given this assumption:
- The provider cannot choose a favorable random value the VRF is deterministic for a given seed, and the seed is derived from onchain state the provider doesn't control.
- Players cannot predict the random value they don't have the provider's secret key.
- Anyone can verify after the fact the proof and public key are onchain.
- The provider cannot choose a favorable random value --- the VRF is deterministic for a given seed, and the seed is derived from onchain state the provider doesn't control.
- Players cannot predict the random value --- they don't have the provider's secret key.
- Anyone can verify after the fact --- the proof and public key are onchain.

The main trust assumption is that the provider isn't selectively *withholding* unfavorable results (censorship).

Expand Down