Skip to main content
TheBingoFi’s Solidity contracts (Foundry, Solidity ^0.8.24, OpenZeppelin) exist solely for ownership and catalog. There is no betting, pot, or stake mechanic anywhere in this code, only primary NFT sale plus standard secondary-market royalty support.

The 4 contracts

Role wiring (from script/Deploy.s.sol): SkillFactory holds REGISTRAR_ROLE on SkillRegistry and LISTER_ROLE on Marketplace; Marketplace holds MINTER_ROLE on SkillCollection.

Live on GIWA Sepolia (chain ID 91342), verified

All 4 contracts are deployed and verified on Blockscout. GIWA Sepolia is a testnet; there is no GIWA mainnet yet.
Machine-readable address list: contracts/deployments/91342.json. ABIs and addresses reach the apps through packages/chain (abi/*.ts as-const modules and deployments/91342.ts), regenerated from source by contracts/export-artifacts.sh on every function/event change. The catalog is already seeded with the 5 launch skills (IDs 1-5). See the supply/price table in Economy & Business Model.

Release flow: shipping a new skill (platform, 1 transaction)

Purchase flow

Functions the frontend calls

1

Quote the price: required before every purchase

Marketplace.priceOf(skillId) is a view function returning the current unit price, already including the scarcity premium and demand-decay discount. The frontend must always quote through priceOf; basePrice alone is stale the moment any unit sells or any time passes. See the pricing formulas in Economy & Business Model.
2

Buy

Marketplace.buy(skillId, amount) is payable, msg.value = priceOf(skillId) * amount (quote immediately before submitting, to minimize drift from a moving price). Overpayment is automatically refunded in the same transaction; underpayment reverts with InsufficientPayment(expected, actual).
3

Stock and base price

Marketplace.sales(skillId) returns (basePrice, maxSupply, minted, active, lastPurchaseAt), used for “X of Y left” stock display, rarity tier, and a discount badge (by comparing against priceOf). Never used to compute the actual purchase price.
4

Check ownership

SkillCollection.balanceOfBatch(owners, skillIds) is used by the server at matchmaking time to verify a loadout, and by the frontend for inventory/collection views (one call covers many IDs; single-item balanceOf isn’t used).
5

Read the catalog

SkillRegistry.nextSkillId() then getSkill(skillId) for 1..n returns the full SkillDef (charges/cooldown/maxPerLoadout/rarity) for rendering rules and the market.

Deliberately not called by the app

  • SkillCollection.uri(skillId) and SkillDef.metadataURI: name, description, and asset URLs are served by the game server’s GET /metadata/{id}.json (built from on-chain effectType/rarity) instead. The server, not on-chain uri(), is the source of truth for what the app displays, though uri() remains available for third-party wallets/marketplaces that expect the standard ERC-1155 metadata path.
  • SkillCollection.royaltyInfo(tokenId, salePrice): read independently by third-party secondary marketplaces; the app has no reason to call it itself.
  • Marketplace.pricingParams(): discount/hot-item badges are computed from the difference between priceOf and basePrice; the raw parameters aren’t needed client-side.
  • All admin write functions (createSkill, setActive, createSale, setPricingParams, setTreasury, setURI, setDefaultRoyalty, mint, role management): operated by the platform via forge script/the explorer, never from the app UI.
  • withdraw(): permissionless (funds can only ever flow to treasury), triggered manually to sweep revenue; there’s no automated schedule for it yet.
  • Secondary transfers (setApprovalForAll/safeTransferFrom): a peer-to-peer marketplace UI isn’t in scope yet (see Roadmap & Status).

Events

There is currently no indexer/event listener running against these contracts (see Architecture); the server verifies entitlements with live reads instead. This table documents what these events would back if an indexer is added later; it does not describe something already wired up.

Testing

Test coverage spans role guards (Registry), factory wiring, collection mint/royalty behavior, and the full Marketplace buy/sale lifecycle including dynamic pricing (scarcity ramp, demand decay, refunds, setPricingParams validation).