Giới thiệu
Khi hệ sinh thái tài chính phi tập trung (DeFi) phát triển nhanh chóng, AAVE V2, với tư cách là một trong những giao thức cho vay phi tập trung hàng đầu, vẫn đi đầu trong ngành trong việc cung cấp các giải pháp quản lý thanh khoản và cho vay sáng tạo. Cơ chế không cần tin cậy độc đáo và việc sử dụng vốn hiệu quả đã thu hút sự tham gia của đông đảo người dùng và tổ chức. Tuy nhiên, với việc ứng dụng ngày càng phổ biến và quy mô quỹ liên quan ngày càng mở rộng, tầm quan trọng của các cuộc kiểm toán an ninh và các biện pháp kiểm soát rủi ro ngày càng trở nên nổi bật. Sổ tay hướng dẫn này sẽ khám phá sâu hơn về thiết kế cốt lõi, các chức năng chính và các điểm kiểm tra liên quan của giao thức AAVE V2.
Tổng quan về dự án
AAVE V2 là một nền tảng cho vay mở được xây dựng trên blockchain Ethereum cho phép người dùng gửi nhiều loại token ERC-20 khác nhau và kiếm lãi từ chúng, đồng thời cho phép người dùng vay token trên thị trường dưới dạng thanh toán lãi. Bằng cách giới thiệu khái niệm "thị trường lãi suất", AAVE V2 hiện thực hóa việc quản lý quỹ phi tập trung và cơ chế điều chỉnh lãi suất tự động. Ngoài ra, AAVE V2 còn cung cấp các tính năng nâng cao như cho vay nhanh, thế chấp và hoán đổi mã thông báo để đáp ứng nhu cầu đa dạng của người dùng, củng cố thêm vị thế dẫn đầu trong lĩnh vực DeFi.
Phân tích kiến trúc dự án

Thiết kế kiến trúc tổng thể của AAVE V2 xoay quanh các chức năng chính như người dùng, quản lý dòng vốn, cơ chế thế chấp, quy trình thanh lý và chiến lược lãi suất, nhằm mục đích cung cấp các dịch vụ cho vay phi tập trung hiệu quả và an toàn. Sau đây là phân tích toàn diện:
Quy trình vận hành của người dùng
Người dùng:Người dùng có thể thực hiện nhiều hoạt động khác nhau như gửi tiền, cho vay, trả nợ, rút tiền, trao đổi mô hình lãi suất cho vay, cho vay nhanh và tín dụng ủy thác. Khi người dùng tương tác với giao thức, aToken tương ứng sẽ tự động được đúc hoặc hủy dựa trên hoạt động của họ, thể hiện quyền ký quỹ của họ trong giao thức và họ nhận được lợi nhuận dựa trên chiến lược lãi suất.
Tín dụng được ủy quyền: Người dùng có thể ủy quyền hạn mức tín dụng của mình cho người dùng khác, mở rộng tính linh hoạt và khả năng sử dụng của giao thức.
Thành phần cốt lõi
LendingPool: Là mô-đun cốt lõi, mô-đun này chịu trách nhiệm xử lý mọi yêu cầu hoạt động của người dùng, bao gồm tiền gửi, vay, trả nợ, trao đổi mô hình lãi suất cho vay, cho vay nhanh và thanh lý, cũng như cập nhật lãi suất và trạng thái.
Quản lý tài sản thế chấp:Quản lý tài sản thế chấp để đảm bảo hành vi vay của người dùng là an toàn và có thể kiểm soát được. Khi tài sản thế chấp không đủ, quá trình thanh lý sẽ được kích hoạt để bảo vệ tính thanh khoản chung của hệ thống.
Thư viện: Bao gồm logic tiết kiệm, logic xác minh và logic chức năng chung, chẳng hạn như tính toán hoạt động thanh lý và cho vay, để hỗ trợ cho LendingPool.
GenericLogic tính toán và xác minh trạng thái của người dùng, bao gồm đánh giá tài sản, tính toán giá trị tài sản thế chấp, hệ số sức khỏe và các hoạt động khác.
ReserveLogic được sử dụng để quản lý nhóm dự trữ, theo dõi và cập nhật số tiền gửi, số tiền vay và lãi suất hiện tại của từng tài sản.
ValidationLogic chịu trách nhiệm xác minh xem hoạt động của người dùng có tuân thủ các quy tắc giao thức hay không và kiểm tra chặt chẽ tài sản thế chấp và nghĩa vụ khi người dùng gửi tiền, vay, trả nợ, thanh lý, cho vay nhanh, chuyển đổi chế độ nợ, v.v.
Nợ và mã hóa
Mã hóa nợ:Được sử dụng để theo dõi nghĩa vụ vay nợ của người dùng, 1:1 với số tiền đã vay. Mã thông báo nợ có các tùy chọn lãi suất cố định và thay đổi (như DebtDAI ổn định, DebtDAI thay đổi, v.v.) và mã thông báo nợ không thể chuyển nhượng.
aToken: Khi người dùng gửi tài sản, aToken 1:1 sẽ được tạo ra để neo giữ tài sản cơ bản. Các aToken này sẽ tiếp tục tăng giá để phản ánh lãi suất kiếm được từ các khoản tiền gửi. Số tiền được đưa vào đây sẽ được lưu trữ cùng với số dư gốc theo tỷ lệ, gọi là số dư được chia tỷ lệ (ScB).
Công thức như sau:

Giá và lãi suất
Oracle Proxy:Dựa vào oracle bên ngoài (Chainlink) để cung cấp dữ liệu giá thị trường tài sản, được sử dụng để đánh giá giá trị tài sản thế chấp của người dùng và đảm bảo độ chính xác về giá của hành vi cho vay và tính ổn định của hệ thống.
Lending Rate Oracle: Cung cấp lãi suất cho vay năng động dựa trên trạng thái hệ thống và điều kiện thị trường để tối ưu hóa việc sử dụng vốn và thanh khoản.
Cấu hình và quản lý
Trình cấu hình:Được sử dụng để cấu hình các tham số hệ thống, chẳng hạn như tham số rủi ro và giới hạn cho vay đối với các tài sản khác nhau và quản lý nhiều hoạt động khác nhau của quỹ dự trữ, bao gồm kích hoạt, vay, thế chấp, đóng băng, cập nhật tham số và bật hoặc tắt các chức năng trong các tình huống khẩn cấp. Đảm bảo rằng thỏa thuận có thể được điều chỉnh linh hoạt theo những thay đổi của thị trường.
Các chức năng chính khác
Trình quản lý thanh lý:Khi giá trị tài sản thế chấp của người dùng giảm xuống dưới ngưỡng thanh lý, hãy quản lý các hoạt động thanh lý và bảo vệ an ninh tài chính của hệ thống. Người thanh lý có thể nhận được phần thưởng thông qua hoạt động thanh lý.
Số dư dự trữ:Lưu trữ dữ liệu quỹ dự trữ của hệ thống, được sử dụng để tính toán và điều chỉnh các chiến lược lãi suất.
Chiến lược lãi suất
Chiến lược lãi suất:Điều chỉnh linh hoạt lãi suất để đạt được phân bổ vốn tối ưu dựa trên nhu cầu của thị trường và người dùng, đồng thời cân nhắc đến rủi ro thanh khoản để đảm bảo tính linh hoạt và ổn định của hệ thống trong các điều kiện thị trường khác nhau.
Mặc dù có hai mô hình lãi suất (ổn định và thả nổi), nhưng cách tính toán mô hình của chúng lại tương tự như mô hình điểm uốn. Độ dốc 1 theo tỷ lệ sử dụng tối ưu tại điểm uốn và độ dốc 2 vượt quá tỷ lệ sử dụng tối ưu được tính theo từng phần và theo điều kiện này, chúng cũng được chia thành mô hình lãi suất cố định và mô hình lãi suất thả nổi.

Công thức như sau:



Hiểu quy trình
Gửi tiền
Người dùng gọi Chức năng gửi tiền của hợp đồng LendingPool được sử dụng để gửi tiền. Chức năng này chấp nhận bốn tham số: địa chỉ tài sản, số tiền gửi, địa chỉ người nhận và mã giới thiệu. Trước tiên, hãy xác minh rằng hợp đồng không ở trạng thái đã bật, sau đó xác minh rằng số tiền ký quỹ phải lớn hơn 0 thông qua ValidationLogic.validateDeposit và xác nhận rằng khoản dự trữ đang hoạt động và không bị đóng băng. Sau đó, hệ thống sẽ cập nhật trạng thái dự trữ, gọi reserve.updateState() để cập nhật chỉ số tích lũy thanh khoản và chỉ số vay biến đổi, đồng thời tính toán lãi suất phát sinh trong khoảng thời gian đó, một phần trong số đó sẽ được đúc và chuyển vào kho bạc giao thức.
Công thức như sau:

Sau đó, reserve.updateInterestRates được sử dụng để điều chỉnh động lãi suất thanh khoản, lãi suất vay ổn định và lãi suất vay biến động theo mối quan hệ cung cầu mới nhất (tất cả đều được tính toán và cập nhật bởi hàm DefaultReserveInterestRateStrategy.calculateInterestRates). Trong giai đoạn chuyển giao tài sản, hệ thống sẽ chuyển tài sản cơ bản của người dùng vào hợp đồng aToken và đồng thời đúc một lượng aToken tương đương vào địa chỉ onBehalfOf do người dùng gửi. Trong số đó, aToken áp dụng cơ chế mở rộng quy mô (số dư theo tỷ lệ) để xử lý việc tích lũy lãi suất. Nếu đây là khoản tiền gửi đầu tiên của người dùng, hệ thống sẽ tự động đánh dấu tài sản là tài sản thế chấp của người dùng.
So với Compound, quy trình gửi tiền của AAVE V2 có các tính năng chính sau:
Hỗ trợ chỉ định địa chỉ người nhận (onBehalfOf).
Xác minh khoản tiền gửi được thực hiện thông qua hợp đồng ValidationLogic.
Cập nhật chỉ số tích lũy thanh khoản và chỉ số vay biến đổi để tính toán và phân bổ lãi suất trái phiếu kho bạc theo thỏa thuận.
Điều chỉnh đồng thời ba mức lãi suất thanh khoản, lãi suất vay ổn định và lãi suất vay thả nổi.
Sử dụng cơ chế cân bằng theo tỷ lệ của aToken để xử lý lãi suất.
Khoản tiền gửi đầu tiên sẽ tự động được đánh dấu là tài sản thế chấp.
Rút tiền
Người dùng rút tiền mặt bằng cách gọi hàm rút tiền. Đầu tiên, hãy lấy dữ liệu dự trữ của tài sản được chỉ định, bao gồm địa chỉ aToken tương ứng và kiểm tra số dư của người dùng này trong aToken. Tiếp theo, hãy gọi hàm ValidationLogic.validateWithdraw để xác thực yêu cầu rút tiền, bao gồm kiểm tra xem số tiền rút có hợp lệ không, số dư của người dùng có đủ không, tiền dự trữ có hoạt động không, v.v. GenericLogic.balanceDecreaseAllowed được sử dụng để kiểm tra yếu tố sức khỏe của người dùng và liệu việc rút tiền có ảnh hưởng đến tài sản thế chấp hay không, tương tự như hàm getHypotheticalAccountLiquidityInternal trong Compound. Trong hàm balanceDecreaseAllowed, các hàm calculateUserAccountData và calculateHealthFactorFromBalances tính toán ngưỡng thanh lý sau khi rút tiền và kiểm tra tổng tài sản thế chấp, tổng số tiền vay và hệ số sức khỏe hiện tại của người dùng để xác định xem hệ số sức khỏe của người dùng có ở trạng thái an toàn trong ngưỡng thanh khoản hay không.
Công thức tính HF như sau:

Sau đó, trạng thái của khoản dự trữ được cập nhật, lãi suất được cập nhật và số tiền rút được chuyển đến hàm. Nếu số tiền rút mà người dùng yêu cầu bằng với số dư hiện tại của họ, cấu hình của người dùng sẽ được cập nhật để đánh dấu khoản dự trữ không còn khả dụng để thế chấp. Cuối cùng, aToken của người dùng sẽ bị hủy và tài sản được rút sẽ được chuyển đến địa chỉ đã chỉ định.
So với Compound, quy trình rút tiền của AAVE V2 có các tính năng chính sau:
aToken được sử dụng để đại diện cho khoản tiền gửi của người dùng trong giao thức và việc rút tiền thực sự sẽ phá hủy aToken.
Cho phép người dùng rút tiền đến một địa chỉ cụ thể (thông qua tham số to), tăng tính linh hoạt.
Cung cấp tùy chọn rút một phần và rút toàn bộ.
Trong quá trình xác minh rút tiền, AAVE sử dụng hàm balanceDecreaseAllowed phức tạp hơn để kiểm tra tác động của việc rút tiền đối với trạng thái tài sản thế chấp chung của người dùng.
Quy trình rút tiền của AAVE cập nhật trực tiếp lãi suất thay vì cập nhật thông qua hàm accrueInterest như Compound.
Vay
Người dùng vay thông qua hàm loan. Khi thực hiện khoản vay, giá hiện tại của tài sản sẽ được lấy từ oracle giá và số tiền vay sẽ được chuyển đổi thành ETH tương đương. Sau đó, ValidationLogic.validateBorrow được kiểm tra và GenericLogic.calculateUserAccountData được sử dụng để kiểm tra xem khoản vay của người dùng có hợp pháp hay không. Tổng tài sản thế chấp, tổng nợ, tỷ lệ cho vay trên giá trị hiện tại (LTV), ngưỡng thanh lý và hệ số sức khỏe, và tính ổn định của thị trường của địa chỉ onBehalfOf được tính toán (tương tự như getHypotheticalAccountLiquidityInternal của Compound), để xem liệu có đủ tài sản thế chấp để vay hay không. reserve.updateState cập nhật trạng thái dự trữ, chẳng hạn như lãi suất và chỉ số vay (bước này tương tự như accrueInterest trong Compound), được sử dụng để tính toán và cập nhật lãi suất.
Sau đó, khoản nợ được tạo ra dựa trên interestRateMode (lãi suất ổn định hoặc lãi suất thả nổi) do người dùng lựa chọn và các hợp đồng mã thông báo với các mô hình lãi suất khác nhau được chọn để đúc mã thông báo. Đồng thời, một kiểm tra sẽ được thực hiện khi đúc token. Nếu địa chỉ onBehalfOf không phải là người gọi, quyền cho vay của địa chỉ này đối với người dùng gọi sẽ bị trừ khỏi hợp đồng token. Nếu đây là khoản vay đầu tiên của người dùng, họ sẽ được cấu hình là người vay đang hoạt động. Sau khi DebtToken được đúc cho người dùng, giao thức sẽ cập nhật lãi suất vay thông qua updateInterestRates để phản ánh lãi suất mới sau khi vay và những thay đổi trong nhóm dự trữ. Nếu người dùng yêu cầu giải phóng tài sản cơ bản của khoản vay, giao thức sẽ chuyển tài sản trực tiếp cho người dùng.
So với Compound, quy trình cho vay của AAVE V2 có những tính năng chính sau:
Hỗ trợ cả chế độ lãi suất ổn định và thả nổi.
Sử dụng hợp đồng logic xác minh riêng để xác minh khoản vay.
Sử dụng DebtToken để biểu diễn khoản vay của người dùng.
Hỗ trợ phân quyền tín dụng, cho phép người dùng vay thay mặt cho các địa chỉ khác.
Thanh toán
Người dùng thanh toán thông qua chức năng thanh toán, trước tiên lấy số nợ hiện tại của người dùng (bao gồm nợ ổn định stableDebt và nợ thả nổi variableDebt). Dựa trên chế độ lãi suất (ổn định hoặc thả nổi) do người dùng lựa chọn, ValidationLogic.validateRepay sẽ xác minh tính hợp pháp của hoạt động trả nợ của người dùng, bao gồm cả việc số dư nợ của người dùng có đủ để trả nợ hay không. Loại nợ cụ thể cần hoàn trả được xác định bởi mô hình lãi suất do người dùng lựa chọn (lãi suất ổn định hoặc lãi suất thả nổi). Nếu số tiền người dùng muốn trả ít hơn số dư nợ hiện tại, hệ thống sẽ sử dụng số tiền trả nợ do người dùng cung cấp để trả một phần; nếu không, toàn bộ khoản nợ sẽ được trả. Cập nhật trạng thái của updateState dự trữ, được sử dụng để tính toán và cập nhật lãi suất, số tiền cho vay và chỉ số cho vay trong giao thức. Các token nợ ổn định tương ứng sau đó sẽ bị đốt và lãi suất vay được cập nhật thông qua updateInterestRates. Tại thời điểm này, nếu tất cả các khoản nợ của người dùng (bao gồm cả nợ ổn định và nợ thả nổi) đều bằng 0 sau khi hoàn trả, trạng thái vay của người dùng sẽ được đánh dấu là sai, cho biết người dùng không còn vay nữa. Cuối cùng, người dùng chuyển số tiền hoàn trả từ tài khoản của mình đến địa chỉ hợp đồng aToken của giao thức.
So với Compound, quy trình hoàn trả của AAVE V2 có các tính năng chính sau:
Hỗ trợ hoàn trả theo cả chế độ lãi suất ổn định và thả nổi.
Sử dụng DebtToken để biểu diễn và quản lý nợ, đồng thời đốt mã thông báo nợ tương ứng khi trả nợ.
Hỗ trợ trả nợ một phần và trả nợ toàn bộ, xử lý riêng biệt nợ ổn định và nợ tạm thời.
Hỗ trợ người dùng trả nợ cho các địa chỉ khác thông qua việc ủy quyền tín dụng.
Thanh lý
Người dùng thực hiện thanh lý thông qua hàm liquidationCall của lendingpool. Hàm này gọi hàm liquidationCall của LendingPoolCollateralManager ở chế độ proxy để đảm bảo thực hiện thành công hàm. Đầu tiên, GenericLogic.calculateUserAccountData sẽ lấy dữ liệu dự trữ của tài sản thế chấp và tài sản nợ cũng như thông tin cấu hình của người dùng, tính toán hệ số sức khỏe của người dùng và lấy các khoản nợ ổn định và biến đổi hiện tại của người dùng thông qua getUserCurrentDebt.
Hàm ValidationLogic.validateLiquidationCall xác minh tính hợp pháp của lệnh thanh lý, bao gồm kiểm tra hệ số sức khỏe, tình trạng nợ và cấu hình tài sản thế chấp của người dùng. Nếu hệ số sức khỏe thấp hơn ngưỡng, hệ số này đã được sử dụng làm tài sản thế chấp và cả hai khoản nợ đều không bằng 0, thì xác minh được thông qua. Tiếp theo, số nợ thanh lý tối đa của người dùng được tính toán và số tiền nợ thực tế cần thanh lý sẽ được xác định. Nếu khoản nợ thanh lý vượt quá tài sản thế chấp khả dụng của người dùng, số tiền thanh lý sẽ được điều chỉnh.
Nếu bên thanh lý chọn nhận tài sản cơ sở do bên bị thanh lý thế chấp, cần phải đảm bảo có đủ thanh khoản trong dự trữ tài sản thế chấp. Cập nhật trạng thái dự trữ nợ và đốt số lượng token nợ biến đổi và ổn định tương ứng tùy thuộc vào việc người thanh lý có nhận được aToken hay không. Cập nhật lãi suất nợ để phản ánh tình hình thị trường sau khi thanh lý. Phần thưởng cho người thanh lý Nếu chọn nhận aToken, người thanh lý sẽ nhận được số lượng aToken tương ứng. Nếu aToken không được chấp nhận, trạng thái tài sản thế chấp và lãi suất của tài sản thế chấp sẽ được cập nhật, số lượng aToken tương ứng sẽ bị đốt khỏi tài khoản của người dùng và tài sản cơ sở sẽ được chuyển cho bên thanh lý. Cuối cùng, các tài sản nợ cần thiết để thanh lý sẽ được chuyển từ bên thanh lý sang aToken dự trữ tương ứng để hoàn tất quá trình thanh lý.
So với Compound, quy trình thanh lý của AAVE V2 có các tính năng chính sau:
Hỗ trợ thanh lý kết hợp nhiều tài sản thế chấp và tài sản nợ.
Người thanh lý được phép lựa chọn nhận aToken hoặc tài sản cơ bản.
Quy trình thanh lý mang tính mô-đun hơn, tách logic xác minh, logic tính toán, v.v. thành các chức năng khác nhau.
Hỗ trợ thanh lý hai loại nợ: lãi suất ổn định và lãi suất thả nổi.
Vay nhanh
Người dùng có thể thực hiện các khoản vay nhanh thông qua chức năng flashLoan của lendingpool. Với tư cách là khoản vay nhanh trong giao thức cho vay, bạn có thể cho phép khoản vay nhanh hiện tại được hoàn trả ngay lập tức hoặc như một khoản nợ để hoàn trả sau, được xác định bởi các tham số chế độ khác nhau được truyền vào. 0 nghĩa là trả nợ ngay lập tức, 1 nghĩa là nợ ổn định và 2 nghĩa là nợ thả nổi.
Đầu tiên, hàm sẽ kiểm tra sự khớp của tham số đầu vào thông qua ValidationLogic.validateFlashloan, tính toán chi phí bảo hiểm cần thiết cho khoản vay nhanh và chuyển trực tiếp aToken cần thiết đến địa chỉ người nhận. Gọi thao tác executeOperation của người nhận để triển khai khoản vay flash được cài đặt sẵn. Các hoạt động cho vay nhanh do AAVE triển khai bao gồm các hoạt động trao đổi, thanh lý trao đổi và trả nợ trao đổi. Sau khi executeOperation hoàn tất các hoạt động trên, nó sẽ ghi lại số tiền vay nhanh cần hoàn trả và các khoản phí tương ứng. Nếu người dùng chọn trả lại tiền ở chế độ không nợ: hệ thống sẽ cập nhật trạng thái dự trữ, tích lũy thanh khoản dự trữ và cập nhật chỉ số thanh khoản. Cuối cùng, tiền và phí được chuyển từ người yêu cầu vào quỹ dự trữ. Nếu người dùng chọn xử lý ở chế độ nợ, _executeBorrow sẽ được gọi để mở vị trí nợ tương ứng.
Chuyển đổi chế độ nợ
Trong AAVE V2, người dùng có thể chuyển đổi giữa chế độ lãi suất ổn định và chế độ lãi suất thả nổi thông qua hàm swapBorrowRateMode. Đầu tiên, lấy khoản nợ có lãi suất ổn định hiện tại và khoản nợ có lãi suất thả nổi của người dùng trên tài sản mục tiêu thông qua hàm getUserCurrentDebt để xác định trạng thái nợ của người dùng. Sau đó gọi hàm ValidationLogic.validateSwapRateMode để xác minh xem hoạt động chuyển đổi có hợp lệ hay không. Nó kiểm tra xem người dùng có đủ nợ ổn định hoặc nợ thả nổi để hỗ trợ chuyển đổi chế độ hay không, đảm bảo rằng chế độ mục tiêu phù hợp với cấu hình tài sản và tình hình nợ của người dùng. Gọi reserve.updateState để cập nhật trạng thái của tài sản dự trữ nhằm đảm bảo dữ liệu dự trữ được cập nhật. Bước tiếp theo là chuyển đổi hai token nợ thành nhau, đốt token nợ ổn định để đúc token nợ nổi hoặc đốt token nợ nổi để đúc token nợ ổn định. Sau khi quá trình chuyển đổi hoàn tất, reserve.updateInterestRates sẽ cập nhật lãi suất tài sản mục tiêu để đảm bảo rằng lãi suất này phản ánh tình trạng thị trường hiện tại và những thay đổi trong nợ của người dùng.
Danh sách kiểm tra lỗ hổng bảo mật
Làm tròn lỗ hổng do thị trường trống
Trong cả AAVE và Compound, đều có lỗ hổng do mất độ chính xác ở thị trường trống. Nếu có thị trường trống (tức là không có người dùng nào vay hoặc cho vay trên thị trường), vì giá trị của liquidIndex trong hàm cumulateToLiquidityIndex phụ thuộc vào số lượng token tài sản cơ bản tương ứng với hợp đồng, kẻ tấn công có thể thao túng giá của aToken bằng cách gửi một lượng lớn token tài sản cơ bản vào hợp đồng thông qua các khoản vay nhanh.
Tương tự như vụ hack đầu tiên của dự án fork Compound Hundred Finance, trong sự cố HopeLend, kẻ tấn công đầu tiên thao túng chỉ số thanh khoản để kiểm soát giá trị của hETHWBTC sang WBTC theo tỷ lệ 1:1, sau đó tăng giá trị của chỉ số thanh khoản bằng cách trao đổi tài sản cơ sở và vay mượn. Hàm _handleFlashLoanRepayment sau đó được gọi liên tục thông qua một vòng lặp các khoản vay nhanh. Trong hàm cumulateToLiquidityIndex, độ chính xác bị mất của rayDiv sẽ khuếch đại thêm giá trị của reserve.liquidityIndex và cuối cùng khuếch đại số lượng WBTC có thể được đổi. (Giao dịch tấn công: https://etherscan.io/tx/0x1a7ee0a7efc70ed7429edef069a1dd001fbff378748d91f17ab1876dc6d10392) Điểm kiểm toán: Trong quá trình kiểm toán, cần chú ý xem phương pháp tính tỷ giá hối đoái có dễ bị thao túng không và phương pháp làm tròn có phù hợp không. Đồng thời, có thể đề xuất nhóm dự án đúc aToken ngay sau khi thị trường mới được tạo để tránh thị trường bị bỏ trống và bị thao túng.
Lỗ hổng bảo mật có thể nhập lại do token ERC677/ERC777 gây ra
Tương tự như vụ hack thứ hai vào dự án Compound fork Hundred Finance, trong cuộc tấn công Agave, kẻ tấn công đã gọi hàm liquidateCall để tự thanh lý mà không phải chịu bất kỳ trách nhiệm pháp lý nào. Token thanh lý là token chuẩn ERC-677 được sử dụng trên Gnosis Chain. Khi chuyển loại token này, chức năng của địa chỉ nhận sẽ được gọi bên ngoài, do đó hợp đồng thanh lý gọi hợp đồng tấn công. Trong quá trình này, hợp đồng tấn công đã gửi 2728 WETH thu được thông qua các khoản vay flash, đúc 2728 aWETH và sử dụng số tiền này làm tài sản thế chấp để vay tất cả các tài sản có sẵn trong dự án Agave. Sau khi cuộc gọi bên ngoài kết thúc, hàm liquidationCall sẽ trực tiếp thanh lý 2728 aWETH mà kẻ tấn công đã gửi trước đó và chuyển cho người thanh lý.

(Nguồn tham khảo: https://x.com/danielvf/status/1503756428212936710; Giao dịch tấn công: https://gnosis.blockscout.com/tx/0xa262141abcf7c127b88b4042aee8bf601f4f3372c9471dbd75cb54e76524f18e)
Điểm kiểm tra: Trong quá trình kiểm tra, cần chú ý xem các mã liên quan của chức năng cho vay có tuân thủ thông số kỹ thuật CEI (Kiểm tra-Hiệu ứng-Tương tác) hay có khóa chống nhập lại hay không và cần xem xét tác động của các mã thông báo có chức năng gọi lại.
Rủi ro thao túng giá do cơ chế oracle không phù hợp
Trong vụ hack dự án Blizz Finance, do giá LUNA liên tục giảm mạnh tại thời điểm đó, thông tin giá Chainlink mà giao thức sử dụng trở nên không chính xác, dẫn đến khả năng vay vốn bằng tài sản thế chấp LUNA đắt đỏ. Đồng thời, dự án không có cơ chế an toàn nào hiện có và mặc dù các cảnh báo đã được đưa ra trước nhưng không có biện pháp phòng ngừa nào được đưa ra kịp thời để ngăn ngừa tổn thất. Khi giá giảm xuống dưới mức đó, bất kỳ ai cũng có thể mua một lượng lớn LUNA với giá thị trường (thấp hơn nhiều so với 0,10 đô la) và sử dụng nó làm tài sản thế chấp (trị giá 0,10 đô la) để vay tiền từ nền tảng.
(Nguồn tham khảo: https://x.com/BlizzFinance/status/1524911400992243761)
Điểm kiểm toán: Trong quá trình kiểm toán, cần chú ý xem cơ chế cung cấp giá của oracle dùng để tính giá trị tài sản thế chấp có dễ bị thế giới bên ngoài thao túng hay không. Có thể đề xuất bên dự án sử dụng nhiều nguồn giá để đánh giá toàn diện nhằm tránh rủi ro do một nguồn giá duy nhất gây ra. Đồng thời, cũng cần chú ý xem dự án có cơ chế tạm dừng hợp lý để phòng ngừa những trường hợp khẩn cấp như vậy hay không.
Các vấn đề bất ngờ phát sinh do các lệnh gọi bên ngoài tới hợp đồng ngoại vi
Trong quá trình tương tác giữa giao thức AAVE và giao thức Para Swap, hàm _buyOnParaSwap của hợp đồng Aave Collateral Repay Adapter V3 có nhiều rủi ro bảo mật. Hàm này đặt giới hạn của assetToSwapFrom thành maxAmountToSwap trên tokenTransferProxy bằng cách gọi phương thức safeApprove, nhưng không tính đến tình huống không thực hiện trao đổi hoặc trao đổi một phần, dẫn đến số tiền còn lại không thay đổi khi giới hạn không được sử dụng hết. Ngoài ra, chức năng này dựa vào lệnh gọi hợp đồng bên ngoài (augustus.call(buyCalldata)) để thực hiện trao đổi và không xác minh cũng như hạn chế đầy đủ tham số paraswapData, cho phép kẻ tấn công thao túng buyCalldata đã giải mã và địa chỉ hợp đồng augustus thông qua paraswapData được xây dựng độc hại, bỏ qua logic trao đổi dự định hoặc tránh trao đổi hoàn toàn. Vì chức năng này không giảm hoặc kiểm tra giới hạn mã thông báo của assetToSwapFrom sau khi hoán đổi, ngay cả khi hoán đổi không thành công hoặc bị bỏ qua, kẻ tấn công vẫn có thể sử dụng giới hạn cao không thay đổi để rút mã thông báo khỏi hợp đồng, do đó đạt được chuyển tiền trái phép. Việc thiếu xác thực dữ liệu đầu vào và kết quả trao đổi, cũng như không quản lý hiệu quả giới hạn mã thông báo đã khiến hợp đồng bị kẻ tấn công khai thác.

(Giao dịch tấn công: https://etherscan.io/tx/0xc27c3ec61c61309c9af35af062a834e0d6914f9352113617400577c0f2b0e9de)
Điểm kiểm tra: Trong quá trình kiểm tra, cần đặc biệt chú ý đến mã tương tác với các giao thức của bên thứ ba bên ngoài. Tập trung vào việc đánh giá xem đầu vào và đầu ra của hợp đồng bên ngoài có bị hạn chế nghiêm ngặt hay không, liệu logic tương tác có tác động tiềm ẩn đến mô hình cốt lõi của giao thức hay tính bảo mật của tiền hay không và liệu dữ liệu đầu vào có được làm sạch và xác minh để ngăn dữ liệu độc hại gây ra các vấn đề bảo mật hay không. Rủi ro của các lỗ hổng như vậy có thể được giảm thiểu hiệu quả bằng cách xem xét chặt chẽ logic mã của các tương tác bên ngoài và cơ chế xác minh dữ liệu.
Các vấn đề về khả năng tương thích giữa mã thông báo và chiến lược lãi suất
Trong quá trình triển khai AAVE trên chuỗi Polygon, sự không tương thích của các thiết lập InterestRateStrategy đã gây ra các bất thường về chức năng và một chiến lược lãi suất không tương thích đã được đặt nhầm cho WETH. <. M6C9YYDL4OXT42UZWDIIF9XF0.PNG ">
Do không tương thích giao diện, lợi ích mới không thể được gọi bình thường bằng cách cho vay Chức năng nhóm WETH bị gián đoạn và người dùng không thể gửi hoặc rút ETH.
Điểm kiểm tra: Trong quá trình kiểm tra, cần đảm bảo rằng giao diện của các thành phần chính trong mã (hoặc nhánh) hoàn toàn tương thích. Đồng thời, mặc dù các vấn đề trên không phải do đặc điểm đa chuỗi gây ra nhưng vẫn cần lưu ý xem đặc điểm của các chuỗi khác nhau có gây ra kết quả không mong muốn trong quá trình kiểm toán hay không.
Phát hành Dust Token
Việc gửi và rút AAVE được thực hiện bằng cách thiết lập usingAsCollateral trong hàm setUsingAsCollateral, để quản lý linh hoạt chiến lược thế chấp. Khi một giao thức hoặc hợp đồng bên ngoài vay tiền lần đầu tiên thông qua hàm vay AAVE, hàm vay sẽ đặt usingAsCollateral thành true. Khi một giao thức hoặc hợp đồng bên ngoài rút toàn bộ tiền khỏi AAVE, trạng thái usingAsCollateral của trình xử lý giao thức trong AAVE sẽ được đặt thành false. Nhưng trên thực tế, khi AAVE tính toán số lượng aToken cần phải đốt để rút tiền, có thể có rất ít aToken còn lại trong trình xử lý giao thức do lỗi độ chính xác về mặt số học. Do đó, lần tiếp theo trình xử lý giao thức gửi AAVE, usingAsCollateral sẽ không thay đổi và vẫn được đặt thành true. Vì không có giao diện nào trong hợp đồng trình xử lý giao thức để gọi hàm setUserUseReserveAsCollateral, điều này có thể khiến trình xử lý giao thức không còn có thể thực hiện các hoạt động vay mượn.
Điểm kiểm tra: Trong quá trình kiểm tra, bạn cần phải hoàn toàn quen thuộc với giao thức được gọi và hiểu đầy đủ các đặc điểm của giao thức đó để xác định xem có vấn đề tương thích nào đó trong quá trình tương tác với các giao thức bên ngoài hay không, chẳng hạn như khả năng tương thích của mã thông báo, khả năng tương thích của logic triển khai cuộc gọi, v.v.
Cuối cùng
Sổ tay hướng dẫn này khám phá sâu về thiết kế cốt lõi, các chức năng chính và các điểm kiểm tra liên quan của giao thức AAVE V2. Chúng tôi hy vọng rằng sổ tay hướng dẫn này có thể giúp các nhà phát triển và nhà nghiên cứu bảo mật xác định tốt hơn các rủi ro tiềm ẩn và đảm bảo giao thức hoạt động an toàn. Do giới hạn về không gian, bài viết này sẽ bỏ qua một số mã và hình ảnh. Người đọc có thể nhấp vào "đọc văn bản gốc" ở cuối bài viết để chuyển đến GitHub để đọc phiên bản đầy đủ (https://github.com/slowmist/AAVE-V2-Security-Audit-Checklist).