Search code examples
ethereumsolidity

What is the purpose of declaring an extra local variable in this OpenZeppelin ERC20 implementation?


From the implementation of ERC20 from Openzeppelin using solidity ^0.8.0, the _transfer function is like this:

function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

Is there a special purpose of writing

uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = senderBalance - amount;

instead of simply

require(_balances[sender]>= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] -= amount;

?


Solution

  • From the pull request comment that contains this commit adding the senderBalance:

    The addition of revert messages back into the 0.8 branch (#2491) generated double reading of some storage slot. This PR remove the double sload, which reduces gas costs of running the affected function.

    So it's because of lowering gas usage.

    "One read from storage and one from memory" cost significantly less gas than "two reads from storage".