# 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** Create Mew 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. Basic Info Form *** ## 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. Media Upload Interface *** ## 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. Build Upload Interface *** ## 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**. Onchain Form *** ## 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. Publishing Form 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.