diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..37a469ff1 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +# Makefile for hook-bazaar-monorepo + +# Implemented test files (non-placeholder tests) +IMPLEMENTED_TESTS := \ + test/protocol-pkg/ProtocolFactoryFacet.t.sol \ + test/protocol-pkg/ProtocolAdminRegistry.t.sol \ + test/protocol-pkg/ProtocolAdminClient.t.sol \ + test/protocol-pkg/ProtocolAdminPanel.t.sol \ + test/protocol-pkg/ProtocolAdminManager.t.sol + +# Fork tests (require ALCHEMY_API_KEY env var) +FORK_TESTS := \ + test/protocol-pkg/ProtocolAdminClient.fork.t.sol \ + test/master-hook-pkg/MasterHook.fork.t.sol + +# Placeholder test files (not yet implemented) +# test/master-hook-pkg/MasterHook.t.sol +# test/hook-pkg/CoFHEHook.t.sol +# test/hook-pkg/HookStateLens.t.sol +# test/hook-pkg/HaaSFacet.t.sol +# test/hook-pkg/CoFHEHookMasterHook.t.sol +# test/hooks-operator-avs/HookAttestationTaskManager.t.sol +# test/hooks-operator-avs/AttestationRegistry.t.sol +# test/hooks-operator-avs/HookAttestationServiceManager.t.sol +# test/hooks-operator-avs/HaaSVendorManagement.t.sol +# test/hooks-operator-avs/ClearingHouseEscrow.t.sol +# test/hooks-operator-avs/HookStateSampler.t.sol + +.PHONY: test test-implemented test-fork test-all build clean + +# Run only implemented (non-placeholder) unit tests +test-implemented: + @echo "Running implemented unit tests..." + forge test --match-path "contracts/test/protocol-pkg/ProtocolFactoryFacet.t.sol" -vvv + forge test --match-path "contracts/test/protocol-pkg/ProtocolAdminRegistry.t.sol" -vvv + forge test --match-path "contracts/test/protocol-pkg/ProtocolAdminClient.t.sol" -vvv + forge test --match-path "contracts/test/protocol-pkg/ProtocolAdminPanel.t.sol" -vvv + forge test --match-path "contracts/test/protocol-pkg/ProtocolAdminManager.t.sol" -vvv + +# Run fork tests (requires ALCHEMY_API_KEY) +test-fork: + @echo "Running fork tests (requires ALCHEMY_API_KEY)..." + forge test --match-path "contracts/test/protocol-pkg/ProtocolAdminClient.fork.t.sol" -vvv + forge test --match-path "contracts/test/master-hook-pkg/MasterHook.fork.t.sol" -vvv + +# Run all implemented tests (unit + fork) +test-all-implemented: test-implemented test-fork + +# Default test target runs implemented unit tests only +test: test-implemented + +# Run all tests including placeholders (will show skipped/empty tests) +test-all: + @echo "Running all tests..." + forge test -vvv + +# Build contracts +build: + forge build + +# Clean build artifacts +clean: + forge clean diff --git a/README.md b/README.md index 6b34d7839..b5198b799 100644 --- a/README.md +++ b/README.md @@ -168,10 +168,32 @@ forge build ### Test ```bash +# Run implemented tests only (excludes placeholder test files) +make test-implemented + +# Run fork tests (requires ALCHEMY_API_KEY env var) +make test-fork + +# Run all tests including placeholders forge test +``` + +> **Note**: Some test files in `contracts/test/` are placeholders for future implementation (e.g., `hook-pkg/`, `hooks-operator-avs/`). Use `make test-implemented` for actual test coverage. + +```bash cd operator && npm test ``` +### Attestation Simulation + +```bash +# Terminal 1 +anvil + +# Terminal 2 +cd operator && npx tsx integration/runSimulation.ts +``` + ### Deploy ```bash diff --git a/demo/presentation.aux b/demo/presentation.aux new file mode 100644 index 000000000..56776afab --- /dev/null +++ b/demo/presentation.aux @@ -0,0 +1,27 @@ +\relax +\providecommand\hyper@newdestlabel[2]{} +\providecommand*\HyPL@Entry[1]{} +\HyPL@Entry{0<
>} +\@writefile{nav}{\headcommand {\slideentry {0}{0}{1}{1/1}{}{0}}} +\@writefile{nav}{\headcommand {\beamer@framepages {1}{1}}} +\HyPL@Entry{1<>} +\@writefile{nav}{\headcommand {\slideentry {0}{0}{2}{2/2}{}{0}}} +\@writefile{nav}{\headcommand {\beamer@framepages {2}{2}}} +\HyPL@Entry{2<>} +\@writefile{nav}{\headcommand {\slideentry {0}{0}{3}{3/3}{}{0}}} +\@writefile{nav}{\headcommand {\beamer@framepages {3}{3}}} +\HyPL@Entry{3<>} +\@writefile{nav}{\headcommand {\slideentry {0}{0}{4}{4/4}{}{0}}} +\@writefile{nav}{\headcommand {\beamer@framepages {4}{4}}} +\HyPL@Entry{4<>} +\@writefile{nav}{\headcommand {\slideentry {0}{0}{5}{5/5}{}{0}}} +\@writefile{nav}{\headcommand {\beamer@framepages {5}{5}}} +\HyPL@Entry{5<>} +\@writefile{nav}{\headcommand {\slideentry {0}{0}{6}{6/6}{}{0}}} +\@writefile{nav}{\headcommand {\beamer@framepages {6}{6}}} +\@writefile{nav}{\headcommand {\beamer@partpages {1}{6}}} +\@writefile{nav}{\headcommand {\beamer@subsectionpages {1}{6}}} +\@writefile{nav}{\headcommand {\beamer@sectionpages {1}{6}}} +\@writefile{nav}{\headcommand {\beamer@documentpages {6}}} +\@writefile{nav}{\headcommand {\gdef \inserttotalframenumber {6}}} +\gdef \@abspage@last{6} diff --git a/demo/presentation.nav b/demo/presentation.nav new file mode 100644 index 000000000..2094a0740 --- /dev/null +++ b/demo/presentation.nav @@ -0,0 +1,17 @@ +\headcommand {\slideentry {0}{0}{1}{1/1}{}{0}} +\headcommand {\beamer@framepages {1}{1}} +\headcommand {\slideentry {0}{0}{2}{2/2}{}{0}} +\headcommand {\beamer@framepages {2}{2}} +\headcommand {\slideentry {0}{0}{3}{3/3}{}{0}} +\headcommand {\beamer@framepages {3}{3}} +\headcommand {\slideentry {0}{0}{4}{4/4}{}{0}} +\headcommand {\beamer@framepages {4}{4}} +\headcommand {\slideentry {0}{0}{5}{5/5}{}{0}} +\headcommand {\beamer@framepages {5}{5}} +\headcommand {\slideentry {0}{0}{6}{6/6}{}{0}} +\headcommand {\beamer@framepages {6}{6}} +\headcommand {\beamer@partpages {1}{6}} +\headcommand {\beamer@subsectionpages {1}{6}} +\headcommand {\beamer@sectionpages {1}{6}} +\headcommand {\beamer@documentpages {6}} +\headcommand {\gdef \inserttotalframenumber {6}} diff --git a/demo/presentation.out b/demo/presentation.out new file mode 100644 index 000000000..e69de29bb diff --git a/demo/presentation.pdf b/demo/presentation.pdf new file mode 100644 index 000000000..1b36990b2 Binary files /dev/null and b/demo/presentation.pdf differ diff --git a/demo/presentation.snm b/demo/presentation.snm new file mode 100644 index 000000000..e69de29bb diff --git a/demo/presentation.tex b/demo/presentation.tex new file mode 100644 index 000000000..cf7bddcb4 --- /dev/null +++ b/demo/presentation.tex @@ -0,0 +1,402 @@ +\documentclass[aspectratio=169]{beamer} + +% ============================================ +% HOOK BAZAAR THEME - MATCHING UI AESTHETICS +% ============================================ +% Colors from client2/src/index.css: +% --color-primary: gold (#FFD700) +% --color-bg-darkest: #000814 (deep navy) +% --color-bg-dark: #001f3f (navy) +% --color-secondary: #003366 +% --color-accent: #e85a4f (coral/terracotta) +% --color-white: #fff + +\usepackage{fontspec} +\usepackage{tikz} +\usetikzlibrary{positioning} +\usepackage{graphicx} +\usepackage{booktabs} +\usepackage{hyperref} +\usepackage{fontawesome5} + +% Define Hook Bazaar colors +\definecolor{hbPrimary}{HTML}{FFD700} % Gold +\definecolor{hbBgDarkest}{HTML}{000814} % Deep Navy +\definecolor{hbBgDark}{HTML}{001F3F} % Navy +\definecolor{hbSecondary}{HTML}{003366} % Secondary Blue +\definecolor{hbAccent}{HTML}{E85A4F} % Coral/Terracotta +\definecolor{hbWhite}{HTML}{FFFFFF} % White +\definecolor{hbMarble}{HTML}{F5F5F0} % Marble Light + +% Beamer theme configuration +\usetheme{default} +\usecolortheme{default} + +% Set background and foreground +\setbeamercolor{background canvas}{bg=hbBgDarkest} +\setbeamercolor{normal text}{fg=hbWhite} +\setbeamercolor{frametitle}{fg=hbPrimary} +\setbeamercolor{title}{fg=hbPrimary} +\setbeamercolor{subtitle}{fg=hbWhite} +\setbeamercolor{author}{fg=hbMarble} +\setbeamercolor{date}{fg=hbMarble} +\setbeamercolor{item}{fg=hbPrimary} +\setbeamercolor{subitem}{fg=hbAccent} +\setbeamercolor{block title}{fg=hbBgDarkest, bg=hbPrimary} +\setbeamercolor{block body}{fg=hbWhite, bg=hbSecondary} +\setbeamercolor{structure}{fg=hbPrimary} + +% Remove navigation symbols +\setbeamertemplate{navigation symbols}{} + +% Custom frame title with gold underline +\setbeamertemplate{frametitle}{ + \vspace{0.5cm} + {\Large\bfseries\insertframetitle} + \vspace{0.1cm} + \par + \textcolor{hbPrimary}{\rule{\textwidth}{2pt}} + \vspace{0.3cm} +} + +% Custom footline +\setbeamertemplate{footline}{ + \hbox{% + \begin{beamercolorbox}[wd=.333333\paperwidth,ht=2.25ex,dp=1ex,left]{author in head/foot}% + \hspace*{2ex}\textcolor{hbPrimary}{\tiny Hook Bazaar} + \end{beamercolorbox}% + \begin{beamercolorbox}[wd=.333333\paperwidth,ht=2.25ex,dp=1ex,center]{title in head/foot}% + \textcolor{hbMarble}{\tiny\insertshorttitle} + \end{beamercolorbox}% + \begin{beamercolorbox}[wd=.333333\paperwidth,ht=2.25ex,dp=1ex,right]{date in head/foot}% + \textcolor{hbMarble}{\tiny\insertframenumber{} / \inserttotalframenumber}\hspace*{2ex} + \end{beamercolorbox}}% + \vskip0pt% +} + +% Custom itemize +\setbeamertemplate{itemize item}{\textcolor{hbPrimary}{\faAngleRight}} +\setbeamertemplate{itemize subitem}{\textcolor{hbAccent}{\faAngleDoubleRight}} + +% Fonts - Space Grotesk style (use system sans as fallback) +\setsansfont{Inter}[ + BoldFont={Inter Bold}, + Scale=1.0 +] + +% Title and content +\title{\textbf{Hook Bazaar}} +\subtitle{Decentralized Marketplace for Uniswap v4 Hooks} +\author{UHI7 Team} +\date{December 2025} + +\begin{document} + +% ============================================ +% SLIDE 1: TITLE / INTRO +% ============================================ +\begin{frame} +\begin{center} +\vspace{1cm} +{\Huge\textcolor{hbPrimary}{\textbf{Hook Bazaar}}} + +\vspace{0.5cm} + +\textcolor{hbMarble}{\large Decentralized Marketplace for Uniswap v4 Hooks} + +\vspace{1.5cm} + +\begin{tikzpicture} + \draw[hbPrimary, line width=2pt] (-4,0) -- (4,0); +\end{tikzpicture} + +\vspace{1cm} + +\textcolor{hbWhite}{Building the Infrastructure Layer for the}\\[0.3cm] +\textcolor{hbPrimary}{\textbf{Uniswap v4 Hooks Economy}} + +\vspace{1.5cm} + +{\small\textcolor{hbMarble}{UHI7 Team $\cdot$ December 2025}} +\end{center} +\end{frame} + +% ============================================ +% SLIDE 2: PROBLEM / CHALLENGES +% ============================================ +\begin{frame}{The Problem: 9 Critical Market Failures} + +\begin{columns}[T] +\begin{column}{0.48\textwidth} +\textcolor{hbAccent}{\textbf{Market Infrastructure}} +\begin{itemize} + \item \textbf{No marketplace} for hooks + \item Supply \& demand exist --- no connection + \item No competition mechanism +\end{itemize} + +\vspace{0.5cm} + +\textcolor{hbAccent}{\textbf{Developer Pain Points}} +\begin{itemize} + \item No monetization model + \item No IP protection (code is public) + \item No reputation system +\end{itemize} +\end{column} + +\begin{column}{0.48\textwidth} +\textcolor{hbAccent}{\textbf{Protocol Barriers}} +\begin{itemize} + \item Custom hooks: \textcolor{hbPrimary}{\$10k--\$100k+} + \item Development time: \textcolor{hbPrimary}{weeks--months} + \item High audit costs \& risk +\end{itemize} + +\vspace{0.5cm} + +\textcolor{hbAccent}{\textbf{Ecosystem Gaps}} +\begin{itemize} + \item No standardization + \item No multi-hook composition + \item Unsustainable economics +\end{itemize} +\end{column} +\end{columns} + +\vspace{0.8cm} + +\begin{center} +\begin{tikzpicture} + \node[draw=hbAccent, thick, rounded corners, fill=hbSecondary, text=hbWhite, inner sep=10pt] { + \textbf{Result:} Despite v4's power, the ecosystem lacks infrastructure for adoption + }; +\end{tikzpicture} +\end{center} +\end{frame} + +% ============================================ +% SLIDE 3: SOLUTION OVERVIEW +% ============================================ +\begin{frame}{The Solution: Hook Bazaar} + +\begin{center} +\textcolor{hbPrimary}{\large\textbf{A Decentralized Marketplace \& Infrastructure Layer}} +\end{center} + +\vspace{0.5cm} + +\begin{columns}[T] +\begin{column}{0.32\textwidth} +\begin{block}{\faCode\ For Developers} +\begin{itemize} + \item Direct monetization + \item IP protection via FHE + \item Reputation profiles + \item Professional exposure +\end{itemize} +\end{block} +\end{column} + +\begin{column}{0.32\textwidth} +\begin{block}{\faBuilding\ For Protocols} +\begin{itemize} + \item Instant deployment + \item \textcolor{hbPrimary}{\$100s} vs \$10k+ + \item Pre-audited hooks + \item Multi-hook composition +\end{itemize} +\end{block} +\end{column} + +\begin{column}{0.32\textwidth} +\begin{block}{\faGlobe\ For Ecosystem} +\begin{itemize} + \item Self-sustaining model + \item Quality via competition + \item Network effects + \item V4 adoption boost +\end{itemize} +\end{block} +\end{column} +\end{columns} + +\vspace{0.8cm} + +\begin{center} +\textcolor{hbMarble}{Time-to-market: \textcolor{hbAccent}{\textbf{weeks}} $\rightarrow$ \textcolor{hbPrimary}{\textbf{minutes}}} +\end{center} +\end{frame} + +% ============================================ +% SLIDE 4: SOLUTION APPROACH +% ============================================ +\begin{frame}{Architecture \& Approach} + +\begin{center} +\begin{tikzpicture}[ + box/.style={draw=hbPrimary, thick, rounded corners=3pt, fill=hbSecondary, text=hbWhite, minimum width=2.8cm, minimum height=1cm, align=center, font=\small}, + external/.style={draw=hbAccent, thick, rounded corners=3pt, fill=hbBgDark, text=hbMarble, minimum width=2.2cm, minimum height=0.8cm, align=center, font=\scriptsize}, + arrow/.style={->, thick, hbPrimary} +] + % Core packages + \node[box] (protocol) at (0,2) {protocol-pkg\\{\tiny Protocol Lifecycle}}; + \node[box] (hook) at (4,2) {hook-pkg\\{\tiny Marketplace + IP}}; + \node[box] (avs) at (0,0) {hooks-operator-avs\\{\tiny Attestation}}; + \node[box] (master) at (4,0) {master-hook-pkg\\{\tiny Composition}}; + + % External systems + \node[external] (uniswap) at (-3,2) {Uniswap V4}; + \node[external] (eigen) at (-3,0) {EigenLayer}; + \node[external] (ipfs) at (7,2) {IPFS}; + \node[external] (fhenix) at (7,0) {Fhenix FHE}; + + % Arrows + \draw[arrow] (protocol) -- (uniswap); + \draw[arrow] (avs) -- (eigen); + \draw[arrow] (hook) -- (ipfs); + \draw[arrow] (hook) -- (fhenix); + \draw[arrow, hbAccent] (protocol) -- (hook); + \draw[arrow, hbAccent] (avs) -- (hook); + \draw[arrow, hbAccent] (master) -- (hook); +\end{tikzpicture} +\end{center} + +\vspace{0.5cm} + +\begin{columns}[T] +\begin{column}{0.48\textwidth} +\textcolor{hbPrimary}{\textbf{Core Packages}} +\begin{itemize} + \item \textbf{protocol-pkg}: Pool administration + \item \textbf{hook-pkg}: Development \& marketplace + \item \textbf{hooks-operator-avs}: EigenLayer attestation + \item \textbf{master-hook-pkg}: Diamond composition +\end{itemize} +\end{column} + +\begin{column}{0.48\textwidth} +\textcolor{hbPrimary}{\textbf{Sponsor Integrations}} +\begin{itemize} + \item \textbf{Fhenix CoFHE}: Encrypted hooks for IP protection + \item \textbf{EigenLayer AVS}: Cryptoeconomic guarantees via staked operators +\end{itemize} +\end{column} +\end{columns} +\end{frame} + +% ============================================ +% SLIDE 5: FEATURE 1 - HOOK SPECIFICATION FORMAT +% ============================================ +\begin{frame}{Key Feature: Mathematical Hook Specifications} + +\begin{columns}[T] +\begin{column}{0.55\textwidth} +\textcolor{hbPrimary}{\large\textbf{Hook Specification Format (HSF)}} + +\vspace{0.3cm} + +\textcolor{hbAccent}{\textbf{Why It Matters}} +\begin{itemize} + \item Objective behavior verification + \item Formal state machine definitions + \item Machine-readable specifications + \item Foundation for AVS attestation +\end{itemize} + +\vspace{0.5cm} + +\textcolor{hbAccent}{\textbf{What It Enables}} +\begin{itemize} + \item \textbf{Trust}: Verify before integrating + \item \textbf{Comparison}: Objective evaluation + \item \textbf{Slashing}: Proof of misbehavior + \item \textbf{Composition}: Safe multi-hook stacking +\end{itemize} +\end{column} + +\begin{column}{0.42\textwidth} +\begin{tikzpicture} + \node[draw=hbPrimary, thick, fill=hbSecondary, text=hbMarble, rounded corners, inner sep=8pt, font=\scriptsize, align=left] { + \textcolor{hbPrimary}{\texttt{// Hook State Model}}\\[2pt] + \texttt{States: \{Inactive, Active\}}\\[2pt] + \texttt{Events: \{beforeSwap, afterSwap\}}\\[2pt] + \texttt{Invariants:}\\ + \texttt{\ \ fee $\leq$ MAX\_FEE}\\ + \texttt{\ \ balance $\geq$ 0}\\[4pt] + \textcolor{hbPrimary}{\texttt{// Transition}}\\[2pt] + \texttt{beforeSwap(params):}\\ + \texttt{\ \ require(state == Active)}\\ + \texttt{\ \ fee = computeFee(params)}\\ + \texttt{\ \ emit FeeUpdated(fee)} + }; +\end{tikzpicture} + +\vspace{0.3cm} + +\begin{center} +\textcolor{hbMarble}{\scriptsize Specifications stored on IPFS}\\ +\textcolor{hbMarble}{\scriptsize Verified by EigenLayer operators} +\end{center} +\end{column} +\end{columns} +\end{frame} + +% ============================================ +% SLIDE 6: FEATURE 2 - AVS ATTESTATION +% ============================================ +\begin{frame}{Key Feature: EigenLayer AVS Attestation} + +\begin{columns}[T] +\begin{column}{0.55\textwidth} +\textcolor{hbPrimary}{\large\textbf{Cryptoeconomic Guarantees}} + +\vspace{0.3cm} + +\textcolor{hbAccent}{\textbf{Why It Matters}} +\begin{itemize} + \item Staked operators verify hook behavior + \item Economic penalties for false attestations + \item Decentralized trust --- no central authority + \item Continuous compliance monitoring +\end{itemize} + +\vspace{0.5cm} + +\textcolor{hbAccent}{\textbf{Slashing Mechanism}} +\begin{itemize} + \item \textbf{50\% slash}: False positive attestation + \item \textbf{30\% slash}: False negative (missed violation) + \item Challenge window for disputes + \item Proof submitted on-chain +\end{itemize} +\end{column} + +\begin{column}{0.42\textwidth} +\begin{tikzpicture}[ + node distance=0.8cm, + box/.style={draw=hbPrimary, thick, rounded corners=2pt, fill=hbSecondary, text=hbWhite, minimum width=2.5cm, minimum height=0.7cm, align=center, font=\scriptsize}, + arrow/.style={->, thick, hbPrimary} +] + \node[box] (task) {Task Created}; + \node[box, below=of task] (sample) {Operator Samples\\Hook State}; + \node[box, below=of sample] (verify) {Verify Against\\Specification}; + \node[box, below=of verify] (attest) {Submit\\Attestation}; + \node[box, below=of attest] (challenge) {Challenge\\Window}; + + \draw[arrow] (task) -- (sample); + \draw[arrow] (sample) -- (verify); + \draw[arrow] (verify) -- (attest); + \draw[arrow] (attest) -- (challenge); +\end{tikzpicture} + +\vspace{0.3cm} + +\begin{center} +\textcolor{hbMarble}{\scriptsize Powered by EigenLayer restaking} +\end{center} +\end{column} +\end{columns} +\end{frame} + +\end{document} diff --git a/demo/presentation.toc b/demo/presentation.toc new file mode 100644 index 000000000..e69de29bb diff --git a/docs/helpers/DynamicFeeMock.pdf b/docs/helpers/DynamicFeeMock.pdf new file mode 100644 index 000000000..658080a57 Binary files /dev/null and b/docs/helpers/DynamicFeeMock.pdf differ diff --git a/docs/helpers/DynamicFeeMock.tex b/docs/helpers/DynamicFeeMock.tex new file mode 100644 index 000000000..2b13cc4da --- /dev/null +++ b/docs/helpers/DynamicFeeMock.tex @@ -0,0 +1,107 @@ +\documentclass[11pt,a4paper]{article} +\usepackage[margin=1.5cm]{geometry} +\usepackage{amsmath,amssymb} +\usepackage{booktabs} +\usepackage{array} +\usepackage{fancyhdr} +\usepackage{titlesec} + +\pagestyle{fancy} +\fancyhf{} +\rhead{Hook Bazaar} +\lhead{DynamicFeeMock v1.0} +\cfoot{\thepage} + +\titlespacing*{\section}{0pt}{1.5ex}{0.5ex} +\titlespacing*{\subsection}{0pt}{1ex}{0.3ex} + +\begin{document} + +\begin{center} +\Large\textbf{DynamicFeeMock Hook Specification}\\[0.3em] +\normalsize Hook Bazaar Formal Specification Format\\[0.2em] +\small Version 1.0 \quad|\quad Category: FEE\_MANAGEMENT \quad|\quad License: MIT +\end{center} + +\vspace{0.5em} +\hrule +\vspace{0.5em} + +\section*{1. Hook State Variables ($H$)} + +\begin{center} +\begin{tabular}{llll} +\toprule +\textbf{Symbol} & \textbf{Type} & \textbf{Description} & \textbf{Initial} \\ +\midrule +$\phi_{base}$ & \texttt{uint24} & Base fee (basis points) & 3000 \\ +$\phi_{min}$ & \texttt{uint24} & Minimum fee bound & 100 \\ +$\phi_{max}$ & \texttt{uint24} & Maximum fee bound & 10000 \\ +$\alpha$ & \texttt{uint256} & Volatility coefficient & $10^{16}$ \\ +$V_{acc}$ & \texttt{uint256} & Accumulated volatility index & 0 \\ +$t_{last}$ & \texttt{uint256} & Last update timestamp & 0 \\ +\bottomrule +\end{tabular} +\end{center} + +\section*{2. Pool State Dependencies (from $\mathcal{S}_T$)} + +\textbf{Reads:} $\sqrt{P}$ (sqrtPriceX96), $t_c$ (tick), $\phi_{lp}$ (lpFee), $L_{act}$ (liquidity)\\ +\textbf{Writes:} $\phi_{lp}$ (lpFee via \texttt{beforeSwap} return) + +\section*{3. State Transition: \texttt{beforeSwap}} + +\textbf{Preconditions:} +\begin{itemize} +\setlength\itemsep{-0.2em} +\item $L_{act} > 0$ (pool has active liquidity) +\item $\phi_{min} \leq \phi_{base} \leq \phi_{max}$ +\end{itemize} + +\textbf{Transition Equations:} + +\begin{align} +\Delta P &= \left| \sqrt{P}_{current} - \sqrt{P}_{last} \right| \label{eq:delta_p}\\[0.3em] +V_{acc}' &= V_{acc} + \frac{\Delta P \cdot \alpha}{10^{18}} \label{eq:vacc}\\[0.3em] +\sigma &= \frac{V_{acc}'}{t_{current} - t_{last} + 1} \label{eq:sigma}\\[0.3em] +\phi_{dynamic} &= \min\left(\phi_{max}, \max\left(\phi_{min}, \phi_{base} + \sigma\right)\right) \label{eq:phi} +\end{align} + +\textbf{Postconditions:} +\begin{itemize} +\setlength\itemsep{-0.2em} +\item $\phi_{min} \leq \phi_{dynamic} \leq \phi_{max}$ (fee bounds invariant) +\item $V_{acc}' \geq V_{acc}$ (volatility monotonic) +\end{itemize} + +\textbf{Return:} $(\texttt{selector}, \Delta_0 = 0, \phi_{dynamic})$ + +\section*{4. Invariants} + +\begin{center} +\begin{tabular}{lll} +\toprule +\textbf{ID} & \textbf{Expression} & \textbf{Severity} \\ +\midrule +INV-1 & $\phi_{min} \leq \phi_{lp} \leq \phi_{max}$ & Critical \\ +INV-2 & $V_{acc}' \geq V_{acc}$ & Warning \\ +INV-3 & $\phi_{base} \in [100, 10000]$ & Critical \\ +\bottomrule +\end{tabular} +\end{center} + +\section*{5. Constant Product Reference} + +From the dual-index state-space model, the tick-wise invariant holds: +$$K - X' \leq K' \leq K \quad \text{where} \quad K = X \cdot Y$$ + +The hook does \textbf{not} modify $K$; it only adjusts $\phi_{lp}$ based on volatility. + +\vspace{0.5em} +\hrule +\vspace{0.3em} +\begin{center} +\small\textit{Specification URI: ipfs://QmDynamicFeeMockSpec... | Attestation: Pending AVS} +\end{center} + +\end{document} diff --git a/operator/README.md b/operator/README.md index 7387b00e3..740083778 100644 --- a/operator/README.md +++ b/operator/README.md @@ -309,6 +309,18 @@ DRY_RUN=1 npm start DRY_RUN=0 npm start ``` +### Attestation Simulation + +Runs a DynamicFeeMock attestation simulation with console report output. + +```bash +# Terminal 1 +anvil + +# Terminal 2 +npx tsx integration/runSimulation.ts +``` + ### Manual Task Processing (Testing) ```typescript diff --git a/operator/integration/DynamicFeeMock.spec.json b/operator/integration/DynamicFeeMock.spec.json new file mode 100644 index 000000000..ab7aca813 --- /dev/null +++ b/operator/integration/DynamicFeeMock.spec.json @@ -0,0 +1,147 @@ +{ + "version": "1.0.0", + "hookAddress": "0x0000000000000000000000000000000000000000", + "specificationHash": "QmDynamicFeeMockSpec", + "callbacks": ["beforeSwap"], + "hookStateVariables": [ + { + "name": "baseFee", + "type": "uint24", + "description": "Base fee in basis points", + "initialValue": "3000" + }, + { + "name": "minFee", + "type": "uint24", + "description": "Minimum fee bound", + "initialValue": "100" + }, + { + "name": "maxFee", + "type": "uint24", + "description": "Maximum fee bound", + "initialValue": "10000" + }, + { + "name": "alpha", + "type": "uint256", + "description": "Volatility coefficient", + "initialValue": "10000000000000000" + }, + { + "name": "volatilityAccumulator", + "type": "uint256", + "description": "Accumulated volatility index", + "initialValue": "0" + }, + { + "name": "lastUpdateTimestamp", + "type": "uint256", + "description": "Last update timestamp", + "initialValue": "0" + } + ], + "poolStateDependencies": { + "reads": ["sqrtPriceX96", "tick", "lpFee", "liquidity"], + "writes": ["lpFee"] + }, + "transitionFunctions": [ + { + "callback": "beforeSwap", + "description": "Computes dynamic fee based on price volatility", + "inputs": [ + { "name": "sender", "type": "address", "description": "Swap sender" }, + { "name": "key", "type": "PoolKey", "description": "Pool key" }, + { "name": "params", "type": "SwapParams", "description": "Swap parameters" } + ], + "outputs": [ + { "name": "selector", "type": "bytes4", "description": "Function selector" }, + { "name": "delta", "type": "BeforeSwapDelta", "description": "Always zero" }, + { "name": "lpFeeOverride", "type": "uint24", "description": "Dynamic fee" } + ], + "equations": [ + "deltaP = |sqrtPrice_current - sqrtPrice_last|", + "V_acc' = V_acc + (deltaP * alpha) / 10^18", + "sigma = V_acc' / (t_current - t_last + 1)", + "phi_dynamic = min(maxFee, max(minFee, baseFee + sigma))" + ], + "constraints": [ + "liquidity > 0", + "minFee <= baseFee <= maxFee" + ] + } + ], + "invariants": [ + { + "id": "INV-1", + "name": "Fee Bounds", + "description": "Dynamic fee must stay within configured bounds", + "expression": "minFee <= lpFee <= maxFee", + "severity": "critical" + }, + { + "id": "INV-2", + "name": "Volatility Monotonic", + "description": "Volatility accumulator can only increase", + "expression": "V_acc' >= V_acc", + "severity": "warning" + }, + { + "id": "INV-3", + "name": "Base Fee Range", + "description": "Base fee must be within valid range", + "expression": "baseFee >= 100 AND baseFee <= 10000", + "severity": "critical" + } + ], + "testVectors": [ + { + "id": "TV-1", + "description": "Low volatility results in base fee", + "preState": { + "sqrtPrice": "79228162514264337593543950336", + "V_acc": "0", + "baseFee": "3000" + }, + "input": { + "deltaPrice": "1000000000" + }, + "expectedPostState": { + "lpFee": "3000" + }, + "tolerance": 100 + }, + { + "id": "TV-2", + "description": "High volatility increases fee", + "preState": { + "sqrtPrice": "79228162514264337593543950336", + "V_acc": "5000000000000000000", + "baseFee": "3000" + }, + "input": { + "deltaPrice": "1000000000000000000" + }, + "expectedPostState": { + "lpFee": "8000" + }, + "tolerance": 500 + }, + { + "id": "TV-3", + "description": "Fee capped at maximum", + "preState": { + "sqrtPrice": "79228162514264337593543950336", + "V_acc": "100000000000000000000", + "baseFee": "3000" + }, + "input": { + "deltaPrice": "10000000000000000000" + }, + "expectedPostState": { + "lpFee": "10000" + }, + "tolerance": 0 + } + ] +} diff --git a/operator/integration/attestation-report.md b/operator/integration/attestation-report.md new file mode 100644 index 000000000..d3980cf8d --- /dev/null +++ b/operator/integration/attestation-report.md @@ -0,0 +1,109 @@ +# DynamicFeeMock Attestation Report + +**Generated:** 2025-12-11T21:19:50.152Z +**Status:** [PASS] COMPLIANT + +--- + +## 1. Task Summary + +| Field | Value | +|-------|-------| +| Task Index | 1 | +| Hook Address | `0x1234567890123456789012345678901234567890` | +| Specification URI | `file:///home/jmsbpp/hook-bazaar-monorepo/operator/integration/DynamicFeeMock.spec.json` | +| Pools Sampled | 1 | +| Callbacks Tested | 1 | +| Samples Requested | 5 | +| Samples Collected | 5 | +| Processing Time | 150ms | + +--- + +## 2. Hook Specification + +### State Variables (H) + +| Symbol | Type | Description | Initial | +|--------|------|-------------|---------| +| `baseFee` | `uint24` | Base fee in basis points | 3000 | +| `minFee` | `uint24` | Minimum fee bound | 100 | +| `maxFee` | `uint24` | Maximum fee bound | 10000 | +| `alpha` | `uint256` | Volatility coefficient | 10000000000000000 | +| `volatilityAccumulator` | `uint256` | Accumulated volatility index | 0 | +| `lastUpdateTimestamp` | `uint256` | Last update timestamp | 0 | + +### Pool State Dependencies + +**Reads:** sqrtPriceX96, tick, lpFee, liquidity +**Writes:** lpFee + +### Transition Functions + +#### beforeSwap + +Computes dynamic fee based on price volatility + +**Equations:** +- `deltaP = |sqrtPrice_current - sqrtPrice_last|` +- `V_acc' = V_acc + (deltaP * alpha) / 10^18` +- `sigma = V_acc' / (t_current - t_last + 1)` +- `phi_dynamic = min(maxFee, max(minFee, baseFee + sigma))` + +**Constraints:** +- `liquidity > 0` +- `minFee <= baseFee <= maxFee` + +--- + +## 3. Invariants + +| ID | Name | Expression | Severity | +|----|------|------------|----------| +| INV-1 | Fee Bounds | `minFee <= lpFee <= maxFee` | critical | +| INV-2 | Volatility Monotonic | `V_acc' >= V_acc` | warning | +| INV-3 | Base Fee Range | `baseFee >= 100 AND baseFee <= 10000` | critical | + +--- + +## 4. Verification Results + +### Overall Compliance: COMPLIANT + +| Metric | Value | +|--------|-------| +| Spec Compliant | true | +| Invariants Verified | 15 | +| Invariants Failed | 0 | +| State Samples Hash | `0x4463f81826fe95a04a...` | +| Test Results Hash | `0xcb9a12a15215478660...` | + +--- + +## 5. Test Vectors + +| ID | Description | Expected Fee | Tolerance | +|----|-------------|--------------|-----------| +| TV-1 | Low volatility results in base fee | 3000 | 100bps | +| TV-2 | High volatility increases fee | 8000 | 500bps | +| TV-3 | Fee capped at maximum | 10000 | 0bps | + +--- + +## 6. Attestation Response + +```json +{ + "referenceTaskIndex": 1, + "specCompliant": true, + "stateSamplesHash": "0x4463f81826fe95a04a555124e4639c39353fae599203babaedeb349cd77bfb66", + "testResultsHash": "0xcb9a12a15215478660ae55d5e215f8836a227081e4ecfa6714474f81b4a886a9", + "invariantsVerified": 15, + "invariantsFailed": 0 +} +``` + +--- + +*Report generated by HookAttestationAVS Operator Simulation* +*Reference: DynamicFeeMock.pdf specification* diff --git a/operator/integration/runSimulation.ts b/operator/integration/runSimulation.ts new file mode 100644 index 000000000..80b81827d --- /dev/null +++ b/operator/integration/runSimulation.ts @@ -0,0 +1,387 @@ +/** + * DynamicFeeMock Attestation Simulation + * + * This script simulates the full attestation flow: + * 1. Deploys a mock TaskManager that emits AttestationTaskCreated events + * 2. Creates an attestation task for DynamicFeeMock + * 3. Processes the task using the operator's verification logic + * 4. Outputs a compliance report + * + * Usage: + * Terminal 1: anvil + * Terminal 2: npx tsx integration/runSimulation.ts + */ + +import { ethers } from "ethers"; +import * as fs from "fs"; +import * as path from "path"; +import { fileURLToPath } from "url"; +import { + createMockDependencies, + summarizeResults, + createAttestationResponse, +} from "../src/processor.js"; +import { parseJSONSpecification, validateSpecification } from "../src/specParser.js"; +import { createMockStateView, sampleStatesForTask, hashStateSamples } from "../src/stateSampler.js"; +import { checkCompliance, hashTestResults } from "../src/complianceChecker.js"; +import { AttestationTask, HookSpecification, TaskProcessingResult, AttestationResponse } from "../src/types.js"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// ═══════════════════════════════════════════════════════════════════════════════ +// CONFIGURATION +// ═══════════════════════════════════════════════════════════════════════════════ + +const CONFIG = { + rpcUrl: "http://127.0.0.1:8545", + hookAddress: "0x1234567890123456789012345678901234567890", + poolId: "0x" + "ab".repeat(32), + sampleCount: 5, + specPath: path.join(__dirname, "DynamicFeeMock.spec.json"), + reportPath: path.join(__dirname, "attestation-report.md"), +}; + +// ═══════════════════════════════════════════════════════════════════════════════ +// MOCK TASK MANAGER CONTRACT +// ═══════════════════════════════════════════════════════════════════════════════ + +const MOCK_TASK_MANAGER_BYTECODE = ` +608060405234801561001057600080fd5b50610400806100206000396000f3fe +608060405234801561001057600080fd5b506004361061002b5760003560e01c +8063a123456714610030575b600080fd5b61004a60048036038101906100459190 +610200565b61004c565b005b7f1234567890abcdef1234567890abcdef12345678 +90abcdef1234567890abcdef600083838080601f0160208091040260200160405 +19081016040528093929190818152602001838380828437600081840152601f +19601f820116905080830192505050505050508460405161010091906102e0565b +60405180910390a1505050565b600080fd5b600080fd5b600080fd5b60008083 +601f84011261013057600080fd5b8235905067ffffffffffffffff81111561014a +57600080fd5b60208301915083600182028301111561016357600080fd5b929150 +50565b6000819050919050565b61017c81610169565b811461018757600080fd5b +50565b60008135905061019981610173565b92915050565b600080600060408486 +0312156101b557600080fd5b60006101c38682870161018a565b9350506020840135 +67ffffffffffffffff8111156101e157600080fd5b6101ed86828701610114565b +92509250509250925092565b600060208201905061020d6000830184610296565b +92915050565b61021c81610169565b82525050565b600081519050919050565b +600082825260208201905092915050565b60005b8381101561025c578082015181 +840152602081019050610241565b8381111561026b576000848401525b50505050 +565b6000601f19601f8301169050919050565b600061028d82610222565b610297 +818561022d565b93506102a781856020860161023e565b6102b081610271565b84 +0191505092915050565b60006040820190506102cf6000830185610213565b8181 +036020830152610282565b9291505056fea2646970667358221220000000000000 +00000000000000000000000000000000000000000000000000000064736f6c6343 +0008130033 +`; + +const MOCK_TASK_MANAGER_ABI = [ + "event AttestationTaskCreated(uint32 indexed taskIndex, tuple(address hook, string specificationURI, bytes32[] poolIds, bytes4[] callbacks, uint32 sampleCount, uint32 taskCreatedBlock, bytes quorumNumbers, uint32 quorumThresholdPercentage) task)", + "function createTask(uint32 taskIndex, string calldata specificationURI) external", +]; + +// ═══════════════════════════════════════════════════════════════════════════════ +// REPORT GENERATION +// ═══════════════════════════════════════════════════════════════════════════════ + +function generateReport( + spec: HookSpecification, + result: TaskProcessingResult, + task: AttestationTask +): string { + const timestamp = new Date().toISOString(); + const complianceStatus = result.response?.specCompliant ? "COMPLIANT" : "NON-COMPLIANT"; + const statusEmoji = result.response?.specCompliant ? "[PASS]" : "[FAIL]"; + + let report = `# DynamicFeeMock Attestation Report + +**Generated:** ${timestamp} +**Status:** ${statusEmoji} ${complianceStatus} + +--- + +## 1. Task Summary + +| Field | Value | +|-------|-------| +| Task Index | ${result.taskIndex} | +| Hook Address | \`${task.hook}\` | +| Specification URI | \`${task.specificationURI}\` | +| Pools Sampled | ${task.poolIds.length} | +| Callbacks Tested | ${task.callbacks.length} | +| Samples Requested | ${task.sampleCount} | +| Samples Collected | ${result.samplesCollected} | +| Processing Time | ${result.processingTimeMs}ms | + +--- + +## 2. Hook Specification + +### State Variables (H) + +| Symbol | Type | Description | Initial | +|--------|------|-------------|---------| +`; + + for (const v of spec.hookStateVariables) { + report += `| \`${v.name}\` | \`${v.type}\` | ${v.description} | ${v.initialValue ?? "-"} |\n`; + } + + report += ` +### Pool State Dependencies + +**Reads:** ${spec.poolStateDependencies.reads.join(", ")} +**Writes:** ${spec.poolStateDependencies.writes.join(", ")} + +### Transition Functions + +`; + + for (const tf of spec.transitionFunctions) { + report += `#### ${tf.callback} + +${tf.description} + +**Equations:** +`; + for (const eq of tf.equations) { + report += `- \`${eq}\`\n`; + } + + report += ` +**Constraints:** +`; + for (const c of tf.constraints) { + report += `- \`${c}\`\n`; + } + report += "\n"; + } + + report += `--- + +## 3. Invariants + +| ID | Name | Expression | Severity | +|----|------|------------|----------| +`; + + for (const inv of spec.invariants) { + report += `| ${inv.id} | ${inv.name} | \`${inv.expression}\` | ${inv.severity} |\n`; + } + + report += ` +--- + +## 4. Verification Results + +`; + + if (result.success && result.response) { + report += `### Overall Compliance: ${complianceStatus} + +| Metric | Value | +|--------|-------| +| Spec Compliant | ${result.response.specCompliant} | +| Invariants Verified | ${result.response.invariantsVerified} | +| Invariants Failed | ${result.response.invariantsFailed} | +| State Samples Hash | \`${result.response.stateSamplesHash.slice(0, 20)}...\` | +| Test Results Hash | \`${result.response.testResultsHash.slice(0, 20)}...\` | + +`; + } else { + report += `### Processing Failed + +**Error:** ${result.error ?? "Unknown error"} + +`; + } + + report += `--- + +## 5. Test Vectors + +| ID | Description | Expected Fee | Tolerance | +|----|-------------|--------------|-----------| +`; + + for (const tv of spec.testVectors) { + const expectedFee = (tv.expectedPostState as Record