# 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:

```solidity
// Suggestion: explicit solvency check on buy
require(
    usdm.balanceOf(address(this)) >= totalMintedShares + treasuryBalance + resolverPoolBalance,
    "Solvency check failed"
);
```

### 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:

```solidity
if (o.pricePerShare > getPrice(_marketId, _opt)) { idx++; continue; }
```

### 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
