Skip to content
Solidity

Reentrancy & Checks-Effects-Interactions

Упрочение контрактов против самой распространённой атаки на смарт-контракты.

#security#reentrancy#best-practice

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");
    }
}