Overview
Game Store is the execution layer for purchasing games. Responsibilities:- Validate game from Registry
- Process payment
- Mint license via PGC-1
Dependencies
Data Structures
PriceConfig
State
Functions
1. setPrice
Sets base price for a game.function setPrice(gameId, price, currency)
Params
Rules
- Only publisher
- msg.sender MUST match
PGC1(contractAddress).getPublisher() currencyMUST be a valid supported payment token- Game MUST exist in Registry
priceMAY be 0 for free games
2. setDiscount
Sets discount in basis points.function setDiscount(gameId, discountBps)
Params
Rules
- Only publisher
- msg.sender MUST match
PGC1(contractAddress).getPublisher() discountBpsMUST be<=10000
3. getFinalPrice
Returns final price after discount.function getFinalPrice(gameId): uint256
Returns
Logic
finalPrice = price - (price * discountBps / 10000)4. buyGame
Executes purchase and mints license.function buyGame(gameId)
Flow
- Fetch game from Registry
- Validate
status == approved - Validate
game.contractAddressexists - Get PGC-1 contract
- Get publisher:
publisher = PGC1.getPublisher()
- Load
PriceConfigcurrency = prices[gameId].currency
- Calculate
finalPrice - Validate payment token and amount
- Prevent duplicate purchase by checking
PGC1.canAccessGame(msg.sender) - Calculate:
platformFeepublisherRevenue
- Receive payment
- Process split:
transfer(platformFee → treasury)publisherBalances[publisher][currency] += publisherRevenue
- Call
PGC1.mintLicense(msg.sender, 0) - 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
Rules
- Only governance
feeBpsMUST be<=10000
6. withdraw
Withdraw publisher earnings per token.function withdraw(token)
Params
Rules
- Only publisher
- Balance MUST be > 0
- Withdrawal MUST revert if transfer fails
Behavior
amount = publisherBalances[msg.sender][token]publisherBalances[msg.sender][token] = 0transfer(token → msg.sender)
7. setGovernance
Updates governance address.function setGovernance(governance)
Params
Rules
- Only current governance
- Governance MUST NOT be zero address
- Event SHOULD be emitted
8. setTreasury
Updates treasury receiver address.function setTreasury(treasury)
Params
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
Returns
10. getPublisherBalance
Returns withdrawable publisher balance for a token.function getPublisherBalance(publisher, token)
Params
Returns
11. getPlatformFee
Returns current platform fee in basis points.function getPlatformFee()
Returns
12. getTreasury
Returns treasury receiver address.function getTreasury()
Returns
13. getGovernance
Returns governance address.function getGovernance()
Returns
14. getRegistry
Returns registry contract address.function getRegistry()
Returns
Payment Flow
Hybrid (Push + Escrow) Payments are split during purchase:- Platform fee → sent directly to treasury
- Publisher revenue → stored in contract (escrow)
Flow
- User pays
finalPrice - Contract calculates:
- platformFee
- publisherRevenue
- Execute transfers:
- send platform fee to treasury
publisherBalances[publisher][currency] += publisherRevenue
- 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
Access Control
Requirements
- Game MUST be
approvedin 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