Grok-4

Tool: Grok AI Security Auditor (xAI) v2026.03 Type: 3-round AI audit (Systematic → Economic → Triage) Contracts reviewed: evently.sol v5.4 · EventlyProfiles.sol v1.3 · EventlyMarketsV3.sol (LMSR, b=200) Chain: MegaETH (Chain ID 4326) — Solidity ^0.8.20 Date: March 2026 Status: Complete


Summary

Severity
Count

Critical

0

High

0

Medium

1

Low

2

Info

3

Total

6

Overall Assessment: The contract is production-ready with strong safeguards. All previously reported issues (F-02, F-03, A-03) are correctly patched. Core LMSR invariants, CEI patterns, and access controls hold. One medium economic design gap exists around subsidy handling on cancellation.


Round 1 — Systematic Vulnerability Scan

Reentrancy: Fully mitigated. Every external-interaction function uses the nonReentrant mutex. All state updates precede external calls (strict CEI pattern). ERC-1155 onERC1155Received/onERC1155BatchReceived are pure selectors with no side effects. SafeERC20 prevents ERC-20 reentrancy vectors.

Access Control: Robust. onlyWhitelisted (with admin bypass) gates all user actions. onlyAdmin protects admin-only paths. Creator-only resolution, dispute, and fee claims are correctly restricted. Whitelist/invite mechanics cannot be bypassed.

Integer Arithmetic & Rounding: Safe (Solidity 0.8+ checked arithmetic). Fee calculations use consistent integer division; resolver cut absorbs dust. No overflow paths reachable under realistic quantities (quoteBuy caps at 26,000e18 shares per option).

Token Handling: Standard OpenZeppelin ERC-1155 + SafeERC20. Escrow in createSellOrder and safe mint/burn/transfer patterns are correct. Token ID encoding (marketId * MAX_OPTIONS + opt) cannot overflow in practice.

LMSR Math Correctness:

  • _lmsrCost, getPrice, quoteBuy (binary search), quoteSell implement the canonical LMSR formulas.

  • Binary search in quoteBuy is monotonic and bounded (tolerance 1e15 aligns with MIN_TRADE).

  • C(q) = b · ln(Σ exp(qᵢ/b)) invariant holds; PRBMath SD59x18 usage is precise and within documented safe ranges.

No systematic vulnerabilities found in Round 1.


Round 2 — Economic Attack Analysis

LMSR Solvency: Guaranteed. At any point poolBalance + subsidyDeposited = C(current quantities) ≥ q_winner (because C(q) ≥ b · ln(exp(q_winner/b)) = q_winner). redeemWinnings draws from pool first, then subsidy, never exceeding available funds. Sequential claims preserve the invariant.

Fee Accounting: Accurate 2.5% split (configurable, hard-capped at 5%). P2P and AMM paths both route fees to the correct buckets (treasuryBalance, resolverPoolBalance, creatorAccruedFees). Admin-market creator cut is correctly redirected to treasury.

Order-Book Safety: MAX_ORDERS_PER_BOOK = 200 prevents griefing. Cheapest-first fill logic, partial-fill support, and post-fill _cleanOrders compaction are correct. Sell-order escrow and cancellation paths cannot be abused.

Resolution MEV / Front-running: Creator resolution window is time-bound and can be overridden by anyone after the resolution deadline. Dispute mechanism + admin settlement provides a credible challenge path. No on-chain MEV vector allows unauthorized resolution.

Subsidy-Exhaustion / Refund Solvency: Impossible to exhaust subsidy beyond its mathematical bound. claimCancelRefund uses pre-burn total-supply snapshot (F-02 fix) and pro-rata math is sound under sequential calls.

No economic attacks succeed — except the design gap identified in M-01 below.


Round 3 — Adversarial Triage

Can funds be stolen from poolBalance or subsidyDeposited? No. All outflows are either:

  • Explicit redemptions/refunds (math-guaranteed)

  • Fee withdrawals by authorized parties

  • Admin slash/cancel (funds move only to treasury or rightful owners)

Admin-key compromise is the only vector, which is an accepted centralization trade-off.

Can the contract be permanently bricked? No. All state transitions are reachable; no dead-end status combinations. Order-book and quantity arrays remain manageable.

Edge cases simulated:

  • Zero-volume market → cancel succeeds, collateral returned ✅

  • Single bettor takes entire liquidity on one side → redeem works ✅

  • All bets on losing side + honest resolution → no winning shares, pool locked (see M-01) ✅

  • Full dispute flow (creator wins / loses) → accounting correct ✅

  • Extreme quantities → quoteBuy capacity guard triggers before PRBMath overflow ✅


Findings

M-01 — Medium

Title: subsidyDeposited is permanently locked on Cancelled/Slashed markets

Contract: EventlyMarketsV3.sol

Description: The creator (or admin for admin markets) pays the LMSR initial subsidy (b · ln(n)) at creation. On cancelMarket / slashMarket, only poolBalance is refunded pro-rata via claimCancelRefund. The subsidyDeposited value is never included in the refund pool and has no withdrawal path. In finalized markets, any unclaimed winnings leave the remaining poolBalance + subsidyDeposited locked forever.

Impact: Creator permanently loses the subsidy on cancellation. Unclaimed funds in resolved markets are locked indefinitely with no recovery mechanism.

Recommended Fix:

  1. Include subsidyDeposited in the effective refund pool in claimCancelRefund (or return it to creator on honest cancel).

  2. Consider an optional admin sweep function for unclaimed funds after a long timeout (e.g. 365 days post-finalization).

Status: Open


L-01 — Low

Title: quoteBuy binary search returns slightly conservative share count due to flooring

Contract: EventlyMarketsV3.sol

Description: The binary search exits with sharesOut = lo where C(q + lo) - C(q) < _usdm (tolerance 1e15). The buyer receives marginally fewer shares than the exact net USDm paid would justify.

Impact: Negligible (< 0.001 shares per trade). Fully protected by _minShares slippage parameter.

Recommended Fix: Optional — after binary search, compute exact shares via Newton iteration, or document the 0.001-share tolerance explicitly.

Status: Acknowledged


L-02 — Low

Title: No market-existence check in view functions

Contract: EventlyMarketsV3.sol

Description: getMarketInfo, getPrice, getQuantities, etc. accept any _marketId. Non-existent markets return zero / default struct values without reverting, potentially confusing off-chain consumers.

Impact: No on-chain fund risk. Minor UI/UX confusion.

Recommended Fix:

Status: Open


I-01 — Info

Title: NatSpec still references CPMM in key documentation strings

Contract: EventlyMarketsV3.sol

Description: The top-level @notice and the BUYING description in the contract header still reference "CPMM pricing (binary: pool_j / (pool_i + pool_j))". The implementation is pure LMSR — these comments are outdated.

Recommended Fix: Update all inline documentation to reference LMSR.

Status: Open


I-02 — Info

Title: No expiry or sweep for unclaimed creator fees / resolver pool

Contract: EventlyMarketsV3.sol

Description: creatorAccruedFees and resolverPoolBalance have no timeout mechanism. Dust can accumulate indefinitely.

Recommended Fix: Optional admin sweep function after a configurable timeout (e.g. 2 years) with event emission.

Status: Open


I-03 — Info

Title: whitelistedCount is incremented but never read on-chain

Contract: EventlyMarketsV3.sol

Description: whitelistedCount is a purely informational counter. It is incremented in addToWhitelist and batchWhitelist but never read by any on-chain logic.

Status: Acknowledged


Findings Table

ID
Severity
Contract
Title
Status

M-01

Medium

EventlyMarketsV3.sol

subsidyDeposited permanently locked on cancel/slash

Resolved — v3.2: included in claimCancelRefund effective pool (GROK-M01)

L-01

Low

EventlyMarketsV3.sol

quoteBuy binary search conservative flooring

Acknowledged

L-02

Low

EventlyMarketsV3.sol

Missing market-existence checks in view functions

Resolved — v3.2: createdAt != 0 guard on all views (GROK-L02)

I-01

Info

EventlyMarketsV3.sol

Outdated CPMM references in NatSpec

Resolved — v3.2: NatSpec updated to LMSR + CLOB

I-02

Info

EventlyMarketsV3.sol

No expiry for unclaimed creator fees / resolver pool

Acknowledged — admin sweep on roadmap

I-03

Info

EventlyMarketsV3.sol

whitelistedCount never read on-chain

Acknowledged


Production Blockers

None. The contract can be deployed as-is. M-01 is an economic design choice that does not affect security invariants or user funds in active markets.


Severity Scale

Severity
Definition

Critical

Immediate loss of user funds or permanent contract bricking

High

Significant economic loss or denial-of-service under realistic conditions

Medium

Economic loss or UX degradation that requires user awareness or protocol upgrade

Low

Minor precision, gas, or documentation issues with negligible impact

Info

Observations, best-practice recommendations, or non-functional notes

Last updated

Was this helpful?