From 42d2358779e36a629ca0e3c52e0e42285c0d7f83 Mon Sep 17 00:00:00 2001 From: Anton Bukov Date: Mon, 18 Dec 2023 22:28:47 +0100 Subject: [PATCH] Reuse ERC20Lib logic --- contracts/token/ERC20/ERC20Upgradeable.sol | 134 ++++++--------------- 1 file changed, 35 insertions(+), 99 deletions(-) diff --git a/contracts/token/ERC20/ERC20Upgradeable.sol b/contracts/token/ERC20/ERC20Upgradeable.sol index bbe45be5e..87000148e 100644 --- a/contracts/token/ERC20/ERC20Upgradeable.sol +++ b/contracts/token/ERC20/ERC20Upgradeable.sol @@ -8,6 +8,7 @@ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IER import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; +import {ERC20Lib} from "@openzeppelin/contracts/token/ERC20/libs/ERC20Lib.sol"; /** * @dev Implementation of the {IERC20} interface. @@ -33,22 +34,12 @@ import {Initializable} from "../../proxy/utils/Initializable.sol"; * these events, as it isn't required by the specification. */ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { - /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 - struct ERC20Storage { - mapping(address account => uint256) _balances; - - mapping(address account => mapping(address spender => uint256)) _allowances; - - uint256 _totalSupply; - - string _name; - string _symbol; - } + using ERC20Lib for ERC20Lib.Storage; // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; - function _getERC20Storage() private pure returns (ERC20Storage storage $) { + function _getERC20Storage() private pure returns (ERC20Lib.Storage storage $) { assembly { $.slot := ERC20StorageLocation } @@ -65,17 +56,16 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { - ERC20Storage storage $ = _getERC20Storage(); - $._name = name_; - $._symbol = symbol_; + ERC20Lib.Storage storage $ = _getERC20Storage(); + $.init(name_, symbol_); } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { - ERC20Storage storage $ = _getERC20Storage(); - return $._name; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.name(); } /** @@ -83,8 +73,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * name. */ function symbol() public view virtual returns (string memory) { - ERC20Storage storage $ = _getERC20Storage(); - return $._symbol; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.symbol(); } /** @@ -108,16 +98,16 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { - ERC20Storage storage $ = _getERC20Storage(); - return $._totalSupply; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.totalSupply(); } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { - ERC20Storage storage $ = _getERC20Storage(); - return $._balances[account]; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.balanceOf(account); } /** @@ -129,17 +119,16 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * - the caller must have a balance of at least `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { - address owner = _msgSender(); - _transfer(owner, to, value); - return true; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.transfer(_msgSender(), to, value); } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { - ERC20Storage storage $ = _getERC20Storage(); - return $._allowances[owner][spender]; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.allowance(owner, spender); } /** @@ -153,9 +142,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * - `spender` cannot be the zero address. */ function approve(address spender, uint256 value) public virtual returns (bool) { - address owner = _msgSender(); - _approve(owner, spender, value); - return true; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.approve(_msgSender(), spender, value); } /** @@ -175,10 +163,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { - address spender = _msgSender(); - _spendAllowance(from, spender, value); - _transfer(from, to, value); - return true; + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $.transferFrom(_msgSender(), from, to, value); } /** @@ -192,13 +178,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { - if (from == address(0)) { - revert ERC20InvalidSender(address(0)); - } - if (to == address(0)) { - revert ERC20InvalidReceiver(address(0)); - } - _update(from, to, value); + ERC20Lib.Storage storage $ = _getERC20Storage(); + $.transfer(from, to, value); } /** @@ -209,34 +190,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { - ERC20Storage storage $ = _getERC20Storage(); - if (from == address(0)) { - // Overflow check required: The rest of the code assumes that totalSupply never overflows - $._totalSupply += value; - } else { - uint256 fromBalance = $._balances[from]; - if (fromBalance < value) { - revert ERC20InsufficientBalance(from, fromBalance, value); - } - unchecked { - // Overflow not possible: value <= fromBalance <= totalSupply. - $._balances[from] = fromBalance - value; - } - } - - if (to == address(0)) { - unchecked { - // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. - $._totalSupply -= value; - } - } else { - unchecked { - // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. - $._balances[to] += value; - } - } - - emit Transfer(from, to, value); + ERC20Lib.Storage storage $ = _getERC20Storage(); + $.update(from, to, value); } /** @@ -248,10 +203,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { - if (account == address(0)) { - revert ERC20InvalidReceiver(address(0)); - } - _update(address(0), account, value); + ERC20Lib.Storage storage $ = _getERC20Storage(); + $.mint(account, value); } /** @@ -263,10 +216,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { - if (account == address(0)) { - revert ERC20InvalidSender(address(0)); - } - _update(account, address(0), value); + ERC20Lib.Storage storage $ = _getERC20Storage(); + $.burn(account, value); } /** @@ -285,7 +236,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { - _approve(owner, spender, value, true); + ERC20Lib.Storage storage $ = _getERC20Storage(); + $._approve(owner, spender, value, true); } /** @@ -306,17 +258,8 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { - ERC20Storage storage $ = _getERC20Storage(); - if (owner == address(0)) { - revert ERC20InvalidApprover(address(0)); - } - if (spender == address(0)) { - revert ERC20InvalidSpender(address(0)); - } - $._allowances[owner][spender] = value; - if (emitEvent) { - emit Approval(owner, spender, value); - } + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $._approve(owner, spender, value, emitEvent); } /** @@ -328,14 +271,7 @@ abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { - uint256 currentAllowance = allowance(owner, spender); - if (currentAllowance != type(uint256).max) { - if (currentAllowance < value) { - revert ERC20InsufficientAllowance(spender, currentAllowance, value); - } - unchecked { - _approve(owner, spender, currentAllowance - value, false); - } - } + ERC20Lib.Storage storage $ = _getERC20Storage(); + return $._spendAllowance(owner, spender, value); } }