Summary
prediction_market/src/lib.rs stores all platform fees in a single global AccumulatedFees counter (lines ~1290-1348). Individual markets contribute to and withdraw from this pool with no per-market attribution. On cancel_market, the reclaim formula net_pool * TOTAL_FEE_BPS / (BPS_DENOM - TOTAL_FEE_BPS) attempts to reverse fees, but because funds from all markets are fungible, it is mathematically impossible to know which specific fees belong to which market.
Impact
- Cross-market contamination: market A's
cancel_market can reclaim fees that were actually earned by market B, leaving market B's fee recipients underpaid.
- Fee theft: a malicious market creator can resolve a market with tiny stakes, inflate
AccumulatedFees via the reclaim formula, and drain fees earned by other markets.
- Unrecoverable errors: once the accumulator is commingled, per-market fee isolation is impossible without a storage-level redesign.
Why it's unsolvable by a localized patch
- The fungible accumulator model is baked into the storage schema.
- Any per-market segregation requires a new storage layout:
FeeLedger[market_id] with its own TTL and accounting.
- The current
cancel_market reclaim logic assumes the formula is reversible, which it is not when fees are commingled.
Fix
- Replace the global
AccumulatedFees with per-market FeeLedger[market_id] entries.
- Track fee provenance at
place_bet time: credit net * PLATFORM_FEE_BPS / BPS_DENOM to FeeLedger[market_id].
- On
cancel_market, only reclaim the market's own fees from its ledger entry.
- Migrate existing funds to the new model via a one-time upgrade migration.
Summary
prediction_market/src/lib.rsstores all platform fees in a single globalAccumulatedFeescounter (lines ~1290-1348). Individual markets contribute to and withdraw from this pool with no per-market attribution. Oncancel_market, the reclaim formulanet_pool * TOTAL_FEE_BPS / (BPS_DENOM - TOTAL_FEE_BPS)attempts to reverse fees, but because funds from all markets are fungible, it is mathematically impossible to know which specific fees belong to which market.Impact
cancel_marketcan reclaim fees that were actually earned by market B, leaving market B's fee recipients underpaid.AccumulatedFeesvia the reclaim formula, and drain fees earned by other markets.Why it's unsolvable by a localized patch
FeeLedger[market_id]with its own TTL and accounting.cancel_marketreclaim logic assumes the formula is reversible, which it is not when fees are commingled.Fix
AccumulatedFeeswith per-marketFeeLedger[market_id]entries.place_bettime: creditnet * PLATFORM_FEE_BPS / BPS_DENOMtoFeeLedger[market_id].cancel_market, only reclaim the market's own fees from its ledger entry.