# Sigma vault implementation and self-audit

## Verdict and evidence

A useful claims-only vault prototype and TypeScript keeper are delivered, with all
requested source paths, tests, a CREATE2 factory, and a threat model. **Full acceptance
is not established.** Author-produced checks are not independent audit evidence.
The local suite reported **20 tests passed, zero failed**. Each ShareToken fuzz test
and vault round-trip fuzz test ran 100,000 inputs; the Medusa actor repeats the vault
round-trip test. These are input counts, not 100,000 arbitrary stateful sequences.
The final clean offline rerun is documented in `artifacts/local-tests.txt`.

Reproduce with `script/check.sh`; Foundry and Node 24 must be available. Solidity
sources and a Linux x86-64 Solidity 0.8.26 compiler are vendored as ordinary files.
No runtime npm package is needed. `lib/SOURCES.txt` records retrieval heads and compiler
checksum. Files remain untracked; no Git staging, commits, or protected paths were modified.

## Attributable technical basis

Uniswap explains claim accounting in [ERC-6909 concepts](https://developers.uniswap.org/docs/protocols/v4/concepts/erc-6909).
The vault burns claims to settle debts and mints claims for credits, following
[PoolManager](https://github.com/Uniswap/v4-core/blob/main/src/PoolManager.sol).
Using `take` would transfer underlying currency, contrary to the claims-only constraint.
Thus “take/burn” is interpreted as zero delta settlement with burn/mint.

PoolManager does not have a public getSlot0 ABI method. Solidity uses
[StateLibrary](https://github.com/Uniswap/v4-core/blob/main/src/libraries/StateLibrary.sol);
TypeScript decodes the same `extsload` slot. Hook address bits follow
[Hooks.sol](https://github.com/Uniswap/v4-core/blob/main/src/libraries/Hooks.sol).
These upstream pages support technical design choices; local files and logs support
claims about this implementation. They do not independently certify this code.

## Every constraint: implementation or deviation

| Requirement | Local evidence and status |
|---|---|
| BaseHook, bound single pool | `src/BaseHook.sol:8`, `src/SigmaRangeHook.sol:49`. Minimal local BaseHook; single-use binding to a currency/fee/spacing fingerprint and this hook address. Fingerprint excludes hook address to avoid a CREATE2 constructor-address circular dependency. |
| ERC-6909 only | `src/SigmaRangeHook.sol:96`, `:126`, `:131`. No underlying token calls. Tests create claims externally using token transfers. Users authorize hook as PoolManager operator. |
| ERC-20 proportional shares | `src/ShareToken.sol:4`; `src/SigmaRangeHook.sol:87`, `:89`, `:92`, `:104`. Deposits buy proportional position liquidity and fee reserves; share mint/burn is atomic. |
| Required state and 6h cooldown | `src/SigmaRangeHook.sol:30` through `:37`. Reserves also hold idle principal after rebalance. Cooldown is fixed, not configurable. |
| Public deposit/withdraw/rebalance | `src/SigmaRangeHook.sol:64`, `:68`, `:72`. Deposit uses exact liquidity, max claims and minimum shares; withdrawal uses shares and minimum outputs. |
| onlyKeeper rebalance | `src/SigmaRangeHook.sol:73`. Initial keeper established at construction. |
| owner setKeeper, 48h delay | `src/SigmaRangeHook.sol:56`. First call schedules; repeat same address after 48h activates. Different proposals restart delay. |
| pause/unpause | `src/SigmaRangeHook.sol:61`. Withdrawals remain available while paused. |
| Remove old / add new | `src/SigmaRangeHook.sol:112` through `:118`. Reuses recovered principal plus reserves and retains leftovers. Insufficient two-sided assets can produce zero new liquidity; withdrawals still redeem reserves. |
| Rebalance bounds | `src/SigmaRangeHook.sol:74` through `:77`. Order, global tick bounds, tick spacing, cooldown, and strict offsets below 2000. Offset is interpreted as distance of each endpoint from current tick. |
| O(1) afterSwap, writes only | `src/SigmaRangeHook.sol:55`. No-op: no storage reads/writes, external calls, observations or fee collection. “Writes only” is interpreted as forbidding other interactions, not requiring a write. |
| afterSwap never reverts | **Literal deviation**, `src/SigmaRangeHook.sol:55`: noDelegateCall rejects delegate calls; ABI decoder rejects malformed input. Valid ordinary callback calls have no application-level rejection. |
| All interactions through unlock | All state-changing manager operations use `src/SigmaRangeHook.sol:80` / `:81`. **Literal deviation**, `:75`: pre-unlock slot0 read. View reads are exempted in this implementation. |
| Net deltas zero | `src/SigmaRangeHook.sol:96`, `:127`, `:128`, `:131` use burn/mint. Real-manager integration tests enforce PoolManager's final delta settlement. No `take`, as explained above. |
| ReentrancyGuard | `src/SigmaRangeHook.sol:40`: local boolean guard on deposit/withdraw/rebalance, rather than an imported class named ReentrancyGuard. |
| Callback checks-effects-interactions | Capability consumed at `src/SigmaRangeHook.sol:82`; ownership updates precede position add/remove at `:92`, `:104`, `:112`. **Qualified**, `:84`: fee crystallization interacts before final ownership effects. Returned manager deltas determine reserve updates. Immutable trusted manager and spanning guard are assumptions. |
| noDelegateCall all external entries | Explicit mutating vault/share entry points are guarded. **Literal deviation**, `src/SigmaRangeHook.sol:48`: pure permissions and autogenerated public getters are unguarded. `script/DeployHook.s.sol:10` factory is also unguarded. |
| Immutable, no proxy | `src/BaseHook.sol:9`, `src/SigmaRangeHook.sol:42`; no upgrade entry point. Manager/owner/share references immutable; keeper intentionally mutable. |
| Exactly two permissions | `src/SigmaRangeHook.sol:48`; constructor validates address bits at `:46`. |
| HookMiner CREATE2 | `script/DeployHook.s.sol:12`. Factory-relative salt mining and predicted-address check. Mining within factory run may be expensive; offchain mining deployment remains an operational improvement. |
| Poll every 60 seconds | `src/SigmaKeeper.ts:36`, `:39`. Sleeps 60 seconds after completion; request duration adds polling drift. |
| 30-day hourly log returns | `src/SigmaKeeper.ts:21` through `:23`: 721 hourly prices for up to 720 returns. First observation each hour; skips missing hours rather than inventing returns. RPC uses sqrtPriceX96; test transports can approximate with tick. |
| Sample standard deviation | `src/SigmaKeeper.ts:11` through `:17`, denominator n−1. Insufficient observations suppress rebalances. |
| tickOffset round(3σ10000) | `src/SigmaKeeper.ts:25`; expands resulting endpoints to tick spacing. Oversized ranges skipped, not silently capped. |
| Trigger conditions | `src/SigmaKeeper.ts:30` through `:34`. Exit, maximum endpoint displacement above configurable threshold (default 100), or width change above 20%. Cooldown gates every trigger because contract mandates it. Delta-band meaning is an explicit interpretation. |
| Operational keeper | `src/SigmaKeeper.ts:44`: RPC adapter pins reads to one block and encodes rebalance. **Gap:** receipt-confirming signer injected; durable sample storage, chain/pool configuration checks and nonce management are not supplied. Restart loses history unless caller persists samples. |

## Invariants and limits of inference

Supply consistency follows atomic share mint/burn and is tested; tick order is checked
at construction/rebalance and exposed as a Medusa property. These are local evidence
and source reasoning, not formal proofs.

**Literal hook token balance ≥ total user value is not true while liquidity is deployed.**
The position holds principal and uncollected fees separately from hook claim balances.
`test/fuzz/SigmaInvariants.sol` checks reserve backing only. A complete NAV property
must include position inventory and accrued fees currency by currency.

**Literal no value destruction is not established.** V4 adds round up and removes
round down. Round-trip tests permit one claim of loss per currency. Arbitrary price
changes, LP inventory shifts and economic losses cannot be ruled out by share accounting.
Rebalance surplus stays in claims; no forced swaps dispose of inventory.

afterSwap gas trace reports **1,014 gas inside the callback**. The test asserts a warmed
call including caller overhead below 5,000. Calldata construction and transaction
intrinsic costs are excluded. An earlier cold full-call assertion exceeded 5,000;
no claim is made that every caller's total overhead meets the limit. Foundry sets
`isolate=false` so internal calls are measured within a transaction. Check.sh provides
a CI-runnable benchmark; no hosted CI workflow was created because .github is forbidden.

## Verification and unanswered questions

Saved evidence: `artifacts/local-tests.txt`, `artifacts/gas-trace.txt`,
`artifacts/keeper-tests.txt`. Tests cover real-manager initialization, claim-funded
round trip, rebalance, pause, keeper delay, unexpected callbacks, transfer-rejecting
tokens, malicious manager recursive deposit/missing callback, supply fuzz and vault
round-trip fuzz. Keeper checks statistics, trigger, cooldown and missing hourly samples.
There is no TypeScript type-checking campaign or live RPC/signing integration test.

**Medusa 100k campaign not executed.** `test/fuzz/medusa.json` is proposed configuration,
not a verified campaign. Medusa and crytic-compile are not installed/vendored and thus
cannot be assumed available offline. Medusa testLimit counts transactions according to
its [configuration documentation](https://secure-contracts.com/program-analysis/medusa/docs/src/project_configuration/overview.html).

The rejected callback/unlock tests are not a complete nested-unlock exploit simulation.
Reentrancy test checks rollback for a malicious manager returning without callback;
it does not exhaust all reentry branches. Transfer-rejecting token tests demonstrate
that vault claims operations do not invoke underlying transfers, not that upstream
malicious token settlement is safe. Stateful swaps/fees/multiuser dilution, arbitrary
rebalance sequences, full NAV conservation, keeper restart/signing and independent
review remain unanswered. See `docs/threat-model.md` for trust assumptions and MEV risk.
No production deployment, independent certification, or full-acceptance claim is made.

Clean offline verification: `forge clean` followed by `forge test --offline --fuzz-runs 100000`
reported **20 passed, zero failed**. Compiler and source resolution succeeded with no
network dependency. The report was restored after clean removed its output directory.
