Code
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract SafeVault {
mapping(address => uint256) public balances;
bool private locked; // reentrancy guard
modifier noReentrant() {
require(!locked, "reentrant");
locked = true;
_;
locked = false;
}
function deposit() external payable {
balances[msg.sender] += msg.value;
}
// VULNERABLE pattern (DO NOT USE):
// function withdrawBad() external {
// uint256 bal = balances[msg.sender];
// (bool ok,) = msg.sender.call{value: bal}("");
// require(ok);
// balances[msg.sender] = 0; // state update AFTER external call
// }
function withdraw() external noReentrant {
uint256 bal = balances[msg.sender];
require(bal > 0, "nothing");
// 1) Checks (require)
// 2) Effects (mutate state FIRST)
balances[msg.sender] = 0;
// 3) Interactions (external call LAST)
(bool ok, ) = payable(msg.sender).call{value: bal}("");
require(ok, "transfer failed");
}
}