Uniswap v4 کے مین نیٹ ورک پر لانچ کے بعد، ہُک میکنزم DeFi کا ایک سب سے زیادہ توجہ حاصل کرنے والا ایجادی انقلاب بن گیا۔ Base چین پر میم کوائن لانچنگ پلیٹ فارم Flaunch نے ہُک کا استعمال کرتے ہوئے فکسڈ پری سیل قیمت اور آٹو میٹک کلیئرنگ لانچ میکنزم کو حاصل کیا؛ لیکویڈٹی پروٹوکول Bunni v2 نے ہُک کا استعمال کرتے ہوئے قابل پروگرام لیکویڈٹی اور ری مارجیننگ ماڈل تعمیر کیا؛ اس سال SATO، uPEG (Unipeg)، Slonks جیسے ہُک بنیادی ٹریڈنگ کے ارد گرد بنائے گئے ٹوکن نے مختصر عرصے میں دس گنا سے زیادہ کا فائدہ حاصل کیا۔
ہوک ایکوسسٹم کی خوشحالی کے دوسرے پہلو میں، ہوک کے عمل میں موجود خامیوں کا استعمال کرتے ہوئے حملوں میں نمایاں اضافہ ہوا ہے۔ اس مضمون میں، ہم یونی سوواپ v4 کے ہوک مکینزم سے شروع کرتے ہوئے، اس کے مرکزی کال اسٹیک کا تجزیہ کریں گے تاکہ پروجیکٹس کو ممکنہ خامیوں کو سمجھنے میں مدد ملے۔
یونیسواپ v4 ہُک سیکورٹی
1. تعارف
یونیسواپ v4 کا v3 کے مقابلے میں سب سے اہم آرکیٹیکچرل تبدیلی ہک (Hook) مکینزم کا تعارف ہے: جس سے ڈویلپرز کو لیکویڈیٹی پول کے لائف سائکل واقعات پر اپنے کسٹم کنٹریکٹس منسلک کرنے کی اجازت ہوتی ہے، جہاں سوپ، لیکویڈیٹی جوڑنا یا کم کرنا، اور شروع کرنا جیسے نوڈس پر کوئی بھی منطق شامل کیا جا سکتا ہے۔
v4 کے کچھ اہم تبدیلیاں درج ذیل ہیں:
Singleton ماڈل: تمام پولز کی حالت ایک ہی PoolManager کنٹریکٹ کے ذریعے مرکزی طور پر منتظم کی جاتی ہے، جس سے ہر پول کے لیے الگ الگ کنٹریکٹ ڈپلوی نہیں کیے جاتے۔
- فلیش اکاؤنٹنگ: ٹریڈنگ کے دوران درمیانی بیلنس کے تبدیلیوں کو صرف عارضی ذخیرہ میں ریکارڈ کیا جاتا ہے، اور صرف ٹریڈ ختم ہونے پر ایک ساتھ سیٹل کیا جاتا ہے
- ہُک میکنزم: ہر پول ایک ہُک کنٹریکٹ سے بندھا جا سکتا ہے، جس پر PoolManager اہم نکات (beforeInitialize، beforeSwap، afterAddLiquidity وغیرہ) پر کال بیک کرتا ہے۔
- ہُک قابل تبدیلی نہیں: جب پول شروع ہو جائے، تو منسلک ہُک ایڈریس ہمیشہ کے لیے ثابت ہو جاتا ہے (پول سے منسلک ہُک ایڈریس تبدیل نہیں کیا جا سکتا، لیکن ہُک کنٹریکٹ کی اپ گریڈ کرنے کی صلاحیت اس کے عمل کے انداز پر منحصر ہے)

v3 کے دوران، ڈویلپرز کو صرف یونیسواپ پروٹوکول پر اعتماد کرنا تھا؛ جبکہ v4 کے دوران، ہر پول کی سلامتی اس سے جڑے ہوئے ہک پر منحصر ہے۔ ہک نے AMM کو ایک مخصوص فنانشل پریمیٹ سے لے کر ایک قابل پروگرام فنانشل انفراسٹرکچر میں تبدیل کر دیا، لیکن سلامتی ماڈل بھی "پروٹوکول لیول" سے "پول لیول" تک ٹوٹ گیا۔
2. ہُک آرکیٹیکچر
2.1 PoolManager اور unlock/callback ماڈل
v4 کا مرکزی معاہدہ ایک یکتا PoolManager ہے۔ کسی بھی پول کی حالت میں تبدیلی (swap، لیکویڈٹی جوڑنا یا کم کرنا) کے لیے پہلے PoolManager.unlock() کو بلانا ضروری ہے، جس کے بعد ایک بار کے لیے کال بیک کا اجازت نامہ حاصل ہوتا ہے، اور unlockCallback() میں مخصوص عمل مکمل کیا جاتا ہے۔ پورے عمل کے ختم ہونے پر، PoolManager چیک کرتا ہے کہ کیا لیجر متوازن ہے:

jab NonzeroDeltaCount != 0 ہو تو فوری طور پر revert کر دیں، یہ v4 فلیش اکاؤنٹنگ کا بنیادی پابندی ہے۔ کوئی بھی Hook اپنے عمل کے دوران اکاؤنٹ کو عدم توازن میں ڈال سکتا ہے، لیکن ٹریڈ کے ختم ہونے سے پہلے اسے خود settle کرنا ہوگا، ورنہ پوری ٹریڈ منسوخ ہو جائے گی۔
ہر پول PoolKey سٹرکچر سے منفرد طور پر شناخت کیا جاتا ہے، جس میں hooks فیلڈ شامل ہے:

PoolId keccak256(PoolKey) کے ذریعے حساب لگایا جاتا ہے، اس لیے مختلف hooks کے پتے مختلف پولز کا باعث بنتے ہیں۔ اس کا مطلب یہ بھی ہے کہ PoolManager کوئی جانچ نہیں کرتا کہ کیا کوئی Hook پتا پہلے کسی اور پول کے لیے استعمال ہوا ہے، ایک ہی Hook معاہدہ متعدد پولز کے ساتھ одно وقت منسلک ہو سکتا ہے۔

2.2 ہُک اجازت بٹ کوڈنگ پتے میں
v4 کا ایک غیر متوقع ڈیزائن یہ ہے کہ ہُک کی اجازت کسی کنٹریکٹ کے اندر کے کسی متغیر سے نہیں، بلکہ ہُک کنٹریکٹ کے ڈپلوی منبع ایڈریس سے طے ہوتی ہے۔
PoolManager، ہک ایڈریس کے کم 14 بٹس کو چیک کرکے فیصلہ کرتا ہے کہ کیا ہک کو کسی زندگی کے مرحلے پر بلایا جانا چاہیے:

مثلاً BEFORE_SWAP_FLAG = 1 << 7۔ اگر ہُک ایڈریس کا 7ویں بٹ 1 ہے، تو PoolManager swap سے پہلے اس ہُک کی beforeSwap() فنکشن کو کال کرے گا؛ ورنہ، چاہے ہُک کنٹریکٹ beforeSwap() کو کیسے بھی لاگو کرے، PoolManager کبھی بھی اسے کال نہیں کرے گا۔
اس کا مطلب یہ ہے کہ Hook کو ڈیپلوی کرتے وقت CREATE2 + salt کے ذریعے ایڈریس کو کیلکولیٹ کرنا ہوگا تاکہ ایک ایسا ایڈریس بنایا جا سکے جس کے کم بٹس مقصد کے اجازت نامے کے مکمل طور پر مطابق ہوں۔ Uniswap کی طرف سے اس مقصد کے لیے HookMiner ٹول دستیاب ہے:

jab اجازت کے بٹس اور فنکشن کی ت実یت میں عدم مطابقت ہو تو دو قسم کے مسائل پیدا ہوتے ہیں:
(1) کسی ہوک فنکشن کو لاگو کیا گیا، لیکن ایڈریس کو متعلقہ اجازت بٹس کے ساتھ اینکوڈ نہیں کیا گیا — PoolManager کبھی بھی اس فنکشن کو کال نہیں کرے گا، منطق بے معنی ہے
(2) پتہ میں کسی اجازت بٹ کو کوڈ کیا گیا ہے، لیکن ہُک نے متعلقہ فنکشن کو نہیں لاگو کیا ہے — PoolManager کال بیک کے دوران ریورٹ ہو سکتا ہے، جس سے DOS حملہ یا ریٹرن ویلیو چیک فیل ہو سکتا ہے، جس کی وجہ سے متعلقہ آپریشنز نہیں چل سکتے۔
یہ одноں ہوک کے اپگریڈ کا قدرتی رکاوٹ بھی ہے: اگر ہوک کو پروکسی کے ذریعے اپگریڈ کیا جا سکتا ہے، تو ڈیپلومنٹ ایڈریس اپگریڈ کے دوران نہیں بدلتا، اس لیے اپگریڈ کے بعد صرف موجودہ ہوک فنکشنز کے عمل کو تبدیل کیا جا سکتا ہے، نئے ہوک قسمیں شامل نہیں کی جا سکتیں۔ مستقبل کی توسیع کے لیے، ابتدائی ڈیپلومنٹ کے دوران تمام ممکنہ اجازت بٹس پہلے سے تیار کر لینے چاہئیں۔
2.3 BaseHook اور ایک عام طور پر نظر انداز کیا جانے والا ایکسیس کنٹرول کا شکار
یونیسواپ v4 پیرفیری کی قدیمی ورژن کی فراہم کردہ BaseHook ایبستریکٹ کنٹریکٹ، جسے ڈویلپرز اپنے مخصوص ہُک کو لاگو کرنے کے لیے ورثہ دے سکتے ہیں۔ BaseHook کا ایک اہم کردار unlockCallback() فنکشن کے لیے onlyPoolManager مودیفائر فراہم کرنا ہے:

لیکن — یہاں ایک بہت آسانی سے نظرانداز کیا جانے والا ڈیزائن جال ہے — BaseHook کے ابتدائی ورژن نے صرف unlockCallback کے لیے onlyPoolManager شامل کیا تھا، دیگر ہوک کال بیکس (beforeSwap، afterSwap، beforeAddLiquidity وغیرہ) کے لیے کوئی حفاظت نہیں تھی۔ ان فنکشنز کا ایکسیس کنٹرول ہوک ڈویلپر کو خود ظاہر طور پر شامل کرنا ہوگا۔
3. ہُک کے زندگی کے دوران کوڈ کا جائزہ
ایک exact-input swap کے مثال کے ساتھ، صارف کی طرف سے ٹریڈ شروع کرنے سے لے کر سیٹلمنٹ تک مکمل کال اسٹیک کا تجزیہ کیا جاتا ہے۔
3.1 پول کی ابتدائی ترتیب اور ہوک کا بندھنا
کوئی بھی PoolManager.initialize() کو بلा سکتا ہے تاکہ نیا پول بنایا جا سکے:

isValidHookAddress صرف ایڈریس کے اجازت بٹ اور فی فیلڈ کی مطابقت کی جانچ کرتا ہے، یہ یہ نہیں جانچتا کہ Hook پہلے سے کسی اور پول میں استعمال ہو چکا ہے یا نہیں، اور نہ ہی یہ جانچتا کہ کیا یہ Hook اس PoolKey کو قبول کرنے کے لیے تیار ہے۔ اگر Hook کے ڈیزائن میں beforeInitialize میں وائٹ لسٹ یا اکیلے پول بندھن منطق شامل نہیں کیا گیا ہے، تو کوئی بھی ایک نیا پول بناسکتا ہے جس میں وہی Hook استعمال ہو لیکن token pair کسی بھی قسم کا ہو، اور اس سے Hook کے تمام بعد کے کال بیکس فعال ہو سکتے ہیں۔
3.2 beforeSwap اور BeforeSwapDelta
سواپ پروسیجر کا انٹری پوائنٹ PoolManager.swap() ہے، جو مرکزی سواپ منطق کو انجام دینے سے پہلے Hooks.beforeSwap() کو کال کرتا ہے:

beforeSwap کا رجوعی اقدار ایک تہہ (bytes4, BeforeSwapDelta, uint24) ہے:
- bytes4: IHooks.beforeSwap.selector کے برابر ہونا چاہیے، ورنہ PoolManager فوراً revert کر دے گا
- BeforeSwapDelta: ہُک اس سویپ میں مخصوص ٹوکن اور غیر مخصوص ٹوکن کے ڈیلٹا ایڈجسٹمنٹس کو تبدیل کرتا ہے
- uint24: ڈائنامک LP فیس ریٹ کا کوریج ویلیو (صرف اس صورت میں جب پول میں ڈائنامک فیس سرگرم ہو)
BeforeSwapDelta ایک int256 کا مترادف ہے، جس کے اعلیٰ 128 بٹ specified token کا delta (یعنی صارف کی طرف سے مخصوص مقدار والے ٹوکن) کو ظاہر کرتے ہیں، اور کم 128 بٹ unspecified token کا delta ظاہر کرتے ہیں:

توجه دہید کہ BeforeSwapDelta کا مطلب یہ ہے کہ Hook کو فیس وصول کرنے پر مثبت قیمت واپس کرنی چاہیے اور ٹوکن واپس کرنے پر منفی قیمت۔ ڈویلپرز آسانی سے علامت کو الٹ دیتے ہیں؛ ساتھ ہی، specified اور unspecified کا تعلق params.zeroForOne اور amountSpecified کے علامت پر منحصر ہے، جس کی تحریر میں تھوڑی سی غلطی سے ٹوکن کا غلط ترتیب ہو جاتا ہے۔
پول مینیجر beforeSwap کی طرف سے واپس کیا گیا specifiedDelta کو amountToSwap پر براہ راست جمع کر دے گا:

اس لائن میں ایک اہم مفہوم پوشیدہ ہے: ہُک swap کی رقم کو روک سکتا ہے۔ جب hookDeltaSpecified، -params.amountSpecified کے برابر ہو، تو amountToSwap فوراً صفر ہو جاتا ہے، جس سے ہُک پورے swap پر مکمل کنٹرول حاصل کر لیتا ہے—یہی Async Hook یا Custom Curve Hook کہلاتا ہے۔
Async Hook v4 میں سب سے زیادہ خطرناک ڈیزائن پیٹرن ہے: یہ بنیادی طور پر Uniswap کے swap منطق کو اپنے ہی Hook منطق سے تبدیل کرتا ہے۔ اگر Hook میں کوئی خامی ہے یا یہ خود بخود بری نیت کا ہے، تو صارفین کے فنڈز Uniswap کے اصل قیمت تعیناتی منطق کے تحت نہیں رہیں گے، بلکہ ان کی مکمل طور پر Hook کے اپنے عمل کی درستگی پر منحصر ہوں گے۔
3.3 ڈیلٹا سیٹلمنٹ اور NonzeroDeltaCount
beforeSwap اور afterSwap کی طرف سے واپس کیا گیا delta فوری طور پر ٹرانسفر نہیں ہوتا، بلکہ PoolManager کے اندری لیجر میں ریکارڈ کر دیا جاتا ہے:

جب کسی ٹوکن کا جمع ڈیلٹا صفر سے غیر صفر ہو جائے، تو NonzeroDeltaCount بڑھ جاتا ہے؛ جب صفر پر واپس آ جائے، تو کم ہو جاتا ہے۔ جیسا کہ 2.1 میں بیان کیا گیا ہے، اگر unlock() کے ختم ہونے پر NonzeroDeltaCount != 0 ہے، تو پورا ٹرانزیکشن revert ہو جائے گا۔
ہوک اپنا ڈیلٹا settle() (PoolManager کو ٹرانسفر کرکے) اور take() (PoolManager سے نکال کر) کے ذریعے متوازن کرتا ہے:

اس مکینزم کے ذریعے حاصل ہونے والا سیکیورٹی مفہوم واضح ہے: تمام صارفین کو آخرکار اپنا اکاؤنٹ بند کرنا ہوگا۔ لیکن یہ صرف "اکاؤنٹ کا توازن" یقینی بناتا ہے، "اکاؤنٹ کی درستگی" نہیں۔ اگر Hook beforeSwap میں ایک بدسلوکی سے تیار کیا گیا delta واپس کرے، تو PoolManager اس delta کو بھروسہ کرتے ہوئے درست طریقے سے ریکارڈ کر دے گا، اور جب تک آخر میں settle ہو جائے، ٹریڈ کامیاب ہو جائے گی—حتیٰ کہ اس کا مطلب ہو سکتا ہے کہ Hook جھوٹے بزنس اسٹیٹس کے ذریعے سسٹم کو یہ غلط خیال دے دے کہ حملہ آور کے پاس کچھ اثاثوں کے حقوق ہیں، جبکہ PoolManager اس بزنس لیول کی غلطی کو نہیں پہچان سکتا۔
پہلے کورک پروٹوکول کی سیکیورٹی واقعہ اس کے ہوک میں خامی کی وجہ سے ہوا، اور حملے سے پہلے اسے چار آڈٹ کمپنیوں نے جانچ لیا تھا۔ واقعہ کے بعد جائزہ لینے پر ہم نے پایا:
چار میں سے تین آڈٹ میں کورکہوک کنٹریکٹ کا دائرہ کار شamil نہیں ہے
CorkHook کا صرف ایک ہی آڈٹ کیا گیا، جس نے کچھ کوڈ کے مسائل کی شناخت کی اور بہتری کے تجاویز پیش کیے، لیکن ایکسیس کنٹرول کے مسائل تک مکمل طور پر نہیں پہنچا۔
ایک اور آڈیٹر نے اپنی رپورٹ میں واضح طور پر تجویز کی ہے: "ایک دلچسپ مزید معاہدہ یہ ہوگا کہ کورکہوک فنکشنز کے لیے انویرینٹس ثابت کیے جائیں جن کا استعمال اس معاہدے کے دائرہ کار میں تصدیق شدہ مختلف کمپوننٹس کے ذریعے کیا جاتا ہے۔" اس تجویز کا پس منظر میں جائزہ لینے پر بہت زیادہ مربوط ہونے کا ثبوت ہے۔
یہ v4 ہُک کے دور کی ایک نئی آڈٹ کی خلا کو ظاہر کرتا ہے: پروٹوکول کی پیچیدگی کا تیزی سے بڑھنا scope کے تعین کو ایک سیکیورٹی فیصلہ بناتا ہے۔ ہُک اور پروٹوکول کے دیگر معاہدوں کے درمیان تفاعل کا سلسلہ بہت لمبا ہوتا ہے؛ صرف ہُک کنٹریکٹ کا آڈٹ کرنا کراس-کنٹریکٹ کے ترکیبی مسائل کو دریافت نہیں کر سکتا؛ اور اس کے برعکس، اگر آپ گھیرے کے باہر ہُک کو چھوڑ دیں تو v4 دور کا سب سے بڑا حملے کا نقطہ نظر چھوٹ جائے گا۔
4. تفکر
پروٹوکول میکانزم اور کورک حملے کو ایک ساتھ جانچنے سے، v4 Hook سیکورٹی ماڈل کے کچھ مرکزی نکات قائم ہوتے ہیں:
(1) اگر Hook کال بیک فنکشن PoolManager کی فراہم کردہ کال کنٹیکس پر منحصر ہے، تو اسے صرف PoolManager کے ذریعے ہی کال کیے جانے کے لیے واضح طور پر محدود کیا جانا چاہیے۔ BaseHook ڈویلپر کے لیے یہ کام نہیں کرے گا، یہ v4 اور عام کنٹریکٹ اڈٹ کے تجربے کے درمیان سب سے زیادہ تنازعہ پیدا کرنے والا ڈیزائن جال ہے۔
(2) ہُک اور پول کے درمیان کنکشن PoolManager کے تحت نہیں ہوتا۔ ڈیولپرز کو beforeInitialize میں پول وائٹ لسٹ یا ایکل پول بائنڈنگ خود ایمپلیمنٹ کرنا ہوگا۔
(3) ہُک ایڈریس کے اجازت بٹس کو فنکشن کی تکمیل کے ساتھ سختی سے مطابقت رکھنا چاہیے۔ حساب لگائے گئے ایڈریس میں مستقبل میں ممکنہ طور پر توسیع کے لیے تمام اجازت بٹس پہلے سے شamil کر لینے چاہئیں
(4) Async / Custom Curve Hook بنیادی طور پر مکمل طور پر کسٹمائز ڈیل کرنے کا ایک ایمپلیمنٹیشن ہے۔ اس میں Uniswap پروٹوکول کے کسی بھی سطح پر حفاظت نہیں ہے، اور اسے "مکمل خودمختار فنانشل کنٹریکٹ" کے معیار کے مطابق آڈٹ کیا جانا چاہیے۔
(5) ڈیلٹا اکاؤنٹنگ کا "برقرار رکھنا" "درست" کے برابر نہیں ہے۔ NonzeroDeltaCount == 0 صرف یہ یقینی بناتا ہے کہ اکاؤنٹنگ آخرکار متوازن ہے، لیکن یہ یقینی نہیں بناتا کہ اکاؤنٹنگ کا مواد بے ایمانی سے مانیپولیٹ نہیں ہوا۔
(6) کراس مارکیٹ ٹوکن قسم کا اشتباه v4 کے دور کا ایک نیا حملے کا نقطہ ہے۔ جب پروٹوکول صارفین کو مارکیٹ بنانے کی اجازت دے، تو ٹوکن کی معنائی تصدیق ضروری ہے، صرف انٹرفیس چیک پر انحصار نہیں کیا جانا چاہئے
ہر ہُک ایک الگ اعتماد کا علاقہ ہے، اور ہر پول کی سلامتی اس کے منسلک ہُک پر منحصر ہے۔ اس لیے ہُک کی سلامتی کی جانچ کی پیچیدگی اب “ایک کوڈ کی جانچ” نہیں بلکہ “ایک مکمل ذیلی پروٹوکول کی جانچ” بن گئی ہے — یہ تبدیلی منصوبہ ساز اور جانچنے والے دونوں کے لیے طریقہ کار میں ترقی کا مطلب رکھتی ہے۔

