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;
?
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".