# DeepSeek

**Tool:** DeepSeek R1 (DeepSeek AI) **Type:** 3-round AI audit (Systematic → Economic → Triage) **Contracts reviewed:** EventlyMarketsV3.sol (LMSR, b=200) · evently.sol v5.4 · EventlyProfiles.sol v1.3 **Chain:** MegaETH (Chain ID 4326) — Solidity ^0.8.20 **Date:** March 2026 **Status:** Complete — v3.2 post-audit fixes verified

***

## Summary

| Severity  | Count |
| --------- | ----- |
| Critical  | 0     |
| High      | 1     |
| Medium    | 2     |
| Low       | 2     |
| Info      | 2     |
| **Total** | **7** |

***

## Round 1 — Systematic Vulnerability Scan

### M-01 — Reentrancy risk in resolution / cancellation functions

**Severity:** Medium **Location:** `resolveMarket()`, `cancelMarket()`, `slashMarket()`

```solidity
function resolveMarket(uint256 _marketId, uint256 _winningOption) external {
    // ...
    _cancelAllOrders(_marketId); // calls _safeTransferFrom to sellers
}
```

Functions that change market state and then perform external transfers (ERC-1155 `safeTransferFrom`) are **not** protected by the `nonReentrant` modifier. Although state is updated before transfers, an attacker could re-enter through a malicious ERC-1155 receiver and execute operations that rely on the newly set `MarketStatus`. While most state-dependent functions check for `Active` or `BettingClosed` and would revert, the possibility of unexpected interactions remains — for example, a re-entrant call to `claimCancelRefund` after status is set to `Cancelled` but before all transfers have completed.

**Recommendation:** Add `nonReentrant` to `resolveMarket`, `cancelMarket`, and `slashMarket`.

***

### M-02 — Dead order entries can permanently block new orders

**Severity:** High (categorized as M-02 but functionally High impact) **Location:** `createSellOrder()`, `cancelSellOrder()`, `_cleanOrders()`

```solidity
function cancelSellOrder(uint256 _orderId) external nonReentrant {
    // ...
    o.active = false; // marks as dead, but orderId remains in _orderBook array
    o.sharesRemaining = 0;
    _safeTransferFrom(...);
}
```

When a sell order is cancelled, it is only marked `active = false`. The order ID is **not removed** from the `_orderBook` array for its (market, option) pair — the array length remains unchanged. An attacker can fill the array with 200 orders, cancel them all, and leave the array full of dead entries. After that, **no new orders can be created** for that (market, option) pair because `oids.length < MAX_ORDERS_PER_BOOK` will always fail. This permanently disables P2P trading for that option.

**Recommendation:**

* Call `_cleanOrders(marketId, optionIndex)` inside `cancelSellOrder` after marking the order inactive.
* Alternatively, allow creating a new order even if the array is at cap, provided enough dead entries exist (compact on-the-fly).

***

### M-03 — Precision loss in LMSR pricing may cause insolvency in edge cases

**Severity:** Medium **Location:** `getPrice()`, `_lmsrCost()`, `quoteBuy()`, `redeemWinnings()`

```solidity
// Inside _lmsrCost:
sum = add(sum, exp(wrap(int256(q[i] * 1e18 / b_))));
```

The contract uses integer division inside `wrap` before exponentiation, truncating small values to zero. The binary search in `quoteBuy` has a tolerance of `1e15` shares. Over many trades, accumulated rounding errors could cause the actual pool balance (`poolBalance + subsidyDeposited`) to be slightly less than the theoretical cost function value. In the worst case, `redeemWinnings` might revert because the remaining subsidy is insufficient for the last claimant, locking their winning shares permanently.

**Recommendation:**

* Add a small safety margin when checking `fromSubsidy <= m.subsidyDeposited` and emit a warning if the margin is approaching exhaustion.
* Alternatively, use a slight over-allocation at creation (subsidy += epsilon).

***

### L-01 — Inefficient order insertion gas pattern

**Severity:** Low **Location:** `createSellOrder()`

```solidity
oids.push(0);
for (uint256 i = oids.length - 1; i > insertAt; i--) {
    oids[i] = oids[i - 1];
}
oids[insertAt] = orderId;
```

The insertion logic first pushes a dummy zero, then shifts elements rightward. With `MAX_ORDERS_PER_BOOK = 200`, the worst-case overhead is 200 SSTORE operations per insertion. Acceptable at current scale but suboptimal.

**Recommendation:** Consider using a sorted linked list or a packed structure that avoids element shifting.

***

### I-01 — `MAX_ORDERS_PER_BOOK` cap not enforced against dead entries

**Severity:** Info **Location:** `createSellOrder()`

The cap `MAX_ORDERS_PER_BOOK = 200` is enforced at creation time against the raw array length, not the count of active orders. Dead (cancelled) entries count toward the cap. This is a documentation / design gap that compounds with M-02.

**Recommendation:** Document that the cap applies to total order slots (active + dead) for a given pair, and that operators should be aware of the cleanup requirement.

***

## Round 2 — Economic Attack Analysis

### E-01 — Griefing attack via order book spam (dead entries)

**Severity:** High (see M-02 above)

An attacker fills the order book with the maximum number of orders, then cancels them all. This costs only gas (shares are returned on cancellation), with no USDm at risk. It effectively disables P2P trading for that market-option pair, forcing all trades through the AMM at potentially worse prices. On MegaETH with low gas costs, the attack is cheaper than on L1.

**Recommendation:** Same as M-02 — clean dead entries on cancellation.

***

### E-02 — Creator can claim fees on cancelled markets

**Severity:** Low **Location:** `claimCreatorFees()`, `cancelMarket()`

If a market is cancelled after the betting deadline but before resolution, the creator can still call `claimCreatorFees` (if status is `Finalized`). A creator could intentionally generate volume via wash trading, then cancel the market to extract fees, with the fee cost borne by traders. The creator's collateral is returned on honest cancellation, reducing their net risk.

**Recommendation:** Consider forfeiting accrued creator fees to treasury on market cancellation, or require a minimum active duration before fees can be claimed.

***

### E-03 — LMSR rounding edge case (see M-03)

The same precision concern from M-03 applies in the economic context: rounding errors accumulating across many binary-search iterations could cause a final redeemer to encounter an underflow in `subsidyDeposited`. See M-03 for the full analysis.

***

## Round 3 — Adversarial Triage

### A-01 — Can funds be stolen?

**Finding:** No direct theft vector found. All USDm transfers use `safeTransfer` and follow the CEI pattern under `nonReentrant`. Market pool balances are only decreased by `redeemWinnings`, `claimCancelRefund`, and `sellToAMM`. The only risk is the rounding-induced insolvency (M-03), which would block a redemption but not steal funds — they would remain locked in the contract.

### A-02 — Can the contract be permanently bricked?

**Finding:** Partial bricking possible. The CLOB order book dead-entry flooding vector (M-02) has been resolved -- \_cleanBook() is now called immediately on cancelOrder (F-DS-M02). No function permanently disables the entire contract. The admin can still withdraw treasury, create markets, and resolve disputes.

### A-03 — Edge case: single bettor takes all

If a single user buys all shares of the winning option, they receive the entire pool on redemption. Correct and expected: `redeemWinnings` uses `poolBalance + subsidyDeposited`, which is guaranteed ≥ total winning shares by LMSR theory.

### A-04 — Edge case: all bettors on losing side

If no shares of the winning option were purchased, the winning supply is zero — no one can redeem. The `poolBalance` and `subsidyDeposited` remain locked in the contract indefinitely. No sweep mechanism exists. This is a known design limitation of prediction markets, not a security flaw, but worth documenting.

***

## Findings Table

| ID   | Severity | Contract         | Title                                                    | Status                                                                                      |
| ---- | -------- | ---------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| M-01 | Medium   | EventlyMarketsV3 | Reentrancy risk in resolution / cancellation functions   | **Resolved — nonReentrant added to resolveMarket, cancelMarket, slashMarket (L-01)**        |
| M-02 | High     | EventlyMarketsV3 | Dead order entries can permanently block new orders      | **Resolved — \_cleanBook called in cancelOrder (F-DS-M02)**                                 |
| M-03 | Medium   | EventlyMarketsV3 | Precision loss in LMSR pricing — edge case insolvency    | Acknowledged — negligible (\~1 wei/trade); LMSR solvency proven by cost function bound      |
| L-01 | Low      | EventlyMarketsV3 | Inefficient order insertion gas pattern                  | Acknowledged                                                                                |
| E-02 | Low      | EventlyMarketsV3 | Creator can claim fees on cancelled markets              | Acknowledged — fees claimable only after Finalized; cancelled markets never reach Finalized |
| I-01 | Info     | EventlyMarketsV3 | Order book cap not enforced against dead entries         | **Resolved — \_cleanBook removes dead entries immediately on cancelOrder (F-DS-M02)**       |
| A-04 | Info     | EventlyMarketsV3 | Unclaimed pool balance if winning option has zero supply | Acknowledged                                                                                |

***

## Production Blockers

**No production blockers remain.** All identified issues have been resolved in v3.2 (L-01, F-DS-M02) or acknowledged as acceptable design tradeoffs.

***

## Severity Scale

| Severity | Description                                                                                       |
| -------- | ------------------------------------------------------------------------------------------------- |
| Critical | Direct loss of user funds, permanent contract bricking, or complete bypass of access controls     |
| High     | Significant risk of funds being locked, DoS of core functionality, or major economic manipulation |
| Medium   | Non-critical issues that could lead to unexpected behavior, minor DoS, or precision loss          |
| Low      | Code quality, gas optimization, or edge-case issues with minimal impact                           |
| Info     | Recommendations, documentation gaps, or non-security design considerations                        |

*This audit was performed on the provided source code. No runtime testing or formal verification was performed.*
