Skip to main content

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

FieldTypeDescription
issuedAtuint64Timestamp when license is minted
expiresAtuint64Expiration timestamp

Rules

  • expiresAt = 0 means permanent license
  • expiresAt > now means temporary valid license
  • expiresAt < now means expired license

State

VariableTypeDescription
gameIdstringCanonical game identifier
publisheraddressCanonical publisher address
metadataURIstringCanonical metadata URI
mintersmapping(address => bool)Authorized minters
licensesmapping(address => LicensePolicy)User license policy per account

Functions

1. initialize

Initializes canonical game state. function initialize(gameId, publisher, metadataURI, initialMinter)

Params

NameTypeDescription
gameIdstringCanonical game identifier
publisheraddressCanonical publisher address
metadataURIstringCanonical metadata URI
initialMinteraddressInitial 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

NameTypeDescription
toaddressReceiver address
expiresAtuint64License 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

NameTypeDescription
useraddressUser address

Returns

TypeDescription
boolTrue 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

NameTypeDescription
useraddressUser address

Returns

TypeDescription
boolTrue 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

NameTypeDescription
useraddressUser address

Returns

NameTypeDescription
issuedAtuint64Timestamp when license was minted
expiresAtuint64Expiration timestamp

6. setMinter

Updates minter authorization. function setMinter(account, isAuthorized)

Params

NameTypeDescription
accountaddressMinter address
isAuthorizedboolAuthorization 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

NameTypeDescription
accountaddressAccount address

Returns

TypeDescription
boolAuthorized minter status

8. getPublisher

Returns canonical publisher address. function getPublisher()

Returns

TypeDescription
addressPublisher address

9. getMetadataURI

Returns canonical metadata URI. function getMetadataURI()

Returns

TypeDescription
stringMetadata URI

10. getGameId

Returns canonical game identifier. function getGameId()

Returns

TypeDescription
stringGame identifier

11. setPublisher

Updates publisher address. function setPublisher(publisher)

Params

NameTypeDescription
publisheraddressNew 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

NameTypeDescription
metadataURIstringNew 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

FunctionAccess
initializeDeployment only
mintLicenseAuthorized Minter
hasLicensePublic
canAccessGamePublic
getLicensePolicyPublic
setMinterPublisher
isMinterPublic
getPublisherPublic
getMetadataURIPublic
getGameIdPublic
setPublisherPublisher
setMetadataURIPublisher

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