# TICKET — adversarial source audit

**Review date:** 14 September 2026  
**Reviewed artifact:** `review-pack.zip`, manifest cut `2026-09-14T11:40:39.565Z`  
**Source identity:** all 15 source SHA-256 hashes match `MANIFEST.txt`; each source file is also present unchanged in the concatenated bundle. The manifest says these files include changes beyond git HEAD `4a2cacdc972d552156e0127aae1fca121501055c`. This review is of the packaged bytes, not that commit alone.

## Assessment

**No critical vulnerability was established. The jackpot allocation rule needs correction before launch.** Under the ledger's rule of selecting N distinct eligible wallets and paying them equal shares, an attacker can use negligible stakes in many wallets to capture a large fraction of a drop. Honest execution of the published drawing rules does not prevent this.

The review also identified two substantive Season 1 specification failures: expansion does not necessarily bring the pool price to target, and the season can contain 43–44 settlements instead of the advertised 42 nights. The prediction market has separate loss and lockup paths, but the supplied ledger explicitly says it is **unwired for Season 1**. Those findings are not presented as current Season 1 deposit exposure.

| ID | Severity | Finding | Applicability / evidence |
|---|---|---|---|
| F-01 | **High** | Dust wallets can capture equal-share jackpot payouts | Season 1 drawing rules; mathematical reproduction. Actual keeper implementation absent |
| F-02 | **High** | Market accepts a bet on an already-certain winning outcome | Unwired market; source and arithmetic reproduction |
| F-03 | **High** | Market deposits have no exit if their settlement epoch never occurs | Unwired market; cross-contract state trace |
| F-04 | **Medium** | TWAP-based pool mint can push spot below target and disable both Buffer regimes | Season 1; source and arithmetic reproduction |
| F-05 | **Medium** | A 42-day season can execute 43 or 44 settlements | Season 1 if configured for 42 days; state-machine reproduction |
| F-06 | **Medium** | Late market opening combines a new cumulative with an older timestamp | Unwired market; arithmetic reproduction |
| F-07 | **Low** | Security bounds and supporting citations still contradict the implementation or lack supplied evidence | Pack-wide; detailed inventory below |

Severity reflects impact when the stated prerequisites hold. “Reproduced” in this report means an independent Python arithmetic or state-machine reproduction, **not an EVM exploit transaction**. For F-01, the finding is against the supplied product requirements; Solidity alone does not implement winner selection.

## Scope and verification limits

Reviewed all ten protocol contracts and the five included helper/interface files. The brief's “14 files” count is stale; the manifest lists 15. Reviewed the value-flow ledger as requirements and checked relevant comments independently. OpenZeppelin is excluded as requested. The deliberately withheld `DECISIONS.md` and `CLAUDE.md` were not requested or consulted.

Assumed the supplied deployment facts: TICKET has 9 decimals, USDG has 6, genesis starts with zero TICKET supply, the pool follows Uniswap v2 mechanics, and launch ownership is a 2-of-3 multisig without an ownership timelock. The brief names intended chain 4663; the manifest identifies existing **testnet 46630** addresses. Neither deployment nor on-chain wiring was verified.

No compiler, Foundry, EVM runner, dependency lockfile, deployment scripts, keeper/draw implementation, complete module addresses, deployed bytecode, or pair implementation was supplied. No compiler or EVM runner was preinstalled, and external source/dependency retrieval was unavailable. Therefore there is **no build, bytecode-equivalence, live-chain, fork-test, or callback-execution attestation** in this report.

The evidence archive contains a standard-library Python script and its actual output. It reproduces the findings below, checks all source hashes when given the extracted pack, and performs 2,500 genesis allocation scenarios plus 300 independent staking reward scenarios of 42 epochs each. These checks supplement source review; they are not a replacement for Solidity integration tests.

## F-01 — High — Sybil wallets capture equal-share jackpot payouts

**Locations:** `src/TicketStrike.sol:237` (`winnersFor`, especially 245–249); `src/TicketStaking.sol:642` (only positive stake required), `:919` (`scoreOf`); `value-flow-ledger.md:58` (row 20, winner count, eligibility and equal shares).

**Root cause.** The number of winners grows with the number of eligible **wallets**, has a minimum of ten, and is capped only by that same wallet count. Each selected wallet receives an equal amount. A positive stake and positive stake-epoch score are sufficient for eligibility; no meaningful minimum contribution is specified. Stake weighting cannot protect an equal-share draw when enough distinct wallets must be selected.

**Concrete exploit path — thin field:**

1. One genuine wallet has a large active stake. Before settlement 4, an attacker funds nine fresh wallets with one TICKET base unit each (`0.000000001 TICKET` per wallet).
2. Each wallet calls `approve(staking, 1)` and `stake(1)`. None is queued or on the keeper/team/signer exclusion list.
3. Settlement 4 runs. Each dust position now has positive `scoreOf` and satisfies the published eligibility requirements before drop 5.
4. Drop 5 runs normally. The keeper sees ten eligible wallets. For every allowed share from 1% to 10%, `winnersFor(10, shareBps)` returns ten.
5. A draw of ten distinct wallets from a ten-wallet field selects all of them. The honest publisher constructs the equal-share root, and the attacker claims nine leaves through `TicketMerkleDistributor.claim`.

**Result:** the attacker receives **90% of the drop** for a combined stake of `0.000000009 TICKET`, plus transaction costs. No forged proof, malicious owner, manipulated seed, or compromised sequencer is required. Choose a pot large enough that leaf rounding is immaterial.

**This is not confined to ten wallets.** With ten genuine wallets and 2,000 attacker dust wallets, the minimum 1% share produces 21 winners. At most ten can be genuine, so at least eleven are attacker wallets: **at least 52.38% of the pot**, regardless of the weighted selection order. At a 10% share the guaranteed attacker fraction is 191/201, or 95.02%. Funding and gas costs grow with the wallet count; the token stake required remains negligible.

**Evidence and qualification:** `jackpot_sybil` reproduces both cases and checks all 901 allowed integer share values for the 2,010-wallet case. This assumes N means **N distinct eligible wallet winners**, as the ledger describes. If the keeper instead performs independent draws with replacement and permits repeated wins by the same wallet, this particular counting proof does not apply. That implementation was not supplied and would need an explicit specification consistent with the published rules.

**Recommended correction:** make expected payout invariant to splitting the same stake across addresses. For example, draw stake-weighted tickets with replacement, permit repeat wins, and aggregate payouts by recipient; do not derive the total payout opportunities from an easily inflated wallet count. If ten distinct people are a product requirement, define and enforce that identity requirement. A token minimum alone raises the attack cost but does not solve the general wallet-splitting problem.

## F-02 — High — The market permits betting on a certain winner

**Locations:** `src/TicketMarket.sol:219`, `:316`, `:344` (particularly 346–352), `:287` (claim).

**Root cause.** `isOpen` asks whether the selected outcome intersects its estimated reachable band. It does not stop all betting when only one outcome remains possible. Thus when the entire band is above 101, **Up remains open**. The comment at lines 82–86 promises that nobody can bet on an already-decided outcome; the condition does not implement that promise.

**Concrete exploit path:**

1. Open a round at the normal midnight rebase. Earlier bettors place a combined 1,000 USDG on Flat and Down; assume no existing Up stake.
2. Genuine trading keeps the price at approximately four times target for the first seven hours. The attacker need not pay to produce this history; this is an opportunistic attack when it occurs.
3. At 07:00, before the eight-hour close, the attacker reads the cumulative history. Seven hours at 4× target already contributes 28 target-hours. With a normal next-day settlement, a nonnegative subsequent price cannot bring the average below the Up threshold. Even allowing the default 30-minute rebase window and 90-minute observation drift, the conservative retained contribution is `4 × 6.5 / 25.5 = 1.0196078 × target`, above 1.01.
4. The contract's own estimated band is `[258, 541]` cents. `isOpen(UP)` returns true because `hi > 101`; Flat and Down return false.
5. The attacker calls `bet(round, UP, 1_000e6)`. At the next normal rebase, anyone calls `settleRound`. The attacker then calls `claim`.

**Result:** the sole Up bettor receives 1,940 USDG after the 3% rake: **940 USDG profit** against a result already fixed by observable history. Other Up bettors would dilute that profit, not remove the defect. A missed next-day settlement changes the trailing window; this example expressly assumes the next scheduled rebase occurs, which the attacker can call permissionlessly if the protocol is live.

**Evidence:** `market_certain_winner` reproduces the reachable band, boolean gates, conservative mathematical floor, and payout.

**Recommended correction:** reject new bets on **every** leg once the settlement result is provably fixed. Use bounds derived from the actual oracle interval. An assumed ±50% future move is not a mathematical price bound. Explicitly handle settlement delay, observation drift and changed TWAP windows.

**Deployment relevance:** the ledger says the market is unwired this season. This becomes a release blocker if it is enabled.

## F-03 — High — Outstanding market funds become permanently unclaimable when a policy stops

**Locations:** `src/TicketMarket.sol:95`, `:180`, `:234` (239–241), `:287` (289); `src/TicketPolicy.sol:496`, `:533`, `:788`; `src/TicketStaking.sol:505` and `:606`.

**Root cause.** A market round can only settle from an immutable policy's stored `rebaseTwap[N]` and `rebaseTarget[N]`. The policy can permanently stop before N: it can be ejected, or its custody can unwind after the stall timeout. The market has no round cancellation, timeout refund, or migration path.

**Concrete failure path, with no malicious owner required:**

1. Policy settles epoch 12. Anyone calls `openRound`, creating a round for epoch 13; users deposit USDG with `bet`.
2. The next rebase fails to occur and the protocol remains unpaused and unsettled for seven days—for example, a prolonged oracle/keeper outage with no successful permissionless settlement.
3. Anyone calls `staking.endSeason()` after `stalled()` becomes true, then `policy.closeAfterStall()`.
4. The policy is permanently in Intermission. It will never populate `rebaseTwap[13]` or `rebaseTarget[13]`.
5. `market.settleRound(13)` always reverts at line 241. `claim(13)` always reverts because the round is not settled. There is no refund entry point. Installing a new Hub module does not change the market's immutable policy.

**Result:** **100% of the outstanding round's USDG remains trapped** in the market. The attacker or public caller who invokes the valid stall escape receives none of it. A module ejection while a round is open provides another route to the same terminal state.

**Evidence:** complete source entry-point review and `market_permanent_stall` state trace. The Python trace illustrates the terminal state; it does not execute the Solidity escape calls.

**Recommended correction:** add a pull-based void/refund state for rounds whose policy has terminated or whose settlement deadline has passed. Prevent settlement/void races and repeated refunds; return each bettor's contributed USDG without consuming another round's funds. Decide how long a paused round may hold deposits.

**Deployment relevance:** unwired this season; do not enable it without this exit path.

## F-04 — Medium — A green rebase can push spot below target

**Locations:** `src/TicketPolicy.sol:563`, `:609`, `:622` (625–649); `src/TicketBuffer.sol:399`, `:431`, `:463`; `value-flow-ledger.md:28`.

**Root cause.** Expansion derives `dev` from a trailing TWAP but applies that percentage to the **current** pool balance. A TWAP is not the current spot price. Ignoring integer dust and the expansion cap:

`spot_after = spot_before / (1 + dev) = spot_before × target / TWAP`.

This equals target only if `spot_before == TWAP`. When the expansion cap binds, the claimed equality can fail even when the two prices initially match. The comments repeatedly assert unconditional price-to-target behavior.

**Concrete call/state path:**

1. The historical TWAP is $1.20, target is $1.00, and recent selling has brought current spot to $1.00. For a simple reserve example, the pair now contains 69,000 TICKET and 69,000 USDG. Such historical/current-price disagreement does not require an oracle error.
2. A seller may deliberately create this current state before settlement; alternatively it can arise from normal trading. Any caller invokes `policy.rebase()` within the permitted window.
3. `_expand` mints 20% of the current TICKET pool balance: 13,800 TICKET. The Hub and policy sync the pair.
4. The pair now holds 82,800 TICKET against 69,000 USDG: spot is **$0.833333**, despite a green settlement.
5. An immediate `buffer.sell()` passes the TWAP regime check but fails the $0.98 spot floor. `buffer.buyAndBurn()` fails because the TWAP is still above the 95-cent buy threshold.

**Result:** holders experience a below-target spot reset, and neither Buffer trade can operate at that instant. A following red settlement is possible. This is a confirmed violation of the promised reset behavior, **not a demonstrated profitable oracle-manipulation trade**. The reproduction does not claim an attacker can obtain sustained price displacement for free.

**Evidence:** `pool_target_mismatch` reproduces the exact 9/6-decimal calculation and both regime failures.

**Recommended correction:** explicitly decide whether the rule promises a TWAP-proportional mint or a current-price reset. If it promises a reset, calculate the corrective pool amount from contemporaneous quote reserves, target and TICKET balance, with an independently considered manipulation bound. If spot is already below target, adding TICKET cannot put it back on target. Simply substituting a spot oracle everywhere would introduce a different attack surface.

## F-05 — Medium — The 42-day setting allows 43–44 settlements

**Locations:** `src/TicketPolicy.sol:548`, `:557`, `:561`, `:686`, `:700`; `src/TicketStaking.sol:505` and `:526`.

**Root cause.** The first settlement both increments the epoch and starts a full `seasonLength` wall-clock period. The boundary is checked **after** the settlement at the far end of that period. Additionally, `seasonStart` uses the actual first-call timestamp, while daily eligibility is snapped to the beginning of the window.

**Concrete path with 42 days configured:**

1. First rebase occurs at day 0, 00:00. This is epoch 1; `seasonStart` is day 0.
2. Normal daily rebases on days 1–41 produce epochs 2–42. The season is still Active after epoch 42 because only 41 days have elapsed.
3. Day 42 executes **epoch 43**, including its mint/contraction and staking settlement, and only then ends the season.

**One further settlement can be forced when the first call was late:**

1. The first rebase happened at day 0, 00:29, so the end timestamp is day 42, 00:29.
2. On day 42, any caller runs the rebase at 00:00, before that timestamp. Epoch 43 settles but cannot close the season.
3. A call at 00:29 cannot settle again: the once-per-period guard is consumed. The next rebase is day 43, giving **epoch 44** before unwind.

**Result:** an extra one or two mint/contraction events and a delayed fee-free unwind relative to a 42-night schedule. The early caller does not receive a special payout; they can force the extra exposure once the first timestamp has established this alignment. Regular queue withdrawals remain available under their normal conditions.

**Evidence:** `season_length` reproduces 43 and 44 successful settlements. This finding uses the pack's stated 42-night/six-week product expectation; if the intended requirement is a full 42 elapsed days after an already-counted first settlement, the behavior should instead be disclosed as 43–44 possible settlements.

**Recommended correction:** for an exact number of nights, close after a fixed number of settled epochs. For a fixed calendar duration, choose and publish the start/end anchors and specify whether the boundary settlement is included. Avoid mixing an actual-call season anchor with a snapped daily anchor.

## F-06 — Medium — A late market opener corrupts the reachability calculation

**Locations:** `src/TicketMarket.sol:183`, `:190` (192–195), `:320`, `:328`; `src/TicketPolicy.sol:427`.

**Root cause.** `openRound` records `openedAt = policy.lastRebaseTimestamp()` but records the cumulative **at the later openRound call**. `averageSince(openCumulative, openedAt)` then divides an integral covering a shorter period by a longer period. This systematically understates the average. The policy timestamp is also snapped to the window start, not necessarily the actual preceding settlement time.

**Concrete griefing path:**

1. Policy settles at 00:00; nobody has yet opened the market. Price stays at $1.00 throughout the example.
2. A caller opens the round at 02:00, which is permitted by `OPEN_GRACE`. The stored timestamp is 00:00, but the stored cumulative includes price through 02:00.
3. At 03:00, `reachableBand` asks for the average since that cumulative using the 00:00 timestamp. One price-hour is divided by three hours: the reported average is **$0.333333**, not $1.00.
4. The computed band is `[18, 47]` cents instead of `[56, 143]`. `bet` refuses Up and Flat while permitting Down.

**Result:** the round incorrectly excludes valid bets and hedges. Users following the available Down leg may lose all their stakes on a flat settlement; with no Flat winners, line 272 routes the entire pot to the Buffer. The late opener need not profit for this to be a valid market griefing path.

**Evidence:** `market_late_open` reproduces the mismatched intervals and both bands.

**Recommended correction:** pair every cumulative with the timestamp at which it was measured. If opening is anchored to the preceding rebase, store a suitable timestamp/cumulative snapshot in the policy and read that pair. Then align reachability with the actual oracle lookback rather than assuming a fixed 24-hour market interval matches every settlement read.

**Deployment relevance:** unwired this season.

## F-07 — Low — Incorrect bounds, stale comments and unresolved evidence citations

This is included because the brief explicitly requires checking citations and correctness claims. These are not additional critical or high findings.

### The stated supply-growth maximum is not an upper bound

**Locations:** `src/TicketHub.sol:227`, `:229`; implementing conditions at `:731`, `:749`, `:794`; the multiplicative-cap paragraphs in `value-flow-ledger.md`.

The stated maximum is 2.95× per settlement and 25.67× within 24 hours. That assumes the hostile module voluntarily contracts the full 5%. **Contraction is optional.** The actual maximum from minting alone is **3× per settlement and 27× across three such spends**, subject to the token supply ceiling and successful calls.

**Concrete path:** an already-installed hostile module opens a fresh window at t=0 with `hub.mint(pair, 0)`. It mints `2S` just before t=20h, `6S` at t=20h, and `18S` at t=40h. It makes no contraction call. These spends fall within 20 hours plus one second and leave supply at `27S`. All mint destinations can be the permanently allowed pair. This disproves the published bound; it does not establish a new direct wallet payout. `hub_supply_bound` reproduces the sequence.

### Other discrepancies and reference results

| Citation / claim | Source location | Audit result |
|---|---|---|
| Allocations “round down” and therefore can exceed accepted funds | `TicketGenesis.sol:334` | The post-finalization allocation rounds **up** via `dep - floor(excessShare)`. The mint and allocation headroom cover it; the older contradictory comment remains beside the corrected explanation at line 205 |
| Buffer sells must fill within 2% of the TWAP | `TicketBuffer.sol:142` | Current code uses a one-sided **reference-target spot floor**, not that TWAP fill band. The later code comment explains the changed rule |
| Every clip fills at or above 0.98× reference | `value-flow-ledger.md:456` | It is the **pre-trade mid-price** that has this floor. Fees and price impact lower the fill. The ledger's own earlier row 4 states this correctly |
| A queued exit's pinned fee keeps decaying to zero during a pause | `value-flow-ledger.md:417` | `TicketStaking.withdraw` reads `q.feeBps` at line 829. Request at 5%, remain queued for 14 days, withdraw during a pause: the fee is still 5%. `feeTenureDays` does not update the queued fee |
| The 30-minute observation ring spans only about 32 hours | `TicketPolicy.sol:838` | There are 192 slots, not the old 64. At minimum spacing, the oldest-to-newest span is 191×30m = 95.5h; ring replacement cadence is 96h |
| Config changes occur in the 48 hours before a boundary | `TicketPolicy.sol:865` | `configWindowOpen()` at line 887 returns true only in Intermission. The subsequent comment is correct, but the prior one remains |
| Normal policy season transitions reset and reuse staking | `TicketStaking.sol:62`; `TicketPolicy.sol:694` | The supplied policy calls `endSeason` and permanently unwinds. It never calls `startNewSeason`, although that staking function exists |
| The pool mint lands in nobody's pocket; outside LPs receive no prints | `TicketHub.sol:721`; ledger's accumulation discussion | Burning the genesis LP does not itself prohibit later LP minting in a standard v2 pair. External LPs can redeem their pro-rata share of a pool mint. This invalidates the categorical wording; a profitable borrowed-TICKET route would require a separate source of TICKET credit. No such live source was verified |
| Owner timelock protects the current launch | `TicketHub.sol:152`; `TicketBuffer.sol:118`; `TicketPolicy.sol:868`; ledger at line 174 | The deployment facts explicitly say **no owner timelock at launch**. Hub `SWAP_DELAY` and Prize Pot `RELEASE_DELAY` are real, separate contract delays; they are not a general ownership timelock |
| Each Strike `dropGons` records gons actually delivered | `TicketStrike.sol:183` versus `:186` | It records the entire pre-transfer gon balance but transfers only whole token units. The bound exceeds actual delivery by less than one TICKET base unit at that drop's index. `strike_budget_dust` reproduces this. Measure the distributor balance delta or use `amount × gpf` for an exact delivery bound |
| “Paid to the wei”; daily and dormant claims exactly identical | `TicketStaking.sol:74`, `:854` | Integer truncation in `dA`, segment integration and individual accrual leaves rounding residuals. A reward can be marked pending even when `dA` floors to zero. No material over-allocation was reproduced; the exactness claim is too strong |
| `test/Ticket.gons.t.sol` substantiates invariants | `Ticket.sol:37` | Not supplied; existence or assertions cannot be checked from this pack. The review did not treat the citation as evidence |
| `analysis/parimutuel-close-time.mjs` substantiates market reachability | `TicketMarket.sol:65` | Not supplied. The current code's F-02 and F-06 remain independently demonstrable |
| `DECISIONS.md` | `TicketPolicy.sol:620`, `:875` | Intentionally withheld by the brief. Unresolved as a citation here, **not alleged nonexistent**; arithmetic was checked independently |
| `analysis/make-bundle.mjs`, `foundry.toml`, `keeper/.testnet.env` | Brief / manifest | Not supplied. Bundle content was checked directly. Compiler settings, deployment wiring and runtime addresses beyond the two manifest entries remain unverified |
| Upstream Ampleforth commit `701eee27`; linked EIP/OZ historical references | `Ticket.sol:13`, helper-file comments | Referenced external content is not in the pack and could not be retrieved. Claims of verbatim upstream identity are **not verified** |

“Missing from the pack” is not a claim that a file never existed in the maintainer's repository. Historical review labels without their reports also cannot substantiate a security claim. The actual payout/mint/queue function names used in the ledger resolve to supplied code; the important semantic exceptions are listed above and in F-01 through F-06.

**Recommended correction:** remove superseded explanations, qualify deployment-dependent claims, correct the numerical bounds, and provide the cited executable evidence separately from intentionally withheld reasoning. Documentation corrections do not resolve F-01 through F-06.

## Requirements-dependent candidates — not counted as confirmed vulnerabilities

**Mature stake can bank age beyond the weight cap.** At `TicketStaking.sol:682`, top-ups blend uncapped origins. A 1,000-TICKET position aged 28 epochs can add another 1,000 TICKET and remain at full weight: its blended age is 14. If intended behavior is to blend *weight-bearing tenure capped at 14*, the correct combined weight would be 0.75, not 1.00. The supplied ledger says top-ups blend tenure down but does not define this distinction. `tenure_topup_candidate` demonstrates the difference. Clarify the rule and test that chosen rule before classifying it as an exploit.

**Cancellation counts time spent queued toward the later fee clock.** `cancelUnstake` at `TicketStaking.sol:783` resets the epoch origin but does not refresh or blend `feeAnchor`. A fully queued user can wait 14 days, cancel, request again at 0%, then wait the new queue. That avoids the original pinned 5% fee, but also takes at least roughly 16 days and forfeits active rewards while queued. This is not an immediate fee-free exit. Whether it violates “continuous staking” needs a product decision; no profitable short-cycle bypass was established.

**Prize Pot forced execution has no reference-price guarantee.** `TicketPrizePot.sell` at line 131 can be called after a large spot displacement. The tiny clip reduces manipulation incentives, but does not cap the absolute deviation of the fill from the pre-attack price. A simple one-pool sell/sell/buy calculation with 0.3% swap fees was not profitable for the attacker. No profitable drain is claimed. A broader multi-pool or external-credit attack would need executable integration evidence and a demonstrated funding source.

## Accounting, access and lifecycle observations

These are findings of the review process, not claims of formal proof:

- **Genesis split:** excess refunds floor; allocations use the complement and therefore ceil. `accepted + depositorCount` headroom covers their sum. Gon-based proportional claims spread contractions across unclaimed deposits. The seven-day `abort` path avoids depending forever on successful pair seeding. No theft or over-allocation was reproduced at the specified 9/6 decimals.
- **Staking accumulators:** for fixed positions with staggered starts, the two-accumulator segment formula matched a conservative integer approximation to an independent exact rational per-epoch weight calculation. No claimant exceeded that reference in 300 scenarios. This test did not fuzz every top-up, cancellation, queue merge or callback sequence.
- **Queue and custody:** queued gons are removed from earning aggregates; contractions still affect their fragment value. Repeated requests extend release conditions. Withdrawal and unwind debit state before transferring the supplied non-callback TICKET token. Full unwind combines principal, queue and rewards. The pause bypass of queue delays is explicit product behavior, not a new finding.
- **Token accounting:** mint/burn move gon supply and balances together; global contraction changes the index without assigning new gon balances. The supplied transfer paths have no hooks. The zero-address permit behavior cannot spend a zero-address TICKET balance under the specified deployment. No material unauthorized transfer or direct double-payment path was established.
- **Oracle and pair:** the cumulative-difference calculation handles intended wrapping and decimal normalization. The ring cannot be flushed below the maximum 72-hour configured lookback using minimum-spaced checkpoints. A same-pair flash-swap callback cannot be assumed to support rebase: the rebase requires pair `sync`, so pair locking must be considered. No flash-loan PoC was asserted without this check.
- **Distributors:** claim bitmaps and gon-denominated root budgets constrain repeated payment and cross-root overspending. Correctness of the first published root remains trusted as disclosed. The sub-base-unit Strike delivery discrepancy is recorded in F-07.
- **Season termination:** normal boundary processing settles staking before unwind and sweeps custody stray before the Buffer surplus. Recovery paths exist for the Strike carry and Hub surplus. An ejected policy cannot be reinstalled under `everInstalled`. The market has no corresponding recovery, which is F-03.
- **Administrative powers:** the owner can publish a malicious first jackpot root and can install hostile future game logic under the stated swap conditions. Those disclosed capabilities are not relabeled as new exploits. Actual `Ticket.policyLocked`, destination approvals, distributor token/index mode, policy pointers, pair/factory identity and multisig ownership must be checked against the final deployment; this pack is insufficient to attest them.

## Required follow-up for a launch decision

1. Resolve **F-01** in the drawing specification and keeper, then replay thin-field and wallet-splitting examples against the real implementation.
2. Resolve or explicitly change the product promises underlying **F-04** and **F-05**. Test spot/TWAP disagreement, the expansion cap, first-rebase timing and the final settlement together.
3. Keep the market unwired until **F-02, F-03 and F-06** are fixed and exercised through the real policy lifecycle.
4. Run the corrected code with solc 0.8.28, the exact pinned OpenZeppelin dependency and the actual pair/quote implementations. Execute the attack sequences and recovery paths on a local EVM or fork, and verify the final deployed bytecode and irreversible wiring.

The source pack was not modified. The audit report and independent reproductions are the deliverables; no transaction was sent to a deployed contract.
