Prize Pool Escrow
Trustless tournament and event settlement with off-chain result computation and on-chain payout finality.
Overviewβ
The Prize Pools subsystem is Monsuta Coreβs settlement layer for competitions.
- Off-chain services run tournaments, compute final standings, and calculate exact payouts.
- On-chain contracts escrow funds, finalize immutable results, and let winners claim directly.
This gives you the intended hybrid model:
- high-performance competition logic off-chain
- trust-minimized money movement on-chain
Current Implementation Statusβ
Contractsβ
Implemented and tested:
PrizePoolFactory.sol(UUPS upgradeable)PrizePool.sol(UUPS implementation used via ERC1967 proxies per pool)
Settlement Modesβ
Each pool supports:
- Native AVAX settlement (
settlementToken = address(0)) - ERC-20 settlement (
settlementToken = tokenAddress)
Lifecycle (Implemented)β
CreatedRegisteringActiveFinalizedCompletedCancelled
Test Coverage (Current)β
Contract suite currently passes with full lifecycle coverage (native + ERC-20), including:
- registration and funding paths
- authorization controls
- result submission and claim flow
- cancellation/refund flow
- pause/unpause and admin controls
Architectureβ
One factory deploys many isolated pool instances:
PrizePoolFactory (UUPS)
ββ PrizePool Proxy #1 (competition A)
ββ PrizePool Proxy #2 (competition B)
ββ PrizePool Proxy #N
Each pool is independent. A failure in one pool does not automatically compromise another.
Role Modelβ
Factory Ownerβ
- Authorize/revoke deployers
- Set default treasury
- Upgrade factory logic
- Update pool implementation pointer for future deployments
Authorized Deployerβ
- Create pools through factory
- Becomes owner of pools it creates
Pool Ownerβ
- Open registration / activate (owner-or-server path)
- Cancel before finalization
- Extend claim deadline
- Update authorized server
- Pause/unpause contract
Authorized Serverβ
- Submit final results
- Optional gasless registration path (
registerPlayer)
Participants / Sponsorsβ
- Fund pools
- Register (self path)
- Claim prizes (winners)
- Refund deposits if cancelled
Pool Lifecycleβ
Created
|
| openRegistration()
v
Registering
| \
| \ fund() / fundERC20() / register() / registerPlayer()
| \
| activate()
v
Active
|
| submitResults(winners, amounts) [authorizedServer]
v
Finalized
| \
| \ claim() by winners
| \ -> all winners claimed => Completed
|
-> claim window expires -> sweepUnclaimed() -> Completed
Before Finalized:
Created/Registering/Active -> cancel() -> Cancelled -> refund()
Core Contract Behaviorβ
1) Fundingβ
fund()for native poolsfundERC20(amount)for token pools- allowed only in
CreatedorRegistering - deposits are tracked per address for cancellation refunds
2) Registrationβ
register()supports entry fee collectionregisterPlayer(address)allows server-side gasless registration- max participant cap enforced when configured
3) Activationβ
openRegistration()transitionsCreated -> Registeringactivate()transitionsRegistering -> Active
4) Result Finalizationβ
submitResults(winners[], amounts[])callable by authorized server only inActive- validates non-empty and aligned arrays
- computes treasury fee and verifies payout budget
- sets
Finalized+ claim deadline - winners claim independently afterward
5) Claims and Closureβ
claim()enforces winner eligibility and no double-claim- pool auto-completes when all winners claim
sweepUnclaimed()allows post-deadline cleanup to treasury/owner fallback
6) Cancellation and Refundsβ
cancel()available before finalizationrefund()returns depositorβs tracked amount inCancelled
Hybrid Settlement Flow (Recommended)β
Game / tournament backend
-> computes standings + exact payout amounts
-> (recommended) signs settlement payload
-> queues job for distributor worker
-> worker validates pool state and signer policy
-> worker submits on-chain via authorized server wallet
-> winners claim directly from pool contract
This keeps tournament complexity off-chain while preserving on-chain settlement guarantees.
Operational Tooling (Current)β
The subsystem includes:
- deployment/preflight/status/verify scripts
- lifecycle operation scripts (create/open/fund/register/activate/results/claim/cancel/refund)
- distributor worker for queued result submission + audits
- per-run operational logs
- one-shot and daemon runtime modes for workers
Security Properties (Current)β
- no arbitrary admin withdrawal path for active prize funds
- server can finalize results but cannot directly βsweep winnersβ by admin payout
- reentrancy protection on external fund movements
- winner claim tracking prevents double claim
- cancellation refunds are bounded by tracked deposits
- per-pool isolation via proxy-per-competition model
Known Constraints / Gapsβ
These are important to understand in current version:
-
Result trust root is still off-chain
Final rankings originate from game backend authority. -
Duplicate winner protection is primarily off-chain today
Worker-level validation can reject duplicates, but hard on-chain duplicate guard is a recommended hardening step. -
Attested results pipeline is not fully enforced end-to-end yet
There is scaffolding for stricter signing workflows, but full mandatory attestation enforcement is still roadmap work.
Hardening Roadmapβ
P0 β Settlement Integrityβ
- Define canonical signed result schema (e.g.
tournamentId,poolAddress,winners,amounts,resultHash,expiry,nonce) - Enforce attestation verification in worker submit path
- Add idempotency key policy to prevent accidental duplicate submissions
- Add stale-active and near-claim-deadline alerting runbooks
P1 β Contract Hardening (v2 Candidate)β
- Add explicit on-chain duplicate winner rejection in
submitResults - Add richer settlement metadata events for auditability (e.g. result hash / external competition id)
- Evaluate optional signature-verified submit function for cryptographic result provenance
- Review treasury/payout edge behavior with non-standard ERC-20 tokens
P1 β Consistency Cleanupβ
- Remove duplicate source-tree ambiguity in contracts paths
- Maintain single ABI/source-of-truth path for scripts + SDK + docs
- Keep docs synchronized with implementation tracker
P2 β Mainnet Ops Readinessβ
- Publish full Fuji smoke test evidence (native + ERC-20, multi-wallet)
- Publish multisig admin rotation runbook
- Publish incident/disaster playbook (signer compromise, pause/cancel actions)
- Publish unclaimed sweep accounting policy
Recommended Production Controlsβ
Before high-value events:
- use dedicated authorized server key with hardware-backed signing
- move owner/admin functions to multisig
- run preflight and pool-state checks before every result submission
- enforce strict queue validation (
status == Active, unique winners, bounded total payout) - monitor claim windows and unresolved finalized pools
Example: Off-chain to On-chain Result Bundleβ
{
"tournamentId": "tourn-204",
"poolAddress": "0xPool...",
"winners": ["0xA...", "0xB...", "0xC..."],
"amounts": ["3040000000000000000", "1824000000000000000", "1216000000000000000"],
"resultHash": "0x...",
"signedBy": "0xAttestor...",
"signedAt": "2026-03-02T12:00:00Z"
}
The distributor worker should validate this payload, then submit submitResults from the authorized server wallet.
Summaryβ
Prize Pools are already functional as Monsutaβs trust anchor for competition payouts:
- competition logic stays off-chain for speed and flexibility
- settlement finality stays on-chain for player trust
- hardening now focuses on stronger result attestation, duplicate-proofing, and production operations
For the intended hybrid model, this is the correct direction: off-chain heavy compute + on-chain escrowed settlement.