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

Severity
Count

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

Any 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

ID
Severity
Contract
Title
Status

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

Severity
Definition

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?