Gemini 3.1 Pro
Tool: Gemini 1.5 Pro (Google DeepMind) Type: 3-round AI audit (Systematic → Economic → Triage) Contracts reviewed: evently.sol v5.4 · EventlyProfiles.sol v1.3 · EventlyMarketsV3.sol v3.2 (LMSR b=200 + CLOB bids/asks) Chain: MegaETH (Chain ID 4326) — Solidity ^0.8.20 Date: March 2026 Status: Complete — v3.2 post-audit fixes verified
Summary
Critical
1
High
2
Medium
2
Low
2
Informational
2
Total
9
Round 1 — Systematic Scan
Reentrancy, Access Control, Token Handling, and Math
The contract uses nonReentrant on core functions (buyShares, sellToAMM, createSellOrder, disputeMarket, settleDispute, claimCreatorFees, redeemWinnings, claimCancelRefund). However, cancelMarket and closeBetting lack this modifier. While these specific functions don't perform external calls before state changes, it is a best practice for consistency. (L-01)
onlyAdmin and onlyWhitelisted modifiers are correctly applied to sensitive functions. Solidity 0.8.20 provides native overflow protection. SafeERC20 is used for all USDm transfers. The cost function _lmsrCost correctly implements C(q) = b × ln(Σ exp(q[i]/b)). PRBMath SD59x18 is used for fixed-point exp and ln operations.
Round 2 — Economic Attack Analysis
Solvency, Fees, and Order Book
The contract relies on subsidyDeposited + poolBalance ≥ total winning shares. The subsidy is calculated as b × ln(n), which covers the worst-case transition from uniform to concentrated probability.
Fees are collected during buyShares and sellToAMM. A notable design characteristic: fees are taken from the remaining amount in buyShares before the AMM quote, effectively reducing the net USDm passed to the LMSR cost function. (H-02)
The MAX_ORDERS_PER_BOOK cap (A-03 fix) is correctly implemented and prevents order book flooding.
Round 3 — Adversarial Triage
C-01 — Potential Insolvency via P2P Redemptions [RESOLVED / FALSE POSITIVE]
In redeemWinnings, if payout > poolBalance, the contract draws from subsidyDeposited. However, poolBalance only tracks net USDm from AMM trades. When a buyer fills a P2P sell order in Phase 1 of buyShares, the USDm is sent directly to the seller — but the buyer receives ERC-1155 shares that are indistinguishable from AMM-minted shares and are equally redeemable against the contract's pool.
If significant volume goes through P2P orders, the physical USDm backing those shares has already left the contract. The poolBalance does not account for this gap, and the subsidy alone may not cover the shortfall.
Recommended Fix: Implement a redemption reserve that retains a portion of P2P sales in poolBalance, or require that total USDm in the contract always equals the maximum possible payout:
H-01 — P2P vs AMM Price Arbitrage / Griefing
buyShares fills P2P sell orders before routing to the AMM. If a P2P order is priced significantly above the current AMM implied probability (e.g., 0.99 USDm when AMM price is 0.50 USDm), a buyer calling buyShares is forced to fill the expensive P2P order first. While _minShares slippage protection helps, the execution is economically sub-optimal.
Recommended Fix: Compare the cheapest P2P order price against the current LMSR getPrice before filling, and skip P2P orders priced above AMM:
M-01 — closeBetting lacks access control
closeBetting lacks access controlAny user can call closeBetting once the betting deadline has passed. While the function requires the deadline to be expired, allowing any address to trigger state transitions can lead to unexpected bot behavior.
Recommended Fix: Restrict closeBetting to admin, creator, or a permissioned keeper address.
M-02 — Fee rounding dust always favors resolver
The resolverCut = totalFee - creatorCut - treasuryCut calculation means rounding dust is always absorbed by the resolver pool. Over many trades, this creates a systematic minor imbalance in fee distribution.
Recommended Fix: Document this as an explicit design choice, or implement round-robin dust assignment across the three recipients.
Findings Table
C-01
Critical
EventlyMarketsV3
Potential insolvency via P2P redemptions
False positive — BUY orders escrow USDm upfront; CLOB fills deduct from escrowed budget, not new USDm; poolBalance unaffected
H-01
High
EventlyMarketsV3
P2P vs AMM price arbitrage / griefing
Acknowledged — buyer sets _minFill slippage guard; skipping expensive asks would break price-time priority
H-02
High
EventlyMarketsV3
Subsidy / pool imbalance in claimCancelRefund
False positive — poolBalance reduced by gross; fees credited separately; invariant holds
M-01
Medium
EventlyMarketsV3
closeBetting lacks access control
Acknowledged — permissionless by design; requires deadline elapsed
M-02
Medium
EventlyMarketsV3
Fee rounding dust always favors resolver
Acknowledged — intentional; resolver cut absorbs 1-wei rounding dust
L-01
Low
EventlyMarketsV3
Missing nonReentrant on cancelMarket / closeBetting
Acknowledged
L-02
Low
EventlyMarketsV3
Question length limit bypassable via admin
Acknowledged
I-01
Info
EventlyMarketsV3
LMSR binary search tolerance near MIN_TRADE
Acknowledged
I-02
Info
EventlyMarketsV3
No event emitted by closeBetting
Resolved — v3.2: BettingClosed event added (QWEN-I03)
Production Blockers
C-01 (Critical): Potential P2P insolvency — review the poolBalance accounting against P2P-settled shares before high-volume deployment. The mathematical LMSR solvency guarantee applies to AMM-minted shares only; P2P fills may create an uncovered gap.
Severity Scale
Critical
Direct fund loss or permanent bricking — immediate production blocker
High
Fund loss possible under specific conditions
Medium
DoS, griefing, or logic error with economic impact
Low
Edge case, minor logic issue, or gas concern
Informational
Code quality, missing feature, or best practice
Status options: Fixed · In resolution · Acknowledged · Open · By design
Last updated
Was this helpful?

