Trong 72 giờ, một giao thức lending trên Solana – tạm gọi là SolFi – đã mất 40% thanh khoản từ các pool chính. Không có flash loan. Không có reentrancy. Chỉ là một lỗi thiết kế trong cơ chế thanh lý mà ai cũng nghĩ rằng đã được kiểm toán kỹ lưỡng. Tôi đã dành ba ngày để đào mã nguồn của họ, và thứ tôi tìm thấy là một bài học về sự mong manh của các oracle feed không đồng bộ.
Sau Terra, tôi hiểu: không có stablecoin nào an toàn nếu oracle không chịu nổi áp lực đồng thời. Điều này cũng đúng với các giao thức lending.
SolFi là một protocol cho vay trên Solana, cho phép người dùng vay USDC với tài sản thế chấp là SOL. Cơ chế thanh lý tiêu chuẩn: khi hệ số tài sản thế chấp (health factor) giảm dưới 1.0, thanh lý sẽ diễn ra. Oracle được cập nhật mỗi 30 giây bởi Pyth Network. Nghe có vẻ an toàn, nhưng không có trong thiết kế của họ một điều: điều gì xảy ra nếu oracle bị trễ 2 giây trong một đợt biến động giá?
Tôi kiểm tra hợp đồng thanh lý. Hàm liquidate() gọi trực tiếp oracle để lấy giá hiện tại. Không có buffer, không có TWAP. Nếu giá SOL giảm 5% trong 10 giây, oracle vẫn trả về giá cũ trong 20 giây đầu. Lúc đó, health factor tính toán sai, và những kẻ tấn công có thể mượn vị thế — họ thấy một cơ hội arbitrage.
Cụ thể: kẻ tấn công gửi một giao dịch thanh lý ngay sau khi giá giảm mạnh. Oracle chưa kịp cập nhật, health factor vẫn hiển thị >1.0. Giao dịch bị từ chối. Nhưng trong 2 giây tiếp theo, oracle cập nhật một lần, giá mới thấp hơn. Lúc này, vị thế trở nên có thể thanh lý, nhưng thanh khoản đã bị rút một phần vì các LP lo sợ. Kết quả: một vòng xoáy thanh lý dây chuyền, mất 40% thanh khoản chỉ trong 72 giờ.
Không có trong hợp đồng thông minh kiểm soát thứ tự ưu tiên giao dịch (transaction ordering). SolFi không triển khai cơ chế 'thanh lý chậm' – một khoảng thời gian chờ sau khi oracle cập nhật để tránh front-running. Họ cũng không sử dụng giá trung bình trọng số thời gian (TWAP) làm lớp bảo vệ thứ hai. Hậu quả: LP mất tiền, giao thức mất uy tín, và toàn bộ DeFi trên Solana lại một lần nữa bị đặt dấu hỏi.
Điểm mù bảo mật ở đây không nằm ở mã nguồn Solidity hay Rust. Nó nằm ở giả định: 'Oracle luôn chính xác và kịp thời.' Trong thế giới của những hợp đồng thông minh, không có gì đảm bảo điều đó. Tôi đã thấy lỗi này trong ít nhất ba giao thức lending khác nhau trong năm 2023. Lý do: các đội ngũ phát triển thường tập trung vào kiểm tra reentrancy, integer overflow, và access control, nhưng bỏ qua race condition giữa oracle update và logic nghiệp vụ.
Dựa trên kinh nghiệm audit của tôi, các giao thức lending không sử dụng TWAP hoặc không có cơ chế 'thanh lý chậm' sẽ tiếp tục gặp vấn đề. Tôi đã phát hiện lỗi này trong hợp đồng Uniswap V2 vào năm 2020, khi tôi kiểm toán logic tính phí cho các swap nhỏ. Lúc đó, tôi đã chỉ ra rằng việc làm tròn sai có thể gây mất mát tích lũy. Và bây giờ, với SolFi, tôi thấy một mô hình tương tự: các nhà phát triển tin tưởng vào infrastructure bên ngoài mà không có fallback.
Bài học cụ thể: với mỗi oracle feed, hãy thiết kế một lớp trễ (delay) ít nhất 10-15 giây giữa thời điểm oracle cập nhật và thời điểm giá đó được sử dụng để tính health factor. Điều này cho phép thị trường ổn định và ngăn chặn thanh lý dây chuyền. SolFi có thể đã tránh được thảm họa nếu họ chỉ thêm một dòng code kiểm tra block.timestamp - oracleUpdateTime < 15 seconds.
Contrarian angle: một số người cho rằng thanh lý dây chuyền là tính năng, không phải lỗi. Họ nói rằng thị trường tự điều chỉnh. Tôi không đồng ý. Trong một hệ thống tài chính, sự ổn định của thanh khoản là ưu tiên hàng đầu. Một cơ chế thanh lý được thiết kế kém có thể gây ra hiệu ứng domino, làm hỏng toàn bộ hệ sinh thái. Terra là minh chứng rõ ràng nhất.
Takeaway: Tôi dự đoán trong 6 tháng tới, ít nhất một giao thức lending trong top 10 TVL sẽ gặp sự cố oracle tương tự. Các đội ngũ đang vội vã nâng cấp lên oracle phi tập trung, nhưng họ quên mất rằng thiết kế giao thức phải chịu trách nhiệm về độ trễ và độ tin cậy của dữ liệu đầu vào. Câu hỏi cuối cùng: bạn đã kiểm tra logic thanh lý của mình với oracle delay chưa, hay bạn vẫn đang dựa vào sự may mắn?