Revenue sources
Primary sale
Players buy skills/skins directly from the platform through
Marketplace.buy(), which mints the NFT straight to the buyer. Price is set by the on-chain dynamic pricing model below, not a fixed number.Secondary royalty
Any resale on a third-party NFT marketplace pays a 5% royalty (500 basis points) back to the platform, via the
SkillCollection contract’s EIP-2981 default royalty.
The in-app marketplace, quoting live priceOf() for each skill.
Dynamic pricing: scarcity ramp + demand decay
Primary sale price is not a static number. It’s computed on-chain, on every call, from two forces pulling in opposite directions: the closer a skill gets to selling out, the more expensive it gets; the longer a skill goes without a sale, the cheaper it gets. This is implemented inMarketplace.sol and is live on GIWA Sepolia today.
Scarcity ramp
As more units of a skill are minted, its price ramps up linearly, reaching the maximum premium exactly when the sale is fully sold out:scarcityBps = 10000, that means up to +100% over basePrice once minted == maxSupply.
Demand decay
If a skill goes untouched, its price steps down over time, capped at a maximum discount, and reset to zero the instant someone buys:decayInterval = 1 day, decayStepBps = 500 (5% per full day of inactivity), maxDiscountBps = 5000 (50% ceiling). Every purchase resets lastPurchaseAt, which resets the discount to 0.
Final unit price
Marketplace.priceOf(skillId) is the only correct source for a purchase quote: basePrice alone is never enough, since real price moves with every mint and with elapsed time. buy(skillId, amount) computes unitPrice once from state at execution time (not re-priced mid-multi-unit-purchase), and any msg.value overpayment is automatically refunded in the same transaction (checks-effects-interactions; if the refund itself fails, the whole transaction reverts, so buyer funds are never stranded).
All four parameters above (scarcityBps, decayInterval, decayStepBps, maxDiscountBps) are one global set, tunable at any time via setPricingParams(...) (admin-only). No redeploy required.
These are the contract’s shipped default values. They’re a single global set applied to every sale and can be retuned by the platform at any time.
Worked examples (default parameters)
- Scarcity: Wild Daub (id 1)
- Scarcity: Nullify (id 5, super rare)
- Demand decay
basePrice = 0.0005 ETH, maxSupply = 1000priceOf(skillId) can still be queried after a sale sells out (useful for a “last price” UI reference). Only buy() itself reverts (SoldOut) once minted == maxSupply.Rarity tiers (seeded catalog)
The 5 launch skills were seeded on GIWA Sepolia with deliberately staggered supply and base price, to demonstrate the scarcity tiers described above:
Lower max supply pairs with a higher starting base price and a faster climb to the full scarcity premium: the two mechanisms reinforce each other for the rarest items.

Nullify: the rarest launch skill, seeded with a max supply of just 10.
Season model
Each season, the platform can release a fresh batch of skills through theSkillFactory. createSkill(SkillDef, maxSupply, price) is a single transaction that simultaneously registers the skill’s definition in the SkillRegistry and opens its sale in the Marketplace. No new contract deployment, no upgrade, is needed to ship new content each season. See Smart Contracts for the full release flow.
Free-to-play stays competitive
Casual mode carries no skills at all. It’s identical for every player regardless of wallet or NFT ownership, so a player who never buys anything is never at a competitive disadvantage in that mode. Instandard-mode rooms, a player who hasn’t set a loadout simply plays without skills, same as Casual, rather than being blocked from the room.
The original game design (
CONCEPT.md) also describes a non-NFT, non-tradeable “starter” skill loan to let brand-new players try the skill layer before ever touching a wallet. That mechanism is a design idea, not something implemented in the live server today.