# Sigma vault implementation and self-audit

## Verdict

The requested hook, ShareToken, TypeScript keeper, unit/integration tests, Medusa harness, CREATE2 script, threat model, and Foundry configuration are delivered. Local unit tests and bounded fuzz campaigns pass. This is an implementation with explicitly qualified requirements, not a claim that every literal constraint is satisfied or an independently audited production vault.

The core is immutable and uses only PoolManager ERC-6909 claims for vault funding and redemption. Shares proportionally represent deployed liquidity plus realized and unrealized fees and accounted idle assets. Rebalances remove the old position and reinvest the available two-sided assets into the new position without a swap. Solidity dependency sources and dependency-free keeper runtime JavaScript are ordinary files. Verification binaries are excluded from submission to meet the upload limit; offline checks require host-provided tools. Provenance and hashes: [tools/provenance.json](../tools/provenance.json).

## Observed local evidence

Run `./tools/check.sh` and `./tools/fuzz.sh` from the repository root. The first script also regenerates the dependency-free keeper JavaScript from TypeScript. Bash, Python 3, Node 18+, forge 1.8.5, solc 0.8.26, Medusa 1.5.1, and TypeScript 5.9.3 are host verification prerequisites. Solidity libraries and the compiled keeper runtime are vendored. Tool binaries are not submitted; offline verification without host tools is unresolved.

| Check | Observed result | Evidence |
| --- | --- | --- |
| Solidity unit/integration suite | 13 passed, 0 failed | [checks.log](evidence/checks.log), `test/SigmaRangeHook.t.sol` |
| ABI-valid afterSwap fuzz | 100,000 inputs, no failures | `test/SigmaRangeHook.t.sol:169`, checks log |
| Deposit/partial-withdraw/deposit/full-withdraw fuzz | 100,000 sequences, no failures; at most four units loss per currency in this target | `test/SigmaRangeHook.t.sol:173`, checks log |
| Callback gas | 4,543 gas, cold callback including caller ABI/call overhead; threshold is 5,000 | `test/SigmaRangeHook.t.sol:161`, checks log |
| Real-swap callback trace | 1,146 gas in callback body in the recorded integration trace | [swap-trace.log](evidence/swap-trace.log) |
| Contract deployability sizes | Hook runtime 11,961 bytes; ShareToken runtime 1,814 bytes, below EIP-170 limit | [build-sizes.log](evidence/build-sizes.log) |
| Keeper compile/tests | Strict TypeScript compilation and seven checked behaviors pass | `test/SigmaKeeper.test.cjs`, checks log |
| Medusa | Configured transaction limit 100,000, two workers, depth 32; all six properties pass | [medusa.log](evidence/medusa.log), `test/fuzz/medusa.json`, `test/fuzz/SigmaMedusa.sol` |

The final Medusa log records 107,032 calls at its last progress update and 21 tests passed, zero failed. It emits seven source-cache warnings for repository-relative paths; compilation and property execution succeed, but source-line coverage reports are not used as evidence of coverage.

Medusa “calls” and Foundry “runs” are different measures: the Medusa limit counts generated transactions, not 100,000 independent 32-call sequences. Worker batching can overshoot the configured call limit. Its six properties cover reserve backing, supply consistency, valid bounds, callback success, no stranded accounted assets after closure, and constant-price conservation with a rounding budget. Ordinary reverted operations are not classified as invariant failures. Arithmetic-panic detection outside explicit properties is disabled in the Medusa assertion configuration, so this result is not a zero-revert claim.

Foundry isolation was disabled in `foundry.toml` for callback-only measurement: separate-transaction isolation added transaction intrinsic gas to direct hook calls. Earlier runs failed the incorrectly scoped gas measurement; the final log records the corrected benchmark. No GitHub CI workflow was created because `.github/` is prohibited. `tools/check.sh` is the delivered CI entry point; actual external CI execution remains unverified.

## Constraint-by-constraint review

Line references identify delivered files; source hashes are in [source-hashes.json](evidence/source-hashes.json). “Implemented” is a source inspection conclusion supported by the cited tests where applicable, not a proof of all behaviors.

| Requirement | Finding and implementation evidence |
| --- | --- |
| BaseHook | Implemented as local `src/BaseHook.sol:18`, implementing upstream IHooks with reverting unsupported callbacks. This is a local minimal base, not a vendored historical periphery BaseHook. |
| Single pool bound by afterInitialize | Implemented at `src/SigmaRangeHook.sol:53`; manager-only, once-only, verifies the hook address and spacing. First eligible pool wins; constructor does not commit to a predetermined PoolId. |
| ERC-6909 only, no underlying transfers | Implemented at `src/SigmaRangeHook.sol:148` and `:158`. Principal debts burn claims; credits mint claims; reserve contributions and withdrawals transfer claims. Raw ERC-20 transfers exist only in test funding fixtures. |
| ERC-20 proportional shares | `src/ShareToken.sol:5` implements supply, balances, allowances, transfers and events. Mint/burn are vault-only. `src/SigmaRangeHook.sol:105` prices deposits against existing liquidity/share supply and charges proportional idle reserves; `:117` withdraws proportional assets plus removed principal. |
| Requested state | `src/SigmaRangeHook.sol:29` through `:36`; cooldown is a fixed six-hour constant, not configurable. Reserves include idle principal as well as fees. |
| Public deposit/withdraw/rebalance | `src/SigmaRangeHook.sol:74`, `:81`, `:86`; deposit accepts liquidity units and slippage limits; withdraw accepts shares and minimum claim amounts. |
| Keeper-only rebalance | `src/SigmaRangeHook.sol:87`. |
| Owner keeper replacement with 48h timelock | Schedule at `src/SigmaRangeHook.sol:63`, activate at `:67`. Repeated scheduling resets the delay; zero keeper forbidden. |
| Pause/unpause | Owner-only at `src/SigmaRangeHook.sol:71`; withdraw intentionally remains enabled during pause. |
| Remove old range and add new | `src/SigmaRangeHook.sol:132` through `:140`; insufficient balanced assets cause atomic rollback. |
| Ordered bounds and absolute tick limits | Constructor at `src/SigmaRangeHook.sol:46`, rebalance at `:90`. |
| Absolute offset <2,000 ticks | `src/SigmaRangeHook.sol:92`; interpreted as each boundary's distance from current tick, strictly positive and below 2,000. New range must straddle spot. |
| Tick spacing | Initial binding at `src/SigmaRangeHook.sol:55`, rebalance at `:91`. |
| Cooldown elapsed | `src/SigmaRangeHook.sol:88`; initialized timestamp starts the initial cooldown. |
| afterSwap O(1) and no external calls | `src/SigmaRangeHook.sol:61` returns selector and zero delta; no fees or telemetry stored here. |
| All state-changing PoolManager operations unlocked | `src/SigmaRangeHook.sol:95`, `:99`, `:144`, `:148`; no direct modifyLiquidity outside the callback. Read-only slot0 is outside unlock at `:89`. |
| Zero net deltas before return | `_settle` at `src/SigmaRangeHook.sol:148` resolves each currency using mint/burn. Real PoolManager would revert unlock if a nonzero delta remains; integration tests pass. |
| ReentrancyGuard | Local boolean guard at `src/SigmaRangeHook.sol:43`, applied to all three user/keeper operations; adversarial callback test at `test/SigmaRangeHook.t.sol:95`. |
| Callback authorization/replay protection | `src/SigmaRangeHook.sol:100` checks immutable manager, entry guard and request hash; consumes hash at `:101`. |
| Immutable, no proxy | Constructor creates ShareToken and stores immutable manager/owner; no upgrade or delegate execution function. Source inspection of `src/SigmaRangeHook.sol:44`, `src/BaseHook.sol:19`, `src/ShareToken.sol:9`. |
| AFTER_INITIALIZE and AFTER_SWAP only | `src/SigmaRangeHook.sol:50`; constructor validates address flags at `:48`. |
| HookMiner CREATE2 | `script/DeployHook.s.sol:12`; predicts standard CREATE2 deployer address and asserts deployed address. Integration fixture independently mines and deploys flags. Broadcast deployment was not executed. |
| Poll slot0 every 60s | `src/SigmaKeeper.ts:60`; non-overlapping loop, delay adjusted for poll duration. `src/run-keeper.cjs:19` implements StateView RPC adapter. |
| Thirty-day hourly log-return window | `src/SigmaKeeper.ts:37` retains 721 hourly samples, excludes gaps; `:26` computes tick differences times log(1.0001). |
| Sample standard deviation | `src/SigmaKeeper.ts:29` and `:30`, denominator n−1, minimum two returns. |
| tickOffset formula | `src/SigmaKeeper.ts:43`, exact requested round(3 × sigma × 10000); usable bounds rounded outward. |
| Rebalance triggers | `src/SigmaKeeper.ts:50` through `:57`: exit, maximum boundary displacement exceeding threshold, or elapsed cooldown and >20% width change. Every trigger obeys on-chain cooldown. Threshold default 100 ticks. |
| Range/supply fuzz invariants | `test/fuzz/SigmaMedusa.sol:40` and `:41`; Foundry sequences also check both. |
| Reentrancy/malicious-token/nested-unlock targets | `test/fuzz/ReentrancyManager.sol:14`, `test/fuzz/SigmaMedusa.sol:29` through `:31`, unit fixture callback. |

## Explicit deviations and unresolved interpretations

1. **Unconditional “afterSwap never reverts” conflicts with noDelegateCall.** `src/SigmaRangeHook.sol:62` applies the delegate-call guard; `test/SigmaRangeHook.t.sol:102` confirms delegate calls fail. Normal ABI-valid direct calls have no failure-producing arithmetic or state updates and pass 100,000 fuzz inputs. Malformed ABI, gas exhaustion and delegate execution are outside that guarantee.
2. **No telemetry writes in afterSwap.** `src/SigmaRangeHook.sol:61` is a no-op callback. It satisfies a reading of “storage writes only” as forbidding external interactions, but does not satisfy an interpretation requiring a storage write. PoolManager collects fees when modifying liquidity, at `src/SigmaRangeHook.sol:103` and `:144`.
3. **Not every external getter has noDelegateCall.** Public autogenerated getters at `src/SigmaRangeHook.sol:21`, `src/ShareToken.sol:6`, `src/BaseHook.sol:19`, and pure permission query `src/SigmaRangeHook.sol:50` are unguarded. Every explicit mutating entry point is guarded. Read-only queries under delegatecall can describe the caller's storage and must not be trusted as vault state.
4. **Read-only manager interactions outside unlock.** `src/SigmaRangeHook.sol:89` and keeper state reads do not enter an unlock. State-changing manager interactions do. A literal “all interactions”, including views, is not met.
5. **Uses mint/burn rather than take/burn.** `src/SigmaRangeHook.sol:151` mints positive deltas, `:155` burns negatives. Calling take would transfer the underlying currency and violate ERC-6909-only vault interactions. This resolves the contradiction in favor of claim accounting.
6. **Full literal CEI is not met before fee collection.** `src/SigmaRangeHook.sol:103` calls the trusted manager to realize fees before economic share effects. Request authorization is consumed first; the guard protects all operations and reserve effects precede mint/burn. A strict rule disallowing every interaction before all effects is unmet.
7. **Raw token balance cannot cover the full invested share NAV.** `src/SigmaRangeHook.sol:111` invests principal; it is a position, not liquid claim balance. The reserve-backing property at `test/fuzz/SigmaMedusa.sol:42` is tested. Full share coverage must include position principal and fees; no general arbitrary-price NAV invariant is delivered.
8. **Literal zero value destruction across every sequence is not established and is false with rounding/market loss.** The constant-price target at `test/fuzz/SigmaMedusa.sol:33` allows four currency units per operation; Foundry sequence loss bound is four units for its fixed sequence. Rebalance invests conservatively (`src/SigmaRangeHook.sol:138`). Market loss, impermanent loss, bad keeper timing and arbitrarily accumulated rounding are not prevented.
9. **Keeper reads tick-derived price and StateView, not a direct PoolManager getSlot0 ABI call.** `src/SigmaKeeper.ts:26`, `src/run-keeper.cjs:19`. Upstream getSlot0 is a Solidity StateLibrary helper over extsload, exposed externally by StateView. Tick prices approximate exact sqrtPrice-derived log returns. See primary sources below.
10. **Volatility out of range is skipped.** `src/SigmaKeeper.ts:47` declines a band whose offset after tick rounding exceeds the hook limit; it does not clip sigma. At zero volatility it uses a minimum nonempty band (`:45`). Gaps and early warmup are described in the threat model.
11. **No independent audit, live-network deployment, or RPC/signing integration test.** The adapter and CREATE2 broadcast script are delivered but not tested against a live chain. External CI has not run. Medusa campaigns are bounded and use a single pooled depositor, constant price for conservation, and synthetic tokens; they do not prove all-user arbitrary-market financial safety. Foundry separately tests transferable shares and a real manager swap.

## Technical sources and confidence

The supplied source pins and hashes support reproducibility; third-party documentation supports protocol semantics rather than certifying this vault. Verified on 2026-10-06:

- Positive delta minting and negative delta burning use native claim accounting. [Uniswap ERC-6909 guide](https://developers.uniswap.org/docs/protocols/v4/guides/erc-6909), [unlock/delta guide](https://developers.uniswap.org/docs/protocols/v4/guides/unlock-callback-and-deltas).
- `StateLibrary.getSlot0` reads manager storage via extsload; StateView exposes that helper as an external function. [Pinned StateLibrary](https://github.com/Uniswap/v4-core/blob/46c6834/src/libraries/StateLibrary.sol), [pinned StateView](https://github.com/Uniswap/v4-periphery/blob/9969eec/src/lens/StateView.sol).
- Hook callback flags are encoded in the deployed address. [Uniswap hook concepts](https://developers.uniswap.org/docs/protocols/v4/concepts/hooks), [upstream Hooks](https://github.com/Uniswap/v4-core/blob/46c6834/src/libraries/Hooks.sol).
- Medusa supports mutational coverage-guided property and assertion testing; passing a bounded campaign is not a proof. [Medusa upstream](https://github.com/crytic/medusa/tree/v1.5.1).

Facts above are source-inspected or locally measured. Interpretations of “offset”, “delta band”, and “storage writes only” are identified explicitly. Economic guarantees, live adapter behavior, external CI and independent review remain unverified. No configuration or secrets were disclosed, no Git staging/commit was performed, and required named outputs are left as ordinary untracked files for upload.

## Bundle-size repair

The prior upload-size check reported 75,258,552 compressed source bytes against an 8,388,608-byte limit. The repair preserves all vault/keeper implementation files, tests, deployment script, Solidity dependency sources, licenses, and dependency-free compiled keeper runtime. It excludes host verification binaries (Forge, solc, Medusa), the TypeScript compiler installation, generated coverage/build/cache output, third-party audit PDFs/documentation, and prebuilt third-party test JavaScript bundles. Generated files and tools used for this local rerun are in `test/scratch/`, which is deleted before submission. The retained library source imports compile successfully.

`foundry.toml:3` routes build/cache output to scratch. `tools/check.sh:5` accepts host tool paths; `tools/fuzz.sh:5` resolves the real compiler before installing its local adapter and archives generated coverage to scratch. `tools/bin/solc-medusa:7` uses that host compiler. The submitted keeper runtime needs only Node and its built-in modules; rebuilding TypeScript requires a host compiler.

**Explicit packaging limitation:** the delivered archive is not a self-contained verification toolchain. Offline Solidity compilation and fuzzing require tools already installed on the checking host. The original binary/tool hashes in `tools/provenance.json` identify the tools used for local evidence, not files bundled in this repaired submission. This qualifies the earlier no-network reproducibility claim and the instruction to deliver installed dependencies; runtime dependencies and Solidity library source remain included. No independent upload verifier has rerun yet. Local archive measurements and final rerun results are recorded in [bundle-repair.json](evidence/bundle-repair.json).
