DeFi protocols handle valuable assets. A single vulnerability can lead to catastrophic losses. Always follow these patterns and get professional audits.
Security Patterns for DeFi dApps
1. Reentrancy Protection
Reentrancy is one of the most infamous vulnerabilities in smart contract development. It occurs when an external call is made to an untrusted contract before the calling contract has updated its own state, allowing the called contract to recursively call back into the original function and manipulate the contract’s state in unexpected ways.
The Classic Reentrancy Attack (The DAO Hack)
Consider a simple withdrawal function:
// VULNERABLE
function withdraw(uint256 amount) external {
require(balances[msg.sender] >= amount);
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
balances[msg.sender] -= amount;
}
If msg.sender is a malicious contract, its receive() function can call withdraw() again before balances[msg.sender] is updated. This leads to draining the contract.
Attack sequence:
Attacker calls withdraw(1 ether).
Contract sends 1 ether to attacker, triggering attacker's receive().
Attacker's receive() calls withdraw(1 ether) again.
Contract still has the attacker's old balance (not yet subtracted), so it sends another 1 ether.
This repeats until the contract is empty.
The Solution: Checks-Effects-Interactions Pattern
Always follow this order:
Checks: Validate conditions (require statements).
Effects: Update the contract's state (e.g., subtract balance).
Interactions: Make external calls.