// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; /** * @dev {IERC20} 接口的实现。 * * 此实现与代币创建方式无关。这意味着必须在派生合约中使用 {_mint} 添加供应机制。 * * 提示:有关详细说明,请参阅我们的指南 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[如何实现供应机制]。 * * {decimals} 的默认值是 18。要更改此值,您应该重写此函数以返回不同的值。 * * 我们遵循了 OpenZeppelin 合约的一般准则:函数在失败时回退而不是返回 `false`。 * 这种行为仍然是常规的,并且不会与 ERC-20 应用程序的期望冲突。 */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev 设置 {name} 和 {symbol} 的值。 * * 这两个值都是不可变的:它们只能在构造期间设置一次。 */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev 返回代币的名称。 */ function name() public view virtual returns (string memory) { return _name; } /** * @dev 返回代币的符号,通常是名称的较短版本。 */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev 返回用于获取其用户表示的小数位数。 * 例如,如果 `decimals` 等于 `2`,则应该向用户显示 `505` 代币的余额为 `5.05` (`505 / 10 ** 2`)。 * * 代币通常选择值为 18,模仿以太币和 Wei 之间的关系。除非被重写,否则这是此函数返回的默认值。 * * 注意:此信息仅用于 _显示_ 目的:它不会以任何方式影响合约的任何算术, * 包括 {IERC20-balanceOf} 和 {IERC20-transfer}。 */ function decimals() public view virtual returns (uint8) { return 18; } /// @inheritdoc IERC20 function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /// @inheritdoc IERC20 function balanceOf(address account) public view virtual returns (uint256) { return _balances[account]; } /** * @dev 参见 {IERC20-transfer}。 * * 要求: * * - `to` 不能是零地址。 * - 调用者必须有至少 `value` 的余额。 */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /// @inheritdoc IERC20 function allowance(address owner, address spender) public view virtual returns (uint256) { return _allowances[owner][spender]; } /** * @dev 参见 {IERC20-approve}。 * * 注意:如果 `value` 是最大 `uint256`,则在 `transferFrom` 时不会更新授权额度。 * 这在语义上等同于无限授权。 * * 要求: * * - `spender` 不能是零地址。 */ function approve(address spender, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); return true; } /** * @dev 参见 {IERC20-transferFrom}。 * * 跳过发出 {Approval} 事件以指示授权额度更新。ERC 不要求这样做。 * 参见 {xref-ERC20-_approve-address-address-uint256-bool-}[_approve]。 * * 注意:如果当前授权额度是最大 `uint256`,则不会更新授权额度。 * * 要求: * * - `from` 和 `to` 不能是零地址。 * - `from` 必须有至少 `value` 的余额。 * - 调用者必须对 `from` 的代币有至少 `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; } /** * @dev Moves a `value` amount of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * 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); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { 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); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * 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); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * 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); } /** * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. * * 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); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * * ```solidity * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { 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); } } /** * @dev Updates `owner`'s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * 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); } } } }