In Web3 DeFi, lending and borrowing platforms have become foundational components of the ecosystem. These platforms typically enable users to:
This deep dive examines common vulnerabilities that smart contract developers and auditors should be aware of when building or reviewing lending and borrowing protocols. The vulnerabilities described here are based on patterns observed across multiple projects and audits.
<aside> 📌
A critical issue occurs when a borrower's collateral can be seized before legitimate default conditions are met. This unfairly disadvantages borrowers who may lose their collateral despite being current on their obligations.
</aside>
Proper liquidation should only happen when:
Consider this simplified vulnerable code:
function lastRepaymentTime(Loan storage loan) internal view returns (uint32) {
return
loan.lastRepayment == 0
? loan.creationTime // BUG: Uses creation time if no repayments made
: loan.lastRepayment;
}
function canBeLiquidated(uint loanId) public returns (bool) {
Loan storage loan = loans[loanId];
if (loan.state != LoanState.ACTIVE) return false;
return (uint32(block.timestamp) - lastRepaymentTime(loan) > defaultThreshold);
// BUG: Doesn't check payment schedule
// If defaultThreshold < firstPaymentDue, borrower can be
// liquidated before first payment is even due
}
The bug is that liquidation eligibility doesn't account for the actual payment schedule. If defaultThreshold is shorter than the first payment due date, borrowers can be liquidated before they're even required to make a payment!