פיתוח Hooks ל-Uniswap v4 במפתח מלא
Uniswap v3 מגביל התאמה אישית של בריכות: עבור עמלות דינמיות, נאלצתם לפצל את חוזה הבריכה. v4 הופך את הארכיטקטורה — במקום אלפי חוזי בריכה נפרדים, יש PoolManager יחיד ו-14 פונקציות callback המיושמות דרך hooks. אך כל hook דורש הבנה עמוקה של flash accounting והגדרת כתובת. אנו מתמחים במשימות אלה: אנו מפתחים hooks מוכנים לייצור עם כיסוי בדיקות מלא ותיעוד הכנה לאודיט.
פיתחנו hooks עבור 30+ פרויקטי DeFi, כולל עמלות דינמיות ל-DEXים מרכזיים. הניסיון שלנו: 10+ שנים בבלוקצ'יין, אודיטורים מוסמכים של Solidity. אנו מבטיחים איכות קוד ואבטחה.
מדוע כתובת ה-Hook היא התצורה שלו
ב-v4, כתובת ה-hook היא התצורה שלו. 14 הביטים האחרונים של הכתובת מקודדים אילו פונקציות callback ה-hook מיישם: beforeSwap, afterSwap, beforeAddLiquidity, afterAddLiquidity — 14 דגלים בסך הכל. בעת רישום בריכה, PoolManager קורא את כתובת ה-hook ויודע אילו callbacks לקרוא ללא שאילתות on-chain נוספות.
תוצאה: לא ניתן פשוט לפרוס חוזה ולקבל את הכתובת הרצויה. נדרש כרייה — חיפוש brute-force של ה-salt ב-CREATE2 עד שהכתובת מכילה את הביטים הנכונים. Foundry הופך זאת לאוטומטי:
bytes32 salt = HookMiner.find(deployer, flags, creationCode, constructorArgs); אם הדגלים שגויים, bytes32 salt = HookMiner.find(deployer, flags, creationCode, constructorArgs); חוזר עם PoolManager.initialize. זו אבן הנגף הראשונה בעת מעבר מ-v3.
BeforeSwap ו-AfterSwap: שליטה אסימטרית
HookAddressNotValid יכול להחזיר beforeSwap. דרך (bytes4 selector, BeforeSwapDelta delta, uint24 lpFeeOverride), ה-hook יכול לשנות את כמויות הטוקנים המעורבים בהחלפה — למעשה ליירט חלק מהזרימה. דרך delta, הוא יכול להגדיר עמלה דינמית עבור hop ספציפי במקום העמלה הסטטית שנקבעה בעת אתחול הבריכה.
lpFeeOverride מקבל afterSwap — תוצאת ההחלפה — ויכול להוסיף לוגיקה מותאמת אישית מעל. מקרה שימוש טיפוסי הוא hook של החזר (rebate) שמחזיר חלק מהעמלות ל-LPs פעילים בצורת טוקנים.
ניואנס חשוב: Hooks פועלים בהקשר העסקה של PoolManager. כל פעולות הטוקנים עוברות דרך flash accounting — העברות ERC-20 בפועל מתרחשות רק בסוף דרך BalanceDelta/settle. אם hook מנסה לבצע take ישיר בתוך callback, זה שובר את ה-flash accounting וגורם ל-revert או, גרוע מכך, למצב יתרות שגוי.
Reentrancy ב-v4: חוקים חדשים
PoolManager מוגן על ידי modifier מסוג transfer — רק קריאה אחת של Lock פעילה בכל רגע. hook שמנסה לקרוא ל-lock בתוך PoolManager.swap יקבל revert. משמעות הדבר היא שארכיטקטורות שבהן ה-hook צריך ליזום החלפה משנית (למשל, איזון מחדש אוטומטי) דורשות ביצוע דחוי — דרך תור בחוזה חיצוני או דרך beforeSwap עם קריאה נפרדת לאחר מכן.
כיצד Hook יכול ליישם עמלות דינמיות
מקרה מהפרקטיקה שלנו. יישמנו hook שקורא את ה-TWAP מהמצבר שלו (מעודכן ב-afterSwap), מחשב σ על פני N הבלוקים האחרונים, וממפה את σ לרמת עמלה: תנודתיות נמוכה → 0.01%, תנודתיות גבוהה → 1%.afterSwap מוחזר ב-lpFeeOverride. LPs מקבלים הגנה אוטומטית בזמן תנועות שוק חדות ללא התערבות ידנית.
מקרי שימוש טיפוסיים אחרים:
- Hook של רשימת היתרים לבריכות מורשות: בודק
beforeSwapאו יתרת ERC-721 של המחליף ב-merkleProof/beforeSwap. - הפחתת LVR באמצעות מכירה פומבית: before-swap hook מיישם סכמת commit-reveal שבה בוטים של MEV מציעים הצעות על הזכות להחלפה הראשונה. ההכנסות הולכות ל-LPs.
טכנולוגיות וכלים
פיתוח: Foundry עם v4-template מ-Uniswap. בדיקות: fork על Ethereum Sepolia (v4 כבר פרוס ברשת הבדיקות). חוזה הבסיס beforeAddLiquidity מספק HookTest — אין צורך להגדיר ידנית PoolManager מדומה.
לכריית כתובת hook: deployFreshManagerAndRouters מ-v4-periphery. ב-CI, זה מופיע כשלב לפני הבדיקות: כריית ה-salt, העברתו לסקריפט הפריסה.
בדיקת תקינות הדגלים היא בדיקה נפרדת:
assertEq(uint160(address(hook)) & HookFlags.ALL_FLAGS, expectedFlags); בדיקה נכשלת מראה מיד שהכתובת נכרתה בצורה שגויה.
ספציפיות אודיט ל-Hooks
גלאי Slither הסטנדרטיים לא מכירים חוזי callback של v4. אנו כותבים גלאים מותאמים אישית לדפוסים ספציפיים:
- העברת ERC-20 ישירה בתוך callback (מפרה את ה-flash accounting)
- קריאה ישירה של
HookMinerבמקום דרך PoolManager (דפוס v3 מיושן) - חוסר בבדיקת
assertEq(uint160(address(hook)) & HookFlags.ALL_FLAGS, expectedFlags);בפונקציות callback
הנקודה האחרונה היא קריטית: אם hook לא בודק מי קורא ל-slot0, כל אחד יכול לקרוא לו ישירות עם פרמטרים שרירותיים. בהתאם ללוגיקה, זה עלול להוביל למניפולציה של מצב ללא החלפה בפועל.
השוואה: Uniswap v3 לעומת Uniswap v4 עם Hooks
| פרמטר | Uniswap v3 | Uniswap v4 עם Hooks |
|---|---|---|
| ארכיטקטורת בריכה | חוזה נפרד לכל בריכה | PoolManager יחיד + hooks |
| התאמת עמלות | קבועה בעת אתחול | דינמית דרך lpFeeOverride |
| גז ליצירת בריכה | ~500k גז | ~50k גז (פי 10 פחות) |
| יכולת רשימת היתרים | לא (רק fork) | מובנית דרך beforeSwap |
| מסגרת בדיקות | Hardhat/Foundry | Foundry + HookTest |
מה כלול בעבודה
| שלב | תוצר | לוח זמנים |
|---|---|---|
| ניתוח | מפרט טכני, דיאגרמת אינטראקציה | 2-3 ימים |
| עיצוב | פריסת אחסון, ממשק פונקציות בעלים | 2-3 ימים |
| פיתוח | קוד לכל ה-callbacks, בדיקות Sepolia, fuzzing | 1-2 שבועות |
| אודיט | גלאי Slither מותאמים אישית, סקירה ידנית | שבוע |
| פריסה | HookMiner CI, סקריפט פריסה, ניטור | יומיים |
| הדרכת צוות | תיעוד, המלצות ארכיטקטוניות | יום |
תהליך
- ניתוח (2-3 ימים). אנו ממליצים על לוגיקת ה-hook: אילו callbacks נדרשים, האם יש אחסון מותאם אישית, צורך בגישה ל-oracle. אנו בודקים תאימות לארכיטקטורת הבריכה הקיימת.
- עיצוב (2-3 ימים). דיאגרמת אינטראקציה בין hook ל-PoolManager, הגדרת פריסת אחסון (מזעור SLOAD בנתיבים חמים), ממשק תצורת בעלים.
- פיתוח (1-2 שבועות). יישום פונקציות callback, בדיקות fork של Sepolia, בדיקות fuzz לערכי קלט קצה.
-
אודיט (שבוע). גלאי Slither מותאמים אישית + סקירה ידנית של כל הנתיבים שבהם ה-hook משנה את
msg.sender == address(poolManager). תיעוד invariants עבור אודיטור חיצוני. - פריסה (יומיים). HookMiner ב-CI, סקריפט פריסה דרך Foundry עם בדיקת דגלים. ניטור דרך יומן אירועים של PoolManager ב-72 השעות הראשונות לאחר הפריסה.
הערכות לוח זמנים
Hook פשוט (callback יחיד, קריאה בלבד) — 4-6 ימים. Hook עם עמלות דינמיות ו-oracle מותאם אישית — 1-2 שבועות. Hook מורכב עם מכניקת מכירה פומבית או חשבונאות עמדות LP מותאמת אישית — 3-4 שבועות. העלות מחושבת לאחר ניתוח המפרט הטכני.
עיינו בתיעוד הרשמי של Uniswap v4 להבנה מעמיקה של המפרט.
קבלו ייעוץ לפרויקט שלכם
הזמינו פיתוח hook — נבחן את המשימה שלכם תוך 24 שעות. צרו קשר כדי לדון בארכיטקטורה ובלוחות זמנים.







