# Perplexity

**Perplexity GPT-5.1 --- Security Report**

**Tool:** Perplexity GPT-5.1\
**Type:** 3-round AI audit (Systematic → Economic → Triage)\
\*\*Contracts reviewed: evently.sol v5.4 · EventlyProfiles.sol v1.3 · EventlyMarketsV3.sol **Chain:** MegaETH (Chain ID 4326) --- Solidity ^0.8.20\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​\
**Date:** March 2026\
**Status:** Complete

**Summary**

Across the three contracts, I found 1 High, 3 Medium, 4 Low, and several Informational issues, mostly around access control, minor logic bugs, and DoS/UX footguns rather than direct fund theft vectors. The patched evently v5.3 and EventlyProfiles v1.3 handle reentrancy and pull-payments well, but EventlyMarketsV3 still exposes meaningful griefing, fee-routing, and accounting risks in its AMM and order book logic. No clear "instant full-treasury drain" production blocker appears, but I classify the High issue and one Medium in V3 as practical blockers before mainnet deployment.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

**Findings**

***

**ID** **Severity** **Contract** **Title** **Status**

***

F1 High EventlyMarketsV3 Incomplete nonReentrancy coverage on ERC20/1155 flows Fixed — V3: nonReentrant on all external state-mutating functions

F2 Medium EventlyProfiles setAuthorizedCaller ignores \_authorized argument Acknowledged

F3 Medium EventlyMarketsV3 Order book unbounded loops enable griefing/DoS Fixed — A-03: MAX\_ORDERS\_PER\_BOOK = 200

F4 Medium EventlyMarketsV3 Weak validation of market parameters (deadlines, options) Fixed — V3: requires bettingDeadline>now, resolutionDeadline>betting, option length checks

F5 Low evently Referral ETH transfer hard-reverts on profile contract fail By design

F6 Low EventlyProfiles Leaderboard O(n²) iteration may become unusable at scale Acknowledged

F7 Low EventlyMarketsV3 Fee accounting edge cases on cancel / slash / finalize Fixed — V3: creatorAccruedFees zeroed to treasury on slash/dispute loss

F8 Low EventlyMarketsV3 Potential dust and rounding issues in LMSR share math Acknowledged

F9 Informational evently Manual timer expiry trigger is MEV-observable Frontend handles

F10 Informational EventlyProfiles Username mapping is case-normalized but external key isn't By design

### F11 Informational EventlyMarketsV3 Market creator informational advantage is inherent By design

**Round 1 --- Systematic Review**

**1. Reentrancy**

* evently.sol
  * Uses a simple \_locked nonReentrant modifier on all external functions that touch ETH balances (dailyCheckIn, buyCredits, withdrawCredits, click\*, claimWinnings, flushTreasuryFees).\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * \_endGame resets core state before paying the winner and falls back to pull-based pendingWithdrawals if the call fails, which is good CEI plus pull-payment design.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * External calls into profilesContract (view-like + small state updates) are not reentrancy-guarded from the profiles side, but Profiles has its own guard only around ETH transfers (referral claim). This coupling seems safe given Profiles never calls back into evently.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyProfiles.sol
  * Only claimReferralEarnings is nonReentrant and performs CEI before sending ETH to msg.sender, which is correct.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * withdrawFees sends full balance to owner without nonReentrant, but the function cannot be reentered from within this contract because there are no callbacks here; still, making it nonReentrant would be slightly safer defense in depth.
* EventlyMarketsV3.sol (partial, inferred from pattern)
  * Declares its own \_locked guard, but you need to verify every function that moves USDm (AMM buy/sell, create/cancel orders, redeem, resolve/finalize) is actually marked nonReentrant and respects CEI.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * Because Markets V3 is an ERC1155, callbacks like onERC1155Received on external receivers (when transferring positions) could open up cross-contract reentrancy if such transfers are permitted before finalization. The spec says ERC-1155 positions are non-transferable pre-resolution "by design," but you must ensure safeTransferFrom is disabled or overridden accordingly.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

Finding F1 (High):\
If any of the key flows (e.g., AMM trade functions, redeemWinningShares, cancelSellOrder) lack nonReentrant while performing external ERC20 transfers or 1155 mints/burns plus internal accounting, you have a concrete reentrancy surface that could be abused to mint extra shares or drain the USDm pool. I treat this as High until a complete pass confirms all such functions are guarded and CEI-compliant.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

**2. Access Control**

* evently.sol
  * onlyOwner correctly protects transferOwnership, setTreasury, pause, unpause, and flushTreasuryFees, plus seedPot is owner-only.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * Game play functions are permissionless but gated behind hasProfile and whenNotPaused, which is fine.
* EventlyProfiles.sol
  * setGameContract is owner-only, update\* and game-only mutating functions are protected with onlyGame as expected.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * authorizedCallers is intended as an owner-settable whitelist for recordSwap, but setAuthorizedCaller(address \_caller, bool \_authorized) ignores \_authorized and always sets the value to true. This prevents revocation and could accidentally re-enable a compromised address. (F2, Medium)\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyMarketsV3.sol
  * Uses admin as privileged account; must ensure functions like slashMarket, cancelMarket, or any treasury-draining path are properly onlyAdmin-gated. From the context, the presence of creator collateral and treasury balance implies critical admin-only flows.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * Whitelist logic (whitelistEnabled, whitelisted) plus invite codes provide optional access gating; ensure that any bypass (e.g., admin markets) is explicit and documented.

**3. Integer Arithmetic**

* All contracts compile under Solidity ^0.8.20, so arithmetic overflows/underflows revert by default.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* evently.sol
  * Percentage math for POT/TREASURY/REFERRAL uses small constants; there is no risk of overflow, but the distribution sometimes leaves implicit dust (e.g., CLICK\_PRICE - potAdd - tFee) as rFee, which is still consumed in the flow.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * \_creditCostPerClick uses (CLICK\_PRICE \* (100 - CREDIT\_FEE\_PERCENT)) / 100 = 0.001 \* 0.85 = 0.00085 ETH, consistent with 15% fee.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyProfiles.sol
  * Points for swaps (\_volumeUsdCents \* SWAP\_POINTS\_PER\_USD\_CENT) / 100 are straightforward; the \_volumeUsdCents <= 1,000,000 guard removes extreme multipliers.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyMarketsV3.sol
  * CPMM math (not fully shown) will combine poolBalance, virtualPools, and SHARE\_UNIT (1e18) to calculate shares and price. These divisions can introduce dust; some residual USDm or shares may become unclaimable. That is a Low severity accounting issue unless it accumulates significantly (F8).\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

**4. Randomness**

* evently.sol
  * \_shouldEnd() uses block.timestamp, block.prevrandao, msg.sender, clickCount, and \_nonce to generate a pseudo-random value mod 1000, compared to a per-mille risk parameter.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * You explicitly mark this as an intentional design choice (VRF on roadmap), so I do not treat it as a vulnerability, but note that miners / block producers can influence prevrandao and MEV searchers can attempt to game end conditions.
* EventlyMarketsV3.sol
  * Does not rely on randomness; prices are deterministic from pools and order book. No further randomness concerns.

**5. Logic & State**

* evently.sol
  * \_endGame correctly handles the edge case when winner == address(0) by resetting state and starting a new round without payout.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * When block.timestamp >= timerEnd inside \_processClick, non-credit/non-bonus clicks still add POT\_PERCENT of one CLICK\_PRICE to the pot before ending; credits and bonus clicks do not add to pot, honoring the insolvency fix.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * clickFree increments clickCount but does not send ETH, and the timer extension logic is consistent with paid clicks.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyProfiles.sol
  * Username uniqueness is enforced on lowercase, while the stored username preserves original case. This is a good anti-squatting pattern, but external callers querying usernameToAddress must always pass lowercased string; the contract's own \_resolveReferrer currently indexes with the raw \_referrerUsername without lowercasing in v1.3's text snippet, but later reads show it using lowercased keys. In paste.txt, \_resolveReferrer still uses usernameToAddress\[\_referrerUsername], which bypasses lowercasing and makes those lookups case-sensitive, undermining the design (Informational F10, since UX, not funds).\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyMarketsV3.sol
  * Market lifecycle: Active → BettingClosed → Resolved/Disputed → Finalized/Cancelled/Slashed, with creator collateral flags and fee flags.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * Potential issues:
    * If deadlines or statuses are not strictly checked in all entry points, you can buy after bettingDeadline or redeem before Finalized. (F4, Medium)
    * Without careful handling, creatorCollateralReturned and creatorFeePaid might be toggled multiple times or not at all if resolution paths diverge (e.g., cancelled vs slashed). (F7, Low)

**6. Denial of Service**

* evently.sol
  * Core game loops over clicks in clickRich and useAllCredits are bounded by MAX\_CLICKS\_PER\_TX = 200, specifically avoiding unbounded loops.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * Timer expiry requires a manual checkTimerExpiry call, but that's a known design choice; any user can call it once time has elapsed.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyProfiles.sol
  * \_getLeaderboard uses nested loops over allPlayers to compute a top-k leaderboard in O(n²) time in the worst case. As allPlayers grows large, those view calls may become too expensive to execute on-chain, effectively DoS'ing the function (F6, Low). This affects only visibility, not funds.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyMarketsV3.sol
  * Order book uses arrays of order IDs per (marketId, optionIndex), and insertion maintains sorted-by-price order by shifting elements in a nested fashion. Cancelling orders likely traverses arrays to remove IDs. This is prone to gas-heavy execution and griefing: a user can create many tiny orders to bloat the order book and make trades or cancellations revert from gas usage (F3, Medium).\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

**7. Front-running / MEV**

* evently.sol
  * Last-click-wins plus visible timer and \_shouldEnd() randomness means MEV can observe near-expiry clicks and potentially race them, but this is structurally baked into the game and flagged as acceptable design. (F9, Informational)\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyMarketsV3.sol
  * AMM trades and P2P fills are deterministic given the order book; MEV can reorder trades and fills but cannot break invariants if functions are coded correctly.
  * However, if there is any check like "fill cheapest order, then mint from AMM," MEV can place and cancel orders around a user's transaction or front-run with their own fills to capture surplus. That is more economic than technical, and belongs in Round 2.

**Round 2 --- Economic Analysis**

**Pot Solvency (evently.sol)**

* Pot is increased only by direct ETH payments (click price shares, seedPot, plus one last increment on expiry); credits and bonus clicks do not add to the pot but use prepaid balances, deliberately fixing earlier insolvency risks.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* Winnings equal the pot at end-game; referral and treasury fees come only from non-credit paid clicks. No flow appears to create promises exceeding available ETH, so insolvency risk is low provided no external invariant (like off-chain rewards) depends on surplus.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

**Credit System Attacks**

* Credits are bought with ETH, with a 15% fee sent to treasury at purchase time; withdrawCredits refunds only the remaining balance (post-fee) and is nonReentrant.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* Credits can be used for clicks (clickWithCredit, useAllCredits), but bonus clicks do not add to pot or fees; they are purely an extra chance at winning, funded implicitly by the fee margin and prior paid clicks.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* There is no obvious way to mint credits for free or double-spend them, as all write paths to creditBalance are owner-neutral and guarded. The primary risk is not economic theft but users overestimating pot contribution from credit usage; this is clearly documented in comments.

**Referral Sybil Vectors**

* Referrals require referred user to reach REFERRAL\_ACTIVATION\_THRESHOLD = 0.01 ETH totalSpent before rewards are credited, limiting trivial sybil farming.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* However, a single controller can spin many addresses, each legitimately spending 0.01 ETH, to farm referral rewards; that is economically bounded by the fee structure and not a contract-level vulnerability.
* Profiles store referral relationships on-chain and allow only a single referrer per player; there is no on-chain limit to the number of referrals per referrer, which is intentional.

**Market Creator Insider Advantages (EventlyMarketsV3)**

* Creators receive 2% of all trade volume fees for their market, but those fees are paid only after finalization, and a 50 USDm collateral is locked to incentivize honest resolution.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* Creators can choose question wording, resolution criteria, resolution window, and they may have informational advantage; that is inherent to prediction markets. The main concern is whether they can:
  * Resolve in their favor despite objective outcome, or
  * Stall resolution to keep fees or block redemptions.
* The presence of Disputed and Slashed statuses plus DISPUTE\_COLLATERAL suggests a mechanism for disputer challenges, but details are truncated; if admin has unilateral power to slash or finalize, governance centralization is high and may be a social, not technical, risk (F11, Informational).

**AMM Manipulation Vectors (V3 CPMM)**

* Prices come from virtualPools and poolBalance; if virtualPools are seeded with equal liquidity and not adjusted arbitrarily by admin, creator has no special ability beyond trading like anyone else.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* If any admin/creator-only function can directly mutate virtualPools or poolBalance without corresponding share mint/burn, that is a latent rug vector; ensure only trades and resolution update these fields.
* Fee structure (5% each trade, 3% treasury, 2% creator) is symmetric on buy and sell; users cannot create cycles that generate net profit solely from fees unless rounding errors are exploitable (F8).

**Order Book Griefing (V3 P2P Orders)**

* Sorted arrays for order IDs per option mean that:
  * Creating many small orders at extreme prices forces expensive insertions.
  * Canceling or filling orders likely needs scanning and shifting arrays.
* An attacker can spam a market's order book to the point where legitimate order placements or fills hit the gas limit and revert, effectively DoS'ing that market (F3, Medium). This is a credible griefing vector, not directly profitable but harmful.

**ERC-1155 Position Trading Edge Cases**

* ERC-1155 positions are non-transferable pre-resolution "by design," which is good to prevent unauthorized secondary markets before a final outcome.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* After finalization, redemption of winning shares must burn the correct amount and pay pro-rata USDm; losing shares become worthless. The tricky cases are:
  * Partial redemptions leaving dust shares;
  * Rounding such that last redeemer receives disproportionate or zero payout.
* There's no clear double-spend path if burning happens before transfer of funds (CEI), but dust and rounding (F8) can produce unintuitive payouts.

**Treasury Failure Scenarios**

* evently.sol:
  * Treasury fees are sent via call; if they fail in dailyCheckIn, the ETH is added to accumulatedTreasuryFees and can be flushed later, preventing game reverts caused by treasury failure.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
  * In \_processClick, referral and treasury transfers both require success; a failing treasury contract can then block new clicks that pay fees (F5, Low). This is aligned with "protocol revenue" semantics but can stall the game.
* EventlyProfiles.sol:
  * withdrawFees sends all ETH in Profiles to owner; if owner is a contract that reverts or uses too much gas, fees become stuck but this is owner revenue, not user funds.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* EventlyMarketsV3.sol:
  * Treasury balance is tracked in treasuryBalance alongside creatorAccruedFees and poolBalance; mis-accounting across slash/cancel/finalize could send excess funds to treasury or leave collateral stranded (F7, Low).
  * A failing treasury recipient contract could cause trade functions that immediately forward fees to revert, effectively pausing some markets; using an internal balance then separate withdrawal (like evently's flushTreasuryFees) would be more robust.

**Round 3 --- Triage**

**F1 --- Incomplete nonReentrancy coverage on ERC20/1155 flows (High, EventlyMarketsV3)**

* Classification: Real Vulnerability
* Rationale: Any function that both updates market accounting and transfers ERC20 or ERC1155 can be a reentrancy target if not guarded and following CEI, especially via ERC1155 receiver hooks or ERC20 tokens with callbacks.
* Fix (pattern snippet):

text

uint256 private \_locked = 1;

modifier nonReentrant() {

require(\_locked == 1, "Reentrant");

\_locked = 2;

\_;

\_locked = 1;

}

// Example: AMM buy function

function buyFromAMM(uint256 marketId, uint256 optionIndex, uint256 usdmAmount)

external

nonReentrant

{

Market storage m = \_markets\[marketId];

require(m.status == MarketStatus.Active, "Not active");

require(block.timestamp < m.bettingDeadline, "Betting closed");

// 1) Effects

// compute sharesOut based on virtualPools and poolBalance

uint256 sharesOut = \_calcSharesOut(m, optionIndex, usdmAmount);

m.poolBalance += usdmAmount;

optionSupply\[marketId]\[optionIndex] += sharesOut;

m.totalVolume += usdmAmount;

// compute fees, update treasuryBalance and creatorAccruedFees

(uint256 toTreasury, uint256 toCreator, uint256 netAmount) =

\_splitFees(usdmAmount);

treasuryBalance += toTreasory;

creatorAccruedFees\[marketId] += toCreator;

// 2) Interactions

usdm.safeTransferFrom(msg.sender, address(this), usdmAmount);

\_mint(msg.sender, \_tokenId(marketId, optionIndex), sharesOut, "");

}

* Production blocker: Yes, until you verify and enforce nonReentrant + CEI on all external functions doing token transfers and burns/mints.

**F2 --- setAuthorizedCaller ignores \_authorized argument (Medium, EventlyProfiles)**

* Classification: Real Vulnerability (logic bug)
* Rationale: Owner cannot revoke previously authorized callers or set them to false; the function's signature is misleading and may cause security assumptions to be wrong.
* Fix:

text

function setAuthorizedCaller(address \_caller, bool \_authorized) external onlyOwner {

authorizedCallers\[\_caller] = \_authorized;

}

* Production blocker: No, but advisable to fix before relying on dynamic whitelist management.

**F3 --- Order book unbounded loops enable griefing/DoS (Medium, EventlyMarketsV3)**

* Classification: Design Tradeoff (with real DoS impact)
* Rationale: Attacker can flood order books with many tiny orders, making buy, sell, or cancel operations revert due to gas; economically cheap but disruptive.
* Fix options:
  * Hard cap number of active orders per (market, option) per address.
  * Charge protocol-level fees for order placement and cancel, or a per-order gas refund scheme.
  * Move to off-chain order book with on-chain settlement of signed orders.
* Example soft mitigation:

text

uint256 public constant MAX\_ORDERS\_PER\_USER\_PER\_OPTION = 50;

mapping(uint256 => mapping(uint256 => mapping(address => uint256))) public userOrderCount;

function \_beforeCreateOrder(uint256 marketId, uint256 optionIndex, address user) internal {

require(

userOrderCount\[marketId]\[optionIndex]\[user] < MAX\_ORDERS\_PER\_USER\_PER\_OPTION,

"Too many orders"

);

userOrderCount\[marketId]\[optionIndex]\[user] += 1;

}

* Production blocker: I recommend treating this as a blocker for high-volume public deployment unless you accept this DoS risk.

**F4 --- Weak validation of market parameters (Medium, EventlyMarketsV3)**

* Classification: Real Vulnerability (misconfiguration risk)
* Rationale: If not already present, you must validate that bettingDeadline < resolutionDeadline, options.length is between MIN\_OPTIONS and MAX\_OPTIONS, and deadlines are in the future. Otherwise, markets could be unresolvable or permanently stuck.
* Fix example in createMarket:

text

function createMarket(

string memory question,

string\[] memory options,

Category category,

string memory resolutionCriteria,

string memory imageUrl,

uint256 bettingDeadline,

uint256 resolutionDeadline

) external nonReentrant {

require(options.length >= MIN\_OPTIONS && options.length <= MAX\_OPTIONS, "Bad options");

require(bettingDeadline > block.timestamp, "Betting in past");

require(resolutionDeadline > bettingDeadline, "Resolution before betting end");

// rest of creation logic...

}

* Production blocker: Medium; misconfigured markets can be stuck but do not directly lose funds if cancellation/refund paths exist.

**F5 --- Referral ETH transfer hard-reverts on profile contract fail (Low, evently)**

* Classification: Design Tradeoff
* Rationale: \_processClick requires successful transfer to profilesContract for referral fees and to treasury for remaining fee; if either fails, the click reverts and user cannot play.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* Possible mitigation: Mirror the accumulatedTreasuryFees pattern and accumulate failed referral amounts instead of reverting.

**F6 --- Leaderboard O(n²) DoS-at-scale (Low, EventlyProfiles)**

* Classification: Design Tradeoff
* Rationale: On large allPlayers, leaderboard views become too expensive; but they are non-critical and view-only.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* Potential improvement: Maintain incremental sorted leaderboards, or compute top lists off-chain.

**F7 --- Fee accounting edge cases (Low, EventlyMarketsV3)**

* Classification: Design Tradeoff (needs careful review in full code)
* Rationale: Complex states (Cancelled, Slashed, Finalized) with multiple flags (creatorCollateralReturned, creatorFeePaid) plus treasuryBalance and poolBalance easily create mis-accounting paths if not consistently updated.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​
* Recommendation: Unit-test every lifecycle path to ensure total USDm in equals net of: all user redemptions, creator fees, and treasury fees.

**F8 --- Dust and rounding in CPMM (Low, EventlyMarketsV3)**

* Classification: Design Tradeoff
* Rationale: Share math with SHARE\_UNIT = 1e18 and integer division will leave small residuals; last redeemer or treasury must be designated as dust recipient.
* Example mitigation: Track unclaimed dust and direct it explicitly to treasury or burn address during finalization, and document this behavior.

**F9 --- Manual timer expiry and MEV (Informational, evently)**

* Classification: By design
* Rationale: checkTimerExpiry is public and MEV-visible; searchers can time expiry calls, but they cannot retroactively change lastClicker.\[[ppl-ai-file-upload.s3.amazonaws](https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/322944648/1143cb5c-0977-4e61-86ff-8fa95dbb5d99/paste.txt)]​

**F10 --- Username mapping case pitfalls (Informational, EventlyProfiles)**

* Classification: Design Tradeoff / UX issue
* Rationale: Lowercased uniqueness but raw \_referrerUsername lookups can cause confusion; ensure all internal mappings use \_toLower.
* Small fix: Use \_toLower inside \_resolveReferrer (which you partially do in paste, but ensure consistency).

**F11 --- Market creator informational advantage (Informational, EventlyMarketsV3)**

* Classification: By design
* Rationale: Creators choosing questions and resolution criteria will always have some informational advantage; that's inherent to this product class.

**Reentrancy Surface Summary**

***

**Function (conceptual)** **Guard** **CEI Applied** **Verdict**

***

***

***

**Function (conceptual)** **Guard** **CEI Applied** **Verdict**

***

evently.dailyCheckIn nonReentrant Yes Safe

evently.buyCredits nonReentrant Yes Safe

evently.withdrawCredits nonReentrant Yes Safe

evently.clickDirect / clickRich / clickFree nonReentrant Yes (via \_processClick then external calls) Safe

evently.useAllCredits nonReentrant Yes Safe

evently.claimWinnings nonReentrant Yes Safe (pull)

evently.flushTreasuryFees nonReentrant Yes Safe

EventlyProfiles.withdrawFees None Partial Low-risk

EventlyProfiles.claimReferralEarnings nonReentrant Yes Safe

EventlyMarketsV3.buyFromAMM (example) nonReentrant? Varies Review needed

EventlyMarketsV3.sellToAMM (example) nonReentrant? Varies Review needed

EventlyMarketsV3.createSellOrder nonReentrant? Likely Likely safe

EventlyMarketsV3.cancelSellOrder nonReentrant? Varies Review needed

EventlyMarketsV3.fillSellOrder nonReentrant? Varies Review needed

EventlyMarketsV3.redeemWinningShares nonReentrant? Varies Review needed

EventlyMarketsV3.resolveMarket nonReentrant? Varies Review needed

### EventlyMarketsV3.finalizeMarket nonReentrant? Varies Review needed

For evently and EventlyProfiles, reentrancy risk is well-managed; for EventlyMarketsV3, carefully audit and enforce nonReentrant + CEI on every external-call-bearing function before production deployment.
