# Distribution Layer
Source: https://docs.peridotvault.com/architecture/core/distribution-layer
• distribution-layer
* Web-based game store
* Metadata system
* Game delivery pipeline
# Identity layer
Source: https://docs.peridotvault.com/architecture/core/identity-layer
• identity-layer
* Wallet-based authentication
* Role separation (User / Developer)
* Access control logic
# License layer
Source: https://docs.peridotvault.com/architecture/core/license-layer
• license-layer
* Smart contract ownership
* Multi-chain validation
* Wallet interaction model
# Offchain services
Source: https://docs.peridotvault.com/architecture/system-design/offchain-services
• offchain-services
* Payment integration
* Subscription handling
* Indexing service
* API layer
# Smart contracts
Source: https://docs.peridotvault.com/architecture/system-design/smart-contracts
# Storage architecture
Source: https://docs.peridotvault.com/architecture/system-design/storage-architecture
• storage-architecture
* Game asset hosting (Wasabi / S3-like)
* Metadata handling
* Off-chain storage logic
# Factory
Source: https://docs.peridotvault.com/dev/game-licensing/factory
Deploys new PGC-1 contracts and automates initial setup for developers.
***
## Overview
Factory is the developer onboarding layer for Peridot.
Responsibilities:
* Deploy new PGC-1 contracts
* Initialize canonical game data
* Authorize Game Store as minter
* Register the game in Registry
* Reduce manual setup for developers
Factory does NOT handle pricing, payments for game purchases, moderation, or license ownership.
***
## Dependencies
| Component | Purpose |
| ---------- | ------------------------------- |
| PGC-1 | Game-specific license contract |
| Registry | Game registration and validity |
| Game Store | Authorized minter for purchases |
***
## Data Structures
### DeploymentConfig
| Field | Type | Description |
| ----------- | ------ | ---------------------- |
| gameId | string | Unique game identifier |
| metadataURI | string | Canonical metadata URI |
***
## State
| Variable | Type | Description |
| ---------- | ------- | --------------------------- |
| registry | address | Registry contract address |
| gameStore | address | Game Store contract address |
| governance | address | Governance address |
***
## Functions
### 1. createGame
Deploys a new PGC-1 contract and performs initial setup.
`function createGame(gameId, metadataURI)`
#### Params
| Name | Type | Description |
| ----------- | ------ | ---------------------- |
| gameId | string | Unique game identifier |
| metadataURI | string | Canonical metadata URI |
#### Rules
* `gameId` MUST NOT be empty
* `metadataURI` MUST NOT be empty
* Registry registration MUST succeed
* Game Store authorization MUST succeed
* Factory MUST deploy exactly one PGC-1 contract for this call
#### Flow
1. Deploy new PGC-1 contract
2. Initialize:
* `gameId`
* `publisher = msg.sender`
* `metadataURI`
3. Authorize `gameStore` as minter in PGC-1
4. Register game in Registry
5. Return deployed contract address
#### Returns
| Type | Description |
| ------- | ----------------------- |
| address | Deployed PGC-1 contract |
#### Notes
* Registration fee policy is enforced by Registry
* If publisher is fee-exempt in Registry, registration proceeds without fee
* Entire process SHOULD revert if any step fails
***
### 2. setRegistry
Updates Registry contract address.
`function setRegistry(registry)`
#### Params
| Name | Type | Description |
| -------- | ------- | ----------------------------- |
| registry | address | New Registry contract address |
#### Rules
* Only governance
* `registry` MUST NOT be zero address
* Event SHOULD be emitted
***
### 3. setGameStore
Updates Game Store contract address.
`function setGameStore(gameStore)`
#### Params
| Name | Type | Description |
| --------- | ------- | ------------------------------- |
| gameStore | address | New Game Store contract address |
#### Rules
* Only governance
* `gameStore` MUST NOT be zero address
* Event SHOULD be emitted
***
### 4. setGovernance
Updates governance address.
`function setGovernance(governance)`
#### Params
| Name | Type | Description |
| ---------- | ------- | ---------------------- |
| governance | address | New governance address |
#### Rules
* Only current governance
* `governance` MUST NOT be zero address
* Event SHOULD be emitted
***
### 5. getRegistry
Returns Registry contract address.
`function getRegistry()`
#### Returns
| Type | Description |
| ------- | ------------------------- |
| address | Registry contract address |
***
### 6. getGameStore
Returns Game Store contract address.
`function getGameStore()`
#### Returns
| Type | Description |
| ------- | --------------------------- |
| address | Game Store contract address |
***
### 7. getGovernance
Returns governance address.
`function getGovernance()`
#### Returns
| Type | Description |
| ------- | ------------------ |
| address | Governance address |
***
## Access Control
| Function | Access |
| ------------- | ---------- |
| createGame | Public |
| setRegistry | Governance |
| setGameStore | Governance |
| setGovernance | Governance |
| getRegistry | Public |
| getGameStore | Public |
| getGovernance | Public |
***
## Requirements
* Factory MUST deploy a valid PGC-1 contract
* Factory MUST initialize `gameId`, `publisher`, and `metadataURI` in PGC-1
* Factory MUST authorize Game Store as minter in PGC-1
* Factory MUST register the deployed PGC-1 contract in Registry
* `gameId` MUST match the canonical `gameId` stored in PGC-1
* Entire deployment and registration flow SHOULD be atomic
***
## Notes
* Factory is an orchestration layer, not a source of truth
* Publisher and metadata belong to PGC-1
* Game validity belongs to Registry
* Pricing and purchase flow belong to Game Store
* Factory is intended to improve developer experience and reduce manual errors
# Game Store
Source: https://docs.peridotvault.com/dev/game-licensing/game-store
Handles payments and license minting for PGC-1.
***
## Overview
Game Store is the execution layer for purchasing games.
Responsibilities:
* Validate game from Registry
* Process payment
* Mint license via [PGC-1](/dev/game-licensing/pgc1)
Game Store does NOT store metadata or governance logic.
***
## Dependencies
| Component | Purpose |
| --------------------------------- | ----------------------------- |
| [PGC-1](/dev/game-licensing/pgc1) | License minting |
| Registry | Source of truth for game data |
| Treasury | Platform fee receiver |
***
## Data Structures
### PriceConfig
| Field | Type | Description |
| ----------- | ------- | --------------------- |
| price | uint256 | Base price |
| currency | address | Payment token address |
| discountBps | uint16 | Discount in bps |
***
## State
| Variable | Type | Description |
| ----------------- | ----------------------------------------------- | ---------------------------- |
| registry | address | Address of Registry contract |
| governance | address | Governance Role |
| treasury | address | Platform fee receiver |
| prices | mapping(string => PriceConfig) | Game pricing |
| platformFeeBps | uint16 | Platform fee (basis points) |
| publisherBalances | mapping(address => mapping(address => uint256)) | Publisher earnings per token |
***
## Functions
### 1. setPrice
Sets base price for a game.
`function setPrice(gameId, price, currency)`
#### Params
| Name | Type | Description |
| -------- | ------- | --------------- |
| gameId | string | Game identifier |
| price | uint256 | Base price |
| currency | address | Payment token |
#### Rules
* Only publisher
* msg.sender MUST match `PGC1(contractAddress).getPublisher()`
* `currency` MUST be a valid supported payment token
* Game MUST exist in Registry
* `price` MAY be 0 for free games
### 2. setDiscount
Sets discount in basis points.
`function setDiscount(gameId, discountBps)`
#### Params
| Name | Type | Description |
| ----------- | ------ | -------------------------- |
| gameId | string | Game identifier |
| discountBps | uint16 | Discount (e.g. 1000 = 10%) |
#### Rules
* Only publisher
* msg.sender MUST match `PGC1(contractAddress).getPublisher()`
* `discountBps` MUST be `<=` 10000
### 3. getFinalPrice
Returns final price after discount.
`function getFinalPrice(gameId): uint256`
#### Returns
| Type | Description |
| ------- | ----------- |
| uint256 | Final price |
#### Logic
finalPrice = price - (price \* discountBps / 10000)
### 4. buyGame
Executes purchase and mints license.
`function buyGame(gameId)`
#### Flow
1. Fetch game from Registry
2. Validate `status == approved`
3. Validate `game.contractAddress` exists
4. Get PGC-1 contract
5. Get publisher:
* `publisher = PGC1.getPublisher()`
6. Load `PriceConfig`
* `currency = prices[gameId].currency`
7. Calculate `finalPrice`
8. Validate payment token and amount
9. Prevent duplicate purchase by checking `PGC1.canAccessGame(msg.sender)`
10. Calculate:
* `platformFee`
* `publisherRevenue`
11. Receive payment
12. Process split:
* `transfer(platformFee → treasury)`
* `publisherBalances[publisher][currency] += publisherRevenue`
13. Call `PGC1.mintLicense(msg.sender, 0)`
14. Revert whole transaction if mint fails
#### Internal Calls
* `const game = Registry.getGame(gameId)`
* `const finalPrice = getFinalPrice(gameId)`
* `PGC1(game.contractAddress).mintLicense(msg.sender, 0)`
* `publisherBalances[publisher][currency] += publisherRevenue`
#### Rules
* If `finalPrice == 0`, payment transfer MAY be skipped
* Game **MUST** have a valid PriceConfig before purchase **(Including Free Game)**
* Purchase, accounting update, and minting MUST be executed atomically
* Mint **MUST** only happen AFTER payment is recorded
* If mint fails → transaction **MUST** revert
* Double purchase **MUST** be prevented if the buyer already owns a valid license for the same game.
### 5. setPlatformFee
Updates platform fee.
`function setPlatformFee(feeBps)`
#### Params
| Name | Type | Description |
| ------ | ------ | ------------------- |
| feeBps | uint16 | Fee in basis points |
#### Rules
* Only governance
* `feeBps` MUST be `<=` 10000
### 6. withdraw
Withdraw publisher earnings per token.
`function withdraw(token)`
#### Params
| Name | Type | Description |
| ----- | ------- | ------------- |
| token | address | Token address |
#### Rules
* Only publisher
* Balance MUST be > 0
* Withdrawal MUST revert if transfer fails
#### Behavior
* `amount = publisherBalances[msg.sender][token]`
* `publisherBalances[msg.sender][token] = 0`
* `transfer(token → msg.sender)`
### 7. setGovernance
Updates governance address.
`function setGovernance(governance)`
#### Params
| Name | Type | Description |
| ---------- | ------- | ---------------------- |
| governance | address | New governance address |
#### Rules
* Only current governance
* Governance MUST NOT be zero address
* Event SHOULD be emitted
### 8. setTreasury
Updates treasury receiver address.
`function setTreasury(treasury)`
#### Params
| Name | Type | Description |
| -------- | ------- | --------------------- |
| treasury | address | New treasury receiver |
#### Rules
* Only governance
* Treasury MUST NOT be zero address
* Event SHOULD be emitted
### 9. getPriceConfig
Returns pricing configuration for a game.
`function getPriceConfig(gameId)`
#### Params
| Name | Type | Description |
| ------ | ------ | --------------- |
| gameId | string | Game identifier |
#### Returns
| Name | Type | Description |
| ----------- | ------- | --------------------- |
| price | uint256 | Base price |
| currency | address | Payment token address |
| discountBps | uint16 | Discount in bps |
### 10. getPublisherBalance
Returns withdrawable publisher balance for a token.
`function getPublisherBalance(publisher, token)`
#### Params
| Name | Type | Description |
| --------- | ------- | ----------------- |
| publisher | address | Publisher address |
| token | address | Token address |
#### Returns
| Type | Description |
| ------- | -------------------------- |
| uint256 | Withdrawable token balance |
### 11. getPlatformFee
Returns current platform fee in basis points.
`function getPlatformFee()`
#### Returns
| Type | Description |
| ------ | ---------------------------- |
| uint16 | Platform fee in basis points |
### 12. getTreasury
Returns treasury receiver address.
`function getTreasury()`
#### Returns
| Type | Description |
| ------- | ------------------------- |
| address | Treasury receiver address |
### 13. getGovernance
Returns governance address.
`function getGovernance()`
#### Returns
| Type | Description |
| ------- | ------------------ |
| address | Governance address |
### 14. getRegistry
Returns registry contract address.
`function getRegistry()`
#### Returns
| Type | Description |
| ------- | ---------------- |
| address | Registry address |
***
## Payment Flow
**Hybrid (Push + Escrow)** Payments are split during purchase:
* Platform fee → sent directly to treasury
* Publisher revenue → stored in contract (escrow)
***
### Flow
1. User pays `finalPrice`
2. Contract calculates:
* platformFee
* publisherRevenue
3. Execute transfers:
* send platform fee to treasury
* `publisherBalances[publisher][currency] += publisherRevenue`
4. Mint license
### Withdraw
* Publisher MUST call `withdraw(token)` to claim revenue
* Treasury does NOT use withdraw, because platform fee is transferred directly during purchase
***
## Revenue Split
| Component | Formula |
| ---------------- | ------------------------------------ |
| platformFee | finalPrice \* platformFeeBps / 10000 |
| publisherRevenue | finalPrice - platformFee |
***
## Access Control
| Function | Access |
| ------------------- | ---------- |
| setPrice | Publisher |
| setDiscount | Publisher |
| withdraw | Publisher |
| getFinalPrice | Public |
| buyGame | Public |
| setPlatformFee | Governance |
| setGovernance | Governance |
| setTreasury | Governance |
| getPriceConfig | Public |
| getPublisherBalance | Public |
| getPlatformFee | Public |
| getTreasury | Public |
| getGovernance | Public |
| getRegistry | Public |
***
## Requirements
* Game MUST be `approved` in Registry
* Registry MUST return a valid `contractAddress`
* Registry MUST return game status
* Store MUST be authorized minter in PGC-1
* PGC-1 MUST implement `getPublisher()`
* PGC-1 MUST implement `canAccessGame(user)`
* PGC-1 MUST implement `mintLicense(to, expiresAt)`
* Payment MUST succeed before mint
***
## Notes
* Price is dynamic (not stored in Registry)
* Supports future extensions:
* subscription
* bundle
* regional pricing
# License smart contract
Source: https://docs.peridotvault.com/dev/game-licensing/license-smart-contract
• license-smart-contract
* Ownership structure
* Chain deployment options
* Verification logic
# Nft integration
Source: https://docs.peridotvault.com/dev/game-licensing/nft-integration
• nft-integration
* Optional NFT support
* Trading logic
* 2.5% fee structure
# PGC-1
Source: https://docs.peridotvault.com/dev/game-licensing/pgc1
A cross-chain standard for representing game ownership and access rights through non-transferable programmable licenses.
***
## Overview
PGC-1 is the ownership and access layer for a single game in Peridot.
Responsibilities:
* Store canonical `gameId`
* Store canonical publisher address
* Store canonical metadata URI
* Initialize canonical game state during deployment
* Mint non-transferable licenses
* Provide entitlement and access checks
* Manage authorized minters
* Preserve the strongest valid entitlement for each user
PGC-1 does NOT handle pricing, payments, moderation, catalog listing, or publisher-wide subscriptions.
***
## Data Structures
### LicensePolicy
| Field | Type | Description |
| --------- | ------ | -------------------------------- |
| issuedAt | uint64 | Timestamp when license is minted |
| expiresAt | uint64 | Expiration timestamp |
#### Rules
* `expiresAt = 0` means permanent license
* `expiresAt > now` means temporary valid license
* `expiresAt < now` means expired license
***
## State
| Variable | Type | Description |
| ----------- | --------------------------------- | ------------------------------- |
| gameId | string | Canonical game identifier |
| publisher | address | Canonical publisher address |
| metadataURI | string | Canonical metadata URI |
| minters | mapping(address => bool) | Authorized minters |
| licenses | mapping(address => LicensePolicy) | User license policy per account |
***
## Functions
### 1. initialize
Initializes canonical game state.
`function initialize(gameId, publisher, metadataURI, initialMinter)`
#### Params
| Name | Type | Description |
| ------------- | ------- | --------------------------- |
| gameId | string | Canonical game identifier |
| publisher | address | Canonical publisher address |
| metadataURI | string | Canonical metadata URI |
| initialMinter | address | Initial authorized minter |
#### Rules
* MUST only be callable once
* `gameId` MUST NOT be empty
* `publisher` MUST NOT be zero address
* `metadataURI` MUST NOT be empty
* `initialMinter` MUST NOT be zero address
#### Behavior
* set canonical `gameId`
* set canonical `publisher`
* set canonical `metadataURI`
* authorize `initialMinter`
#### Notes
* On EVM implementations this MAY be represented by constructor arguments
* On non-constructor environments this SHOULD be represented by an initialization function
***
### 2. mintLicense
Grants or upgrades a license for a user.
`function mintLicense(to, expiresAt)`
#### Params
| Name | Type | Description |
| --------- | ------- | ---------------------------- |
| to | address | Receiver address |
| expiresAt | uint64 | License expiration timestamp |
#### Rules
* Only authorized minter
* `to` MUST NOT be zero address
* Permanent license MUST NOT be downgraded by a temporary license
* The strongest valid entitlement MUST be preserved
#### Behavior
If the user has no license:
* create new license
If the user has an expired license:
* replace with incoming license
If the user has a temporary license and incoming license is permanent:
* upgrade to permanent
If the user has a permanent license and incoming license is temporary:
* keep permanent license
* incoming temporary license MUST NOT downgrade access
If the user has a temporary license and incoming temporary license expires later:
* extend or replace with later expiry
If the user has a temporary license and incoming temporary license expires earlier:
* keep current license
***
### 3. hasLicense
Returns whether a user owns a valid license for this game.
`function hasLicense(user)`
#### Params
| Name | Type | Description |
| ---- | ------- | ------------ |
| user | address | User address |
#### Returns
| Type | Description |
| ---- | --------------------------------- |
| bool | True if user owns a valid license |
#### Rules
* Expired licenses MUST return `false`
***
### 4. canAccessGame
Returns whether a user can currently access this game.
`function canAccessGame(user)`
#### Params
| Name | Type | Description |
| ---- | ------- | ------------ |
| user | address | User address |
#### Returns
| Type | Description |
| ---- | -------------------------------------------- |
| bool | True if user has a valid non-expired license |
#### Rules
* Expired licenses MUST return `false`
#### Notes
* This function is suitable as an entitlement check for launcher access, download authorization, and future DRM-like enforcement
* This function alone is NOT a complete DRM system
***
### 5. getLicensePolicy
Returns license policy data for a user.
`function getLicensePolicy(user)`
#### Params
| Name | Type | Description |
| ---- | ------- | ------------ |
| user | address | User address |
#### Returns
| Name | Type | Description |
| --------- | ------ | --------------------------------- |
| issuedAt | uint64 | Timestamp when license was minted |
| expiresAt | uint64 | Expiration timestamp |
***
### 6. setMinter
Updates minter authorization.
`function setMinter(account, isAuthorized)`
#### Params
| Name | Type | Description |
| ------------ | ------- | -------------------- |
| account | address | Minter address |
| isAuthorized | bool | Authorization status |
#### Rules
* Only publisher
* `account` MUST NOT be zero address
* Event SHOULD be emitted
***
### 7. isMinter
Returns whether an account is an authorized minter.
`function isMinter(account)`
#### Params
| Name | Type | Description |
| ------- | ------- | --------------- |
| account | address | Account address |
#### Returns
| Type | Description |
| ---- | ------------------------ |
| bool | Authorized minter status |
***
### 8. getPublisher
Returns canonical publisher address.
`function getPublisher()`
#### Returns
| Type | Description |
| ------- | ----------------- |
| address | Publisher address |
***
### 9. getMetadataURI
Returns canonical metadata URI.
`function getMetadataURI()`
#### Returns
| Type | Description |
| ------ | ------------ |
| string | Metadata URI |
***
### 10. getGameId
Returns canonical game identifier.
`function getGameId()`
#### Returns
| Type | Description |
| ------ | --------------- |
| string | Game identifier |
***
### 11. setPublisher
Updates publisher address.
`function setPublisher(publisher)`
#### Params
| Name | Type | Description |
| --------- | ------- | --------------------- |
| publisher | address | New publisher address |
#### Rules
* Only current publisher
* `publisher` MUST NOT be zero address
* Event SHOULD be emitted
#### Notes
* This function is optional if publisher is intended to be immutable in a specific implementation
***
### 12. setMetadataURI
Updates metadata URI.
`function setMetadataURI(metadataURI)`
#### Params
| Name | Type | Description |
| ----------- | ------ | ---------------- |
| metadataURI | string | New metadata URI |
#### Rules
* Only publisher
* `metadataURI` MUST NOT be empty
* Event SHOULD be emitted
#### Notes
* This function is optional if metadata is intended to be immutable in a specific implementation
***
## Access Control
| Function | Access |
| ---------------- | ----------------- |
| initialize | Deployment only |
| mintLicense | Authorized Minter |
| hasLicense | Public |
| canAccessGame | Public |
| getLicensePolicy | Public |
| setMinter | Publisher |
| isMinter | Public |
| getPublisher | Public |
| getMetadataURI | Public |
| getGameId | Public |
| setPublisher | Publisher |
| setMetadataURI | Publisher |
***
## Requirements
* `initialize()` MUST set canonical `gameId`, `publisher`, and `metadataURI`
* `initialize()` MUST only be executable once
* `gameId` MUST be stored in PGC-1
* `publisher` MUST be stored in PGC-1
* `metadataURI` MUST be stored in PGC-1
* `mintLicense()` MUST only be callable by authorized minters
* `getPublisher()` MUST return the canonical publisher for the game
* `getMetadataURI()` MUST return the canonical metadata URI for the game
* `getGameId()` MUST return the canonical game identifier
* `hasLicense(user)` MUST return `false` for expired licenses
* `canAccessGame(user)` MUST return `false` for expired licenses
* Licenses MUST remain non-transferable
* Permanent licenses MUST NOT be downgraded by temporary licenses
* The strongest valid entitlement MUST be preserved for each user
***
## Transferability
PGC-1 licenses are strictly non-transferable.
Implementations MUST ensure:
* licenses cannot be transferred between users
* any transfer attempt MUST fail
***
## Subscription Compatibility
PGC-1 is intended for game-specific entitlement.
Publisher-wide subscriptions, game bundles, or ecosystem-wide passes SHOULD be implemented in a separate access layer or contract.
Such systems MAY grant additional access, but MUST NOT invalidate or downgrade a stronger permanent game license already held by the user.
***
## Notes
* PGC-1 is the source of truth for publisher and metadata
* Registry is the source of truth for game validity and moderation
* Game Store is the source of truth for pricing and purchase flow
* PGC-1 should remain minimal and ownership-focused
***
## Chain Support
PGC-1 is designed to be chain-agnostic.
### EVM
* Built on top of ERC-1155
* Extended with license logic
* Transfer behavior MUST be disabled or restricted
### Solana
* Implemented using Token-2022
* Extensions: NonTransferable, Metadata Pointer
# Registry
Source: https://docs.peridotvault.com/dev/game-licensing/registry
Source of truth for game registration, game status, and PGC-1 contract mapping.
***
## Overview
Registry is the source of truth for game validity in Peridot.
Responsibilities:
* Register games
* Store PGC-1 contract address
* Store game status
* Enforce registration fee policy
* Support trusted factory-based registration
* Manage moderation and governance decisions
* Provide game listing data for catalog and indexing
Registry does NOT store publisher, metadata, pricing, or ownership.
***
## Dependencies
| Component | Purpose |
| ---------- | -------------------------------- |
| PGC-1 | Source of publisher and metadata |
| Governance | Status control and fee policy |
| Treasury | Registration fee receiver |
| Factory | Trusted one-click game creation |
***
## Data Structures
### Game
| Field | Type | Description |
| --------------- | ------- | ---------------------- |
| gameId | string | Unique game identifier |
| contractAddress | address | PGC-1 contract address |
| status | uint8 | Game status |
### Status
| Value | Meaning |
| ----- | -------- |
| 0 | Pending |
| 1 | Approved |
| 2 | Banned |
***
## State
| Variable | Type | Description |
| -------------------- | ------------------------ | ------------------------------ |
| governance | address | Governance address |
| treasury | address | Registration fee receiver |
| factory | address | Trusted factory address |
| registrationFee | uint256 | Base registration fee |
| registrationFeeToken | address | Registration fee token address |
| feeExemptions | mapping(address => bool) | Free registration allowlist |
| admins | mapping(address => bool) | Admin / moderator allowlist |
| games | mapping(string => Game) | Registered games |
| allGameIds | string\[] | All registered game IDs |
***
## Functions
### 1. registerGame
Registers a new game directly by publisher.
`function registerGame(gameId, contractAddress)`
#### Params
| Name | Type | Description |
| --------------- | ------- | ---------------------- |
| gameId | string | Unique game identifier |
| contractAddress | address | PGC-1 contract address |
#### Rules
* Only publisher
* `gameId` MUST be unique
* `contractAddress` MUST NOT be zero address
* Registration fee MUST be paid unless publisher is fee-exempt
* Initial status MUST be `Pending`
#### Behavior
* `publisher = PGC1(contractAddress).getPublisher()`
* `canonicalGameId = PGC1(contractAddress).getGameId()`
* `msg.sender` MUST equal `publisher`
* `gameId` MUST match `canonicalGameId`
* collect registration fee if required
* send registration fee to treasury
* store game data
* append `gameId` to `allGameIds`
* set `status = Pending`
***
### 2. registerGameByFactory
Registers a new game through trusted factory flow.
`function registerGameByFactory(gameId, contractAddress, publisher)`
#### Params
| Name | Type | Description |
| --------------- | ------- | --------------------------- |
| gameId | string | Unique game identifier |
| contractAddress | address | PGC-1 contract address |
| publisher | address | Canonical publisher address |
#### Rules
* Only trusted factory
* `gameId` MUST be unique
* `contractAddress` MUST NOT be zero address
* `publisher` MUST NOT be zero address
* Registration fee policy MUST still be enforced unless publisher is fee-exempt
* Initial status MUST be `Pending`
#### Behavior
* `canonicalPublisher = PGC1(contractAddress).getPublisher()`
* `canonicalGameId = PGC1(contractAddress).getGameId()`
* `publisher` MUST match `canonicalPublisher`
* `gameId` MUST match `canonicalGameId`
* collect or verify registration fee settlement if required
* send registration fee to treasury
* store game data
* append `gameId` to `allGameIds`
* set `status = Pending`
#### Notes
* This function is intended for one-click Factory onboarding
* Registration fee MAY be settled by Factory on behalf of publisher in the same transaction
***
### 3. setStatus
Updates game status.
`function setStatus(gameId, status)`
#### Params
| Name | Type | Description |
| ------ | ------ | --------------- |
| gameId | string | Game identifier |
| status | uint8 | New status |
#### Rules
* Only admin
* Game MUST exist
* `status` MUST be one of:
* `0` Pending
* `1` Approved
* `2` Banned
***
### 4. setAdmin
Updates admin status for an account.
`function setAdmin(account, isAdmin)`
#### Params
| Name | Type | Description |
| ------- | ------- | ------------- |
| account | address | Admin address |
| isAdmin | bool | Admin status |
#### Rules
* Only governance
* `account` MUST NOT be zero address
* Event SHOULD be emitted
***
### 5. setGovernance
Updates governance address.
`function setGovernance(governance)`
#### Params
| Name | Type | Description |
| ---------- | ------- | ---------------------- |
| governance | address | New governance address |
#### Rules
* Only current governance
* `governance` MUST NOT be zero address
* Event SHOULD be emitted
***
### 6. setTreasury
Updates treasury receiver address.
`function setTreasury(treasury)`
#### Params
| Name | Type | Description |
| -------- | ------- | --------------------- |
| treasury | address | New treasury receiver |
#### Rules
* Only governance
* `treasury` MUST NOT be zero address
* Event SHOULD be emitted
***
### 7. setFactory
Updates trusted factory address.
`function setFactory(factory)`
#### Params
| Name | Type | Description |
| ------- | ------- | ----------------------- |
| factory | address | Trusted factory address |
#### Rules
* Only governance
* `factory` MUST NOT be zero address
* Event SHOULD be emitted
***
### 8. setRegistrationFee
Updates registration fee configuration.
`function setRegistrationFee(amount, token)`
#### Params
| Name | Type | Description |
| ------ | ------- | ------------------------------ |
| amount | uint256 | Registration fee amount |
| token | address | Registration fee token address |
#### Rules
* Only governance
* `token` MUST be a valid supported payment token
* Event SHOULD be emitted
***
### 9. setFeeExemption
Updates fee exemption status for a publisher or studio.
`function setFeeExemption(account, isExempt)`
#### Params
| Name | Type | Description |
| -------- | ------- | --------------------------- |
| account | address | Publisher or studio address |
| isExempt | bool | Exemption status |
#### Rules
* Only governance
* `account` MUST NOT be zero address
* Event SHOULD be emitted
#### Notes
* `isExempt = true` grants free registration
* `isExempt = false` removes free registration access
***
### 10. getGame
Returns full game data.
`function getGame(gameId)`
#### Params
| Name | Type | Description |
| ------ | ------ | --------------- |
| gameId | string | Game identifier |
#### Returns
| Name | Type | Description |
| --------------- | ------- | ---------------------- |
| gameId | string | Game identifier |
| contractAddress | address | PGC-1 contract address |
| status | uint8 | Current status |
***
### 11. getAllGames
Returns all registered games.
`function getAllGames()`
#### Returns
| Type | Description |
| ------- | ------------------------ |
| Game\[] | All registered game data |
#### Notes
* Recommended for early-stage use
* For large scale deployments, off-chain indexing is recommended
***
### 12. getContractAddress
Returns PGC-1 contract address for a game.
`function getContractAddress(gameId)`
#### Params
| Name | Type | Description |
| ------ | ------ | --------------- |
| gameId | string | Game identifier |
#### Returns
| Type | Description |
| ------- | ---------------------- |
| address | PGC-1 contract address |
***
### 13. getStatus
Returns current game status.
`function getStatus(gameId)`
#### Params
| Name | Type | Description |
| ------ | ------ | --------------- |
| gameId | string | Game identifier |
#### Returns
| Type | Description |
| ----- | ----------- |
| uint8 | Game status |
***
### 14. getGovernance
Returns governance address.
`function getGovernance()`
#### Returns
| Type | Description |
| ------- | ------------------ |
| address | Governance address |
***
### 15. getTreasury
Returns treasury receiver address.
`function getTreasury()`
#### Returns
| Type | Description |
| ------- | ------------------------- |
| address | Treasury receiver address |
***
### 16. getFactory
Returns trusted factory address.
`function getFactory()`
#### Returns
| Type | Description |
| ------- | --------------- |
| address | Factory address |
***
### 17. getRegistrationFee
Returns current registration fee configuration.
`function getRegistrationFee()`
#### Returns
| Name | Type | Description |
| ------ | ------- | ------------------------------ |
| amount | uint256 | Registration fee amount |
| token | address | Registration fee token address |
***
### 18. isFeeExempt
Returns whether an account is exempt from registration fee.
`function isFeeExempt(account)`
#### Params
| Name | Type | Description |
| ------- | ------- | --------------------------- |
| account | address | Publisher or studio address |
#### Returns
| Type | Description |
| ---- | -------------------------- |
| bool | Registration fee exemption |
***
### 19. isAdmin
Returns whether an account has admin access.
`function isAdmin(account)`
#### Params
| Name | Type | Description |
| ------- | ------- | --------------- |
| account | address | Account address |
#### Returns
| Type | Description |
| ---- | ------------ |
| bool | Admin status |
***
## Access Control
| Function | Access |
| --------------------- | ---------- |
| registerGame | Publisher |
| registerGameByFactory | Factory |
| setStatus | Admin |
| setAdmin | Governance |
| setGovernance | Governance |
| setTreasury | Governance |
| setFactory | Governance |
| setRegistrationFee | Governance |
| setFeeExemption | Governance |
| getGame | Public |
| getAllGames | Public |
| getContractAddress | Public |
| getStatus | Public |
| getGovernance | Public |
| getTreasury | Public |
| getFactory | Public |
| getRegistrationFee | Public |
| isFeeExempt | Public |
| isAdmin | Public |
***
## Requirements
* Every `gameId` MUST be unique
* Every registered game MUST have a valid `contractAddress`
* `PGC-1` MUST implement `getPublisher()`
* `PGC-1` MUST implement `getGameId()`
* `gameId` MUST match `PGC-1.getGameId()`
* Direct registration MUST require `msg.sender == PGC-1.getPublisher()`
* Factory registration MUST require `publisher == PGC-1.getPublisher()`
* Banned games MUST remain queryable
* Registry MUST act as source of truth for game validity
* Registration fee policy MUST be enforced during registration
* Fee exemption MUST bypass registration fee without transferring value to publisher
***
## Notes
* Registry stores game validity, not pricing
* Publisher and metadata belong to PGC-1
* Pricing belongs to Game Store
* Ownership belongs to PGC-1
* Registry is responsible for moderation and governance decisions
* Fee exemption is intended for grants, partnerships, and hackathon support
* `getAllGames()` is suitable for early-stage scale
* Large-scale catalog indexing SHOULD move to off-chain infrastructure
# Subscription model
Source: https://docs.peridotvault.com/dev/game-licensing/subscription-model
• subscription-model
* Developer recurring support model
* Access gating logic
* Revenue handling
# Revenue share
Source: https://docs.peridotvault.com/dev/getting-started/revenue-share
• revenue-share
* 90% to developer
* 10% platform
* Payout structure
* Supported payment currencies
# Welcome
Source: https://docs.peridotvault.com/dev/getting-started/welcome
Example section for showcasing API endpoints
• developer-welcome
* Who should publish on Peridot
* Indie-first platform
* Quick overview of publishing lifecycle
# Step 1 — Connect to Studio
Source: https://docs.peridotvault.com/dev/publishing/1-connect-to-studio
Go to:
[https://studio.peridotvault.com](https://studio.peridotvault.com)
Connect your wallet to start publishing.
Once connected:
1. Open the dashboard
2. Click **Create New Game**
This will create a new draft entry for your game.
You can save your progress at any time using **Save Draft**.
# Step 2 — Basic Game Info
Source: https://docs.peridotvault.com/dev/publishing/2-basic-info
Configure the core metadata for your game before publishing.
After creating a new game, the first step is filling in the **Basic Information** section.
This metadata will appear on the **PeridotVault Store page** and helps players discover your game.
***
## Fields
| Field | Description |
| ------------ | ----------------------------------------------------- |
| Game ID | Automatically generated identifier. Cannot be edited. |
| Game Name | The public title of your game. |
| Description | A short explanation of your game and gameplay. |
| Required Age | Minimum recommended player age. |
| Website URL | Optional link to your official website. |
| Categories | Select up to **3 categories** for discovery. |
| Tags | Keywords that help users find your game. |
***
## Categories
Categories help organize games in the store.
You can choose **up to 3**.
Examples:
* Action
* RPG
* Strategy
* Indie
* Adventure
***
## Tags
Tags are used for search and recommendations.
You can:
• select existing tags\
• create custom tags
Examples:
* Pixel Art
* Multiplayer
* Roguelike
* Co-op
***
## Saving Your Progress
You can safely leave the editor anytime by clicking:
**Save Draft**
All progress will be stored in your developer dashboard.
Game drafts are **not visible publicly** until the game is published.
Once finished, click: **Next**
# Step 3 — Media Assets
Source: https://docs.peridotvault.com/dev/publishing/3-media-assets
Upload images that will appear on the store page.
Media assets are used to present your game visually in the store.
***
## Required Assets
Your game should include:
| Asset | Purpose |
| ---------------- | ---------------------- |
| Cover Vertical | Main store thumbnail |
| Cover Horizontal | Main store thumbnail |
| Banner Image | Banner for Game Detail |
| Screenshots | Gameplay preview |
***
## Recommended Guidelines
For the best store presentation:
• Use **good resolution images**\
• Show **actual gameplay**\
• Avoid text-heavy images
Recommended screenshot types:
* gameplay scene
* combat
* UI
* environment
***
Games with strong visual media receive significantly more clicks in the store.
After uploading all assets, click:
**Save Draft**
# Step 4 — Upload Builds
Source: https://docs.peridotvault.com/dev/publishing/4-build-upload
Upload playable versions of your game.
PeridotVault supports multiple platform builds.
***
## Supported Platforms
You may upload builds for one or more platforms.
| Platform | Supported |
| -------- | --------- |
| Windows | ✓ |
| macOS | ✓ |
| Linux | ✓ |
| Android | - |
| IOS | - |
| Web | ✓ |
***
## Uploading a Version
Click **Upload New Version**.
Then:
1. Upload your build as `.zip`
2. Enter the version number
3. Add description (optional)
Example:
Version: **1.0.0**\
Description: **Initial release build**
***
## System Requirements
Enter the minimum system requirements.
| Field | Example |
| --------- | --------------- |
| Processor | Intel i5 |
| Graphics | GTX 1050 |
| Memory | 8192 MB (8GB) |
| Storage | 12288 MB (12GB) |
Additional notes may also be added if needed.
***
Your uploaded file **must be compressed as `.zip`**.
Click **Save Draft** once finished.
# Step 5 — On-chain Publishing
Source: https://docs.peridotvault.com/dev/publishing/5-onchain-publishing
Configure blockchain license parameters.
PeridotVault publishes game licenses on-chain using the **PGC1 license standard**.
***
## Network
Currently supported:
Base Sepolia Testnet
***
## Payment Token
Choose which token players will use to purchase your game.
Supported tokens:
* ETH
* USDC
* IDRX
***
## Max Supply
Defines the maximum number of licenses.
| Value | Result |
| ------ | ---------------- |
| 0 | Unlimited supply |
| Number | Fixed supply |
Once published, **Max Supply cannot be changed**.
***
## Price
Enter the price using the selected token.
Example:
0.01 ETH
Fill Price with 0 means Free
***
## Release Date
Choose when the game becomes available to players.
Click **Save & Continue**.
# Step 6 — Review & Publish
Source: https://docs.peridotvault.com/dev/publishing/6-review-and-publish
Before publishing, review all settings.
Check the following:
• Game metadata\
• Media assets\
• Build versions\
• Blockchain configuration
If everything is correct, click:
**Publish Game**
***
## Final Step
Your wallet will prompt you to:
1. Pay the publishing fee
2. Sign the blockchain transaction
Once confirmed, your game will be published on **PeridotVault**.
Publishing may take a few seconds while the transaction is confirmed on-chain.
# Overview
Source: https://docs.peridotvault.com/dev/publishing/overview
Learn how to publish your game on PeridotVault.
Publishing a game on **PeridotVault** is a simple process that takes only a few steps.
Developers upload their game build, provide metadata, and publish the game on-chain using the **PGC1 license system**.
## Publishing Flow
The process consists of the following steps:
1. Connect to **PeridotVault Studio**
2. Create a new game entry
3. Fill in game metadata
4. Upload media assets
5. Upload game builds
6. Configure on-chain publishing
7. Review and publish
# License model
Source: https://docs.peridotvault.com/docs/economics/license-model
• license-model
* Smart contract proof-of-ownership
* Not DRM (current phase)
* Chain-verifiable ownership
* Extensible future access control
# Payment model
Source: https://docs.peridotvault.com/docs/economics/payment-model
• payment-model
* IDRX (Rupiah)
* USDT
* Optional PER
* Stability-first approach (PER not default payment token)
# Revenue model
Source: https://docs.peridotvault.com/docs/economics/revenue-model
• revenue-model
* 10% distribution fee
* 2.5% NFT trading fee
* Developer subscription model
* Gamer-to-dev subscription support
# The Problem
Source: https://docs.peridotvault.com/docs/get-started/the-problem
Structural challenges faced by indie developers in modern game distribution ecosystems.
Independent developers face structural disadvantages in modern distribution ecosystems.
These challenges are not merely financial — they are systemic.
***
## 1. High Publishing Fees
* Major distribution platforms often take up to 30% of revenue from game sales.
* For smaller studios, this significantly impacts sustainability and reinvestment capacity.
* Fee structures are not always negotiable, regardless of studio size.
***
## 2. Discovery Inequality
Large publishers dominate visibility channels.
Indie developers struggle with:
* Algorithmic prioritization bias
* Marketing budget limitations
* Limited audience reach
* Platform dependency for exposure
Even quality games often fail due to structural discovery barriers.
***
## 3. Web3 Integration Complexity
Blockchain-based ownership systems promise transparency but introduce friction:
* Smart contract deployment complexity
* Wallet integration requirements
* Gas fee unpredictability
* User onboarding friction
For small teams, technical overhead becomes prohibitive.
***
## 4. Ownership Ambiguity
In traditional platforms:
* Access does not equal ownership
* Licenses are centrally controlled
* Platform bans can remove access
Players and developers operate under centralized entitlement models.
Ownership remains platform-dependent.
***
PeridotVault exists to address these structural inefficiencies by separating distribution infrastructure from speculative token systems while introducing verifiable license ownership.
# Vision & Mission
Source: https://docs.peridotvault.com/docs/get-started/vision-and-mission
The long-term direction of PeridotVault in redefining digital ownership, immersive interaction, and the convergence of virtual and physical economies.
## Vision
To build an integrated gaming ecosystem where digital and physical realities converge — enabling immersive interaction, persistent identity, and seamless ownership across virtual and real-world environments.
PeridotVault envisions a future where:
* Games are not isolated applications, but connected ecosystems
* Ownership extends beyond platforms and into interoperable digital identities
* Virtual economies can meaningfully interact with physical-world value
* AI companions enhance solo and social gameplay experiences
* Dedicated hardware enables frictionless, portable access to decentralized gaming environments
Our long-term ambition is to reduce the boundary between playing, owning, and living in digital spaces — while ensuring that independent creators remain structurally empowered within that ecosystem.
***
## Mission
PeridotVault operates in progressive layers toward this vision:
1. **Build Decentralized Distribution Infrastructure**: Provide indie developers with a chain-agnostic publishing layer that reduces dependency on centralized platforms.
2. **Establish Verifiable Digital Ownership**: Deploy smart contract–based license systems that enable transparent, portable entitlement logic.
3. **Enable Sustainable Developer Economies**: Create monetization structures that support long-term growth without speculative token reliance.
4. **Integrate AI-Enhanced Interaction**: Develop intelligent companion systems that improve solo and community gameplay experiences.
5. **Bridge Virtual and Physical Economies**: Explore mechanisms where digital assets, in-game purchases, and identity layers can extend into real-world utility and interoperability.
6. **Expand Into Dedicated Hardware Ecosystems**: Design portable and seamless access devices that allow users to interact with decentralized gaming environments anywhere.
# What is PeridotVault?
Source: https://docs.peridotvault.com/docs/get-started/what-is-peridotvault
A chain-agnostic distribution infrastructure combining on-chain license ownership and governance-based moderation for indie developers.
PeridotVault is a chain-agnostic game distribution infrastructure designed to support independent and emerging developers.
Rather than functioning as a traditional launcher, Peridot acts as a decentralized distribution and licensing layer that enables developers to publish games, verify ownership through smart contracts, and operate within a governance-moderated ecosystem.
It is built to reduce platform dependency while maintaining sustainable growth pathways for smaller studios.
***
## Core Architecture
### Chain-Agnostic Distribution Layer
Peridot operates across multiple blockchain networks, including Ethereum, Base, and Solana.
This allows:
* Flexible deployment
* Cross-ecosystem participation
* Reduced lock-in to a single chain
Distribution is infrastructure-first, not token-first.
***
### On-Chain License Ownership
Every purchased game can be associated with a smart contract–based license.
This enables:
* Cryptographically verifiable ownership
* Transparent entitlement logic
* Reduced ambiguity between platform access and asset ownership
Ownership is no longer purely database-controlled.
***
### Governance-Based Moderation
Peridot incorporates governance mechanisms to maintain platform standards.
This supports:
* Community-driven moderation
* Transparent content policies
* Removal of prohibited content (e.g., gambling, explicit material)
Governance exists to protect ecosystem integrity — not to speculate.
***
### Built for Indie Developers
Peridot prioritizes:
* Developers without strong publishing leverage
* Small studios struggling with discovery
* Teams seeking simplified Web3 integration
* Builders who want ownership transparency without token volatility
The infrastructure is designed to help smaller creators gain structural support — not compete through marketing dominance alone.
# Competitive landscape
Source: https://docs.peridotvault.com/docs/market-context/competitive-landscape
• competitive-landscape
* Steam (centralized distribution)
* itch.io (open but no on-chain ownership)
* NFT marketplaces (asset trading only)
* Peridot (distribution + license + governance)
# Why peridot
Source: https://docs.peridotvault.com/docs/market-context/why-peridot
• why-peridot
* For Developers:
10% fee
Subscription model
Multi-chain support
On-chain ownership layer
* For Gamers:
Transparent ownership proof
Community governance moderation
Stable payment methods
# Community
Source: https://docs.peridotvault.com/docs/nnc/community
• community
* Focus on SEA indie dev ecosystem
* Developer-first onboarding
* Governance participation via PER
* Open SDK (free, not enterprise-locked)
# Novelty
Source: https://docs.peridotvault.com/docs/nnc/novelty
• novelty
* On-chain license registry
* Chain-agnostic deployment (ETH, Base, Sol)
* Governance-driven moderation
* Subscription-based indie monetization
# Introduction
Source: https://docs.peridotvault.com/index
A multi-chain distribution infrastructure helping indie developers gain visibility, ownership, and sustainable growth without platform dependency.
PeridotVault is a multi-chain game distribution infrastructure built to support independent and emerging developers who struggle with visibility, platform dependency, and complex Web3 integration.
Rather than competing as another game launcher, Peridot provides a decentralized license layer and developer-first monetization structure that enables small studios to publish confidently, retain economic control, and scale sustainably. By combining smart contract–based ownership across Ethereum, Base, and Solana with stable payment integration and governance-based moderation, Peridot creates a foundation where indie developers can grow without being overshadowed by platform dominance.
## Key Foundations
* **Indie-First Infrastructure**: Built to reduce discovery friction and platform dependence for small and emerging studios.
* **Decentralized License Ownership**: Smart contract–based proof-of-ownership deployed across supported chains.
* **Sustainable Monetization**: Developer-first revenue structure with predictable payment systems.
* **Multi-Chain Compatibility**: Designed to operate across Ethereum, Base, and Solana without ecosystem lock-in.