Futures
Access hundreds of perpetual contracts
TradFi
Gold
One platform for global traditional assets
Options
Hot
Trade European-style vanilla options
Unified Account
Maximize your capital efficiency
Demo Trading
Introduction to Futures Trading
Learn the basics of futures trading
Futures Events
Join events to earn rewards
Demo Trading
Use virtual funds to practice risk-free trading
Launch
CandyDrop
Collect candies to earn airdrops
Launchpool
Quick staking, earn potential new tokens
HODLer Airdrop
Hold GT and get massive airdrops for free
Launchpad
Be early to the next big token project
Alpha Points
Trade on-chain assets and earn airdrops
Futures Points
Earn futures points and claim airdrop rewards
I just want to share a security issue in smart contracts that many developers often overlook — reentrancy attacks. If you're building smart contracts on Solidity, this is something you must understand thoroughly.
Simply put, reentrancy occurs when a contract calls another contract, and that called contract can call back into the original contract while it is still executing. Imagine you have ContractA holding 10 Ether, and ContractB sends 1 Ether to it. When ContractB withdraws funds, ContractA checks if the balance is greater than 0, and if so, sends Ether back. However, if ContractB has a fallback function(, it can call the withdraw function of ContractA again before the first call completes. The result? ContractB's recorded balance still shows 1 Ether, so it receives another 1 Ether, and this loop continues until ContractA runs out of funds.
How does this attack work? The attacker needs two things: an attack)( function to initiate the attack, and a fallback function to call back the withdraw function. The fallback function is a special external function with no name, no parameters, which anyone can trigger by calling a non-existent function, sending Ether without data, or sending Ether with no data.
Here's a concrete example: the EtherStore contract has a deposit)( function that stores balances and a withdrawAll)( function that withdraws all funds. The problem is, withdrawAll)( checks the balance, sends Ether, then updates the balance to zero. This creates a window for reentrancy attack.
So, how to protect against this? I'll show three methods.
First, use the noReentrant modifier. The idea is simple: lock the contract during the execution of a function. If someone tries to call the function again, they must pass the lock check, but the lock only releases after the function finishes. The modifier is a special function that adds conditions to other functions without rewriting all logic.
Second, apply the Check-Effect-Interaction pattern. Instead of checking conditions, sending funds, then updating balances, you should check first, update the balance immediately)before sending funds(, and only then perform external interactions. This way, even if reentrancy occurs, the balance has already been set to zero, preventing further withdrawals.
Third, if your project involves multiple interacting contracts, you need a GlobalReentrancyGuard. Instead of locking individual functions, lock the entire system with a state variable stored in a separate contract. Whenever any function in any contract is called, it checks whether the system is locked. If it is, the transaction is rejected. This is especially useful if you have contracts like ScheduledTransfer sending funds to AttackTransfer — GlobalReentrancyGuard will prevent the entire reentrancy attack chain.
The great thing about these three methods is that you can combine them depending on the situation. Important functions? Use noReentrant. Multiple related functions? Use Check-Effect-Interaction. Entire complex project? Use GlobalReentrancyGuard. Understanding reentrancy and how to defend against it will help you build much safer smart contracts.