Skip to main content

Security Model

Trust boundaries, threat model, and concrete security properties of every deployed contract.


Trust Boundary Overview

┌──────────────────────────────────────────────────┐
│ TRUSTED (Game server) │
│ │
│ • Game server decides match outcomes │
│ • Server calculates payout amounts │
│ • Server manages in-game inventory state │
│ • Server signs or submits on-chain transactions │
│ │
│ Players trust the game operator for GAMEPLAY │
│ correctness — the same trust model as any │
│ existing competitive online game. │
│ │
└───────────────────────┬──────────────────────────┘

economic settlement boundary

┌───────────────────────▼──────────────────────────┐
│ TRUSTLESS (On-chain) │
│ │
│ • Smart contracts hold all prize funds │
│ • Only verified winners can withdraw prizes │
│ • Game operator CANNOT redirect prize money │
│ • Bridge requires oracle threshold signatures │
│ • Replay attacks blocked at contract level │
│ • No admin minting of THC token │
│ │
│ Players do NOT need to trust the game operator │
│ for fund custody, payouts, or token ownership. │
│ │
└──────────────────────────────────────────────────┘

The critical insight: The game server is trusted for gameplay. The blockchain removes the need to trust any human for money. These are different concerns requiring different guarantees.


Threat Model

Threat 1: Game Server Manipulation

ThreatCompromised server submits false match results
ImpactIncorrect prize distributions
MitigationServer-side result validation, match replay logging, audit trails
Residual riskThe game operator must be trusted for gameplay correctness — this is intentional and identical to every existing online game

Threat 2: Prize Pool Admin Rug

ThreatDeveloper drains tournament prize pool
ImpactPlayers and sponsors lose funds
MitigationPrizePool.sol has no admin withdrawal for prize funds. Only claim() by verified winners or refund() on cancellation.
Contract refsweepUnclaimed() exists only after claim deadline expires and sends to treasury, not arbitrary addresses

Threat 3: Oracle Collusion

ThreatOracle operators collude to forge bridge attestations
ImpactUnauthorized THC minting on Avalanche
MitigationMulti-oracle threshold (require(valid >= threshold)) — production requires threshold ≥ 3
Contract refFadedMonsutaTHC.sol lines 322–330

Threat 4: Bridge Replay Attack

ThreatAttacker resubmits a previously valid claim() call
ImpactDouble-minting of bridged tokens
Mitigationclaimed[claimHash] mapping — claimHash = keccak256(DOMAIN_SEPARATOR, td.id). Checked and set atomically.
Additionalsigned[td.id][signer] prevents each oracle from approving the same teleport twice

Threat 5: Cross-Chain Replay (Domain Separation)

ThreatSignatures valid on one network replayed on another
ImpactToken minting on unintended chain
MitigationDOMAIN_SEPARATOR = keccak256(FADEDMONSUTA_THC_BRIDGE, block.chainid, address(this)) — unique per chain + contract address

Threat 6: Wrong Chain ID Submission

ThreatWAX teleport data for BSC submitted to Avalanche contract
ImpactToken minting on wrong contract
Mitigationrequire(thisChainId == td.chainId, "wrong chain")thisChainId = 2 on Avalanche deployment

Threat 7: Expired Claim

ThreatOld signed packet used after intended window
ImpactStale or unintended claims
Mitigationrequire(block.timestamp < td.ts + 30 days, "expired") — enforced in verifySigData()

Threat 8: Reentrancy on Prize Claim

ThreatMalicious winner contract re-enters claim() to drain pool
ImpactPool drained beyond winner's allocation
MitigationReentrancyGuardUpgradeable on all fund movement functions: fund(), fundERC20(), register(), claim(), refund()

Threat 9: NFT Theft Through Staking

ThreatStaker sells/transfers NFT while keeping staking weight
ImpactIllegitimate reward accumulation
MitigationsyncPosition() and syncAccount() detect ownership mismatch via IERC721.ownerOf() and remove invalidated positions

Threat 10: Client-Side Cheating

ThreatModified game client sends fabricated game actions
ImpactUnfair match outcomes
MitigationServer-authoritative architecture. Client sends inputs only. Server resolves all state transitions.

Contract-Level Security Properties

FadedMonsutaTHC.sol

PropertyImplementation
No admin mintingTokens only created via claim() with valid oracle signatures
Oracle thresholdConfigurable threshold — requires N valid unique oracle sigs
Domain separationDOMAIN_SEPARATOR derived from chainid + address(this)
Cannot withdraw THCtransferAnyERC20Token() explicitly blocks withdrawal of THC itself
Two-step ownershiptransferOwnership() + acceptOwnership()

PrizePool.sol

PropertyImplementation
No admin prize withdrawalNo such function exists. Owner can only cancel (trigger refunds) or extend deadline.
Winner funds are separate_winnerAmounts mapping is separate from _deposits. Winners and depositors use different claim paths.
No double claim_hasClaimed[winner] checked and set atomically in claim()
Results are finalOnce submitResults() transitions pool to Finalized, no further results can be submitted
Reentrancy protectionnonReentrant on all fund-moving functions
Emergency pausepause() / unpause() — owner only
ERC-20 rescuerecoverERC20() — cannot recover settlement token while pool is active
Upgrade authorization_authorizeUpgrade() — owner only

PrizePoolFactory.sol

PropertyImplementation
Deployer whitelistOnly _authorizedDeployers can create pools — prevents pool spam
Implementation ownershipFactory owner controls which implementation new proxies use
Registry immutability_isPool mapping is append-only — pools cannot be removed
Upgrade protectionFactory is itself UUPS — owner-only upgrades

NFTStaking.sol

PropertyImplementation
Fund theft preventionfundPool() only adds to rewardPool. No withdrawal function.
Reward calculation precisionACC_PRECISION = 1e18 to avoid rounding errors
Lock enforcementlockUntil checked in unstake() — no early exit
NFT ownership verificationIERC721.ownerOf(tokenId) == msg.sender checked at stake time
Stale position cleanupsyncPosition() and syncAccount() detect transferred NFTs
Distributor gatingdistribute() restricted to _distributors mapping

teleporteos (WAX)

PropertyImplementation
Deposit-then-teleportUsers must first transfer tokens before initiating teleport
Oracle deduplicationEach oracle can sign each teleport ID only once
ORACLE_CONFIRMATIONSMinimum approvals before token release
Cancel mechanismTeleports can be cancelled by owner after expiry

Oracle Network Security

Requirements

RequirementRationale
threshold ≥ 3Single oracle compromise cannot mint tokens
Hardware wallet or KMSOracle private keys must not be in plaintext on disk
Separate infrastructureOracles on different cloud providers / regions
Alert on unusual volumesDetect abnormal bridge activity early
Rate cap per epochLimit maximum single-period damage from compromise

Oracle Fault Tolerance

oracle-eth.js handles oracle failure gracefully:

  • Multiple RPC endpoints with automatic failover
  • Block progress persisted to disk (crash-safe)
  • Worker sharding for parallel redundancy
  • Incomplete bridge events tracked in incomplete-eth.js

For Integrating Games

Games adopting Monsuta Core inherit these properties automatically:

  • ✅ Prize pool funds cannot be stolen by the game developer
  • ✅ Replay attacks blocked on all bridge claims
  • ✅ Oracle collusion requires N-of-M compromise
  • ✅ Reentrancy protection on all fund movements
  • ✅ NFT staking validates real-time ownership

Games are responsible for:

  • ⚠️ Game server security (hardened infra, access control, secret management)
  • ⚠️ Match result integrity (anti-cheat, replay validation)
  • ⚠️ Oracle key management (in production: KMS, not env vars)
  • ⚠️ Setting correct production thresholds (bridge, oracle count)