EventlyMarketsV3.sol
Version: v3.2 (post-audit, pre-deployment) Status: Pending deployment (audit complete) Dependencies: OpenZeppelin ERC-1155, ERC-20 SafeERC20, PRBMath SD59x18
Overview
EventlyMarketsV3 is the production prediction markets contract for evently. It combines:
ERC-1155 tradable positions -- each trade mints/burns fungible shares per outcome
LMSR AMM -- Logarithmic Market Scoring Rule for automated, manipulation-resistant pricing (b=200 USDm)
CLOB (Central Limit Order Book) -- bids and asks with price-time priority, matched automatically on
placeOrderCreator economy -- 1% creator fee on all volume, claimable after finalization
The LMSR mechanism eliminates the core flaw of parimutuel systems: being correct always yields a profit, regardless of how many people chose the same option.
Key Parameters
Creator collateral
50 USDm
Dispute collateral
50 USDm
Dispute window
24 hours
Burn delay (losing shares)
24 hours after finalization
Total fee (default)
2.5% (1% creator + 1% treasury + 0.5% resolver pool)
Fee hard cap
5%
Max options per market
4
Min options per market
2
Min trade
0.001 shares (1e15)
LMSR liquidity parameter b
200 USDm (200e18)
Max orders per book
200 per (market, option, side)
1 winning share pays out
1 USDm exactly
LMSR Pricing Mechanism
LMSR (Logarithmic Market Scoring Rule) is an automated market maker where price follows a mathematically sound cost function:
q[i]= shares outstanding for option ib= liquidity parameter (200 USDm) -- controls price sensitivityCost to buy shares of option i = C(q after) - C(q before)
Implied probability of option i:
At initialization all quantities are 0, so each option starts at 1/n probability. Prices always sum to exactly 1.
Market subsidy: To bootstrap liquidity, the creator locks b x ln(n) USDm at market creation. This subsidy guarantees solvency: poolBalance + subsidyDeposited >= total winning shares at all times.
Architecture
Market Lifecycle
Created -- creator locks 50 USDm collateral + LMSR subsidy (
b x ln(n))Active -- users buy/sell shares via LMSR AMM and CLOB
BettingClosed -- after betting deadline, no new trades
Resolved -- creator declares winning option
Dispute Window (24h) -- any whitelisted user can dispute by locking 50 USDm
Finalized -- after dispute window closes or admin settles dispute
Redemption -- winning shareholders call
redeemWinnings()for 1 USDm per share
Fee Structure
Market creator
1% (creatorFeeBps = 100)
Accrues in creatorAccruedFees, claimable after finalization
Treasury
1% (treasuryFeeBps = 100)
Accumulates in treasuryBalance
Resolver pool
0.5% (resolverFeeBps = 50)
Initially = admin; redirected post-TGE to staking
Total
2.5%
Hard cap: 5% via setFees()
Admin markets (created by admin): creator cut goes to treasury instead.
Audit Fixes Applied (v3.2)
F-02
claimCancelRefund -- snapshot total supply before burning; prevents insolvency on sequential claims
A-03
MAX_ORDERS_PER_BOOK = 200 per (market, option, side) -- prevents O(n) DoS griefing
F-DS-M02
_cleanBook() called immediately in cancelOrder -- dead CLOB entries removed, book never fills up with ghosts
R2-2
claimCreatorFees requires Finalized status -- blocks creator fee claim while market is Disputed
L-01
nonReentrant added to resolveMarket, cancelMarket, slashMarket
GROK-M01
subsidyDeposited included in claimCancelRefund effective pool -- subsidy recoverable by shareholders on cancel/slash
GPT-R3-3
slashMarket handles Disputed status -- dispute collateral swept to treasury, nothing stranded
GROK-L02
createdAt != 0 guard added to all view functions -- prevents silent zero returns for nonexistent markets
QWEN-I03
BettingClosed event emitted by closeBetting
Functions
Trading
placeOrder(marketId, optionIndex, side, quantity, pricePerShare, minFill)-- BUY or SELL limit order; CLOB matched first, remainder to AMM for BUYsellToAMM(marketId, optionIndex, shares, minUsdmOut)-- instant sell to LMSR AMM at current pricecancelOrder(orderId)-- cancel resting order; escrowed USDm or shares returned immediately
Pricing (view)
getPrice(marketId, optionIndex)-- LMSR implied probability (0 to 1e18)getImpliedPrices(marketId)-- array of all option probabilitiesquoteBuy(marketId, optionIndex, usdmNet)-- shares out for a given net USDm (binary search)quoteSell(marketId, optionIndex, shares)-- gross USDm out for a given share quantitygetQuantities(marketId)-- outstanding shares per optiongetSubsidy(marketId)-- subsidy deposited and b parametergetBidBook(marketId, optionIndex)-- resting bid order IDsgetAskBook(marketId, optionIndex)-- resting ask order IDsgetOrderInfo(orderId)-- full order struct
Market Management
createMarket(...)-- locks 50 USDm collateral + LMSR subsidycreateAdminMarket(...)-- admin pays subsidy only (no creator collateral)resolveMarket(marketId, winningOption)-- creator resolves after betting deadlinecloseBetting(marketId)-- permissionless; callable by anyone after bettingDeadlinedisputeMarket(marketId, proposedOption)-- dispute with 50 USDm collateralsettleDispute(marketId, creatorWasRight, finalOption)-- admin settlesfinalizeMarket(marketId)-- callable by anyone after dispute window closescancelMarket(marketId)-- creator, admin, or anyone after resolutionDeadlineslashMarket(marketId, reason)-- admin; works on Active, BettingClosed, Resolved, Disputed
Claims
redeemWinnings(marketId)-- burn winning shares for 1 USDm eachclaimCancelRefund(marketId)-- pro-rata refund on cancelled/slashed marketsclaimCreatorFees(marketId)-- creator withdraws accrued fees (post-finalization only)burnLosingShares(marketId, holders[])-- admin keeper; burns losing shares 24h after finalization
Admin
setFees(creatorBps, treasuryBps, resolverBps)-- adjust fee split (<=5% total)setResolverPoolAddress(addr)-- redirect resolver feeswithdrawTreasury(to, amount)-- pull accumulated treasury feeswithdrawResolverPool(to, amount)-- pull accumulated resolver feestransferAdmin(newAdmin)-- transfer admin roleaddToWhitelist(wallet)/batchWhitelist(wallets[])/removeFromWhitelist(wallet)-- whitelist managementsetWhitelistEnabled(bool)-- toggle whitelist enforcementcreateInviteCode(codeHash)/redeemInviteCode(code)-- invite system
Token ID Encoding
MAX_OPTIONS = 4, so each market occupies token IDs [marketId*4, marketId*4+3].
CLOB Design
Order types
BUY and SELL
Matching
Automatic on placeOrder
Price priority
Best price first (ascending for asks, descending for bids)
Time priority
FIFO within same price level
Dead entry cleanup
Immediately on cancelOrder (_cleanBook -- F-DS-M02)
Book cap
200 orders per (market, option, side)
Last updated
Was this helpful?

