Hook: Một dòng code thừa
Trong 72 giờ qua, một giao thức DeFi mới tên YieldSweep đã mất 340 ETH – tương đương $1.2 triệu – chỉ vì một hook trong Uniswap V4. Tôi đã dành 3 ngày để đọc mã nguồn của chúng, và phát hiện ra điều mà đội ngũ phát triển bỏ qua: họ implement callback afterSwap() với một lời gọi external không được bảo vệ. Kết quả? Một kẻ tấn công đã gọi lại hàm swap() từ trong callback, tạo ra vòng lặp vô hạn rút thanh khoản. EVM không tha thứ cho sự cẩu thả.
Context: Uniswap V4 và "Lego có thể lập trình"
Uniswap V4 giới thiệu khái niệm hook – những contract nhỏ được gọi tại các điểm cụ thể trong lifecycle của swap (beforeSwap, afterSwap, beforeAddLiquidity, afterAddLiquidity…). Ý tưởng rất đẹp: cho phép các nhà phát triển tùy chỉnh hành vi pool, từ fee động đến rebalance tự động. Nhưng như mọi công cụ mạnh, hook biến DEX thành Lego có thể lập trình – và mức độ phức tạp tăng vọt sẽ làm 90% developer nản lòng. YieldSweep là một case study điển hình: họ muốn tạo một pool "sweep yield" tự động chuyển lợi nhuận sang pool khác, và đã viết hook afterSwap() để gọi hàm collectFees() trên một contract bên ngoài.
Vấn đề? Họ quên mất nguyên tắc checks-effects-interactions. Họ gọi external contract trước khi cập nhật trạng thái balance của pool. Đó là một lỗ hổng reentrancy kinh điển, nhưng trong bối cảnh hook, nó còn nguy hiểm hơn vì hook có thể gọi lại chính pool.
Core: Phân tích cấp code – Nơi mọi thứ sụp đổ
Tôi sẽ mổ xẻ logic chính. Dưới đây là pseudocode của hook YieldSweep: