// SPDX-License-Identifier: MIT // Inspired on token.sol from DappHub. Natspec adpated from OpenZeppelin. pragma solidity ^0.8.0; import "./IERC20Metadata.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Calls to {transferFrom} do not check for allowance if the caller is the owner * of the funds. This allows to reduce the number of approvals that are necessary. * * Finally, {transferFrom} does not decrease the allowance if it is set to * type(uint256).max. This reduces the gas costs without any likely impact. */ contract ERC20 is IERC20Metadata { uint256 internal _totalSupply; mapping (address => uint256) internal _balanceOf; mapping (address => mapping (address => uint256)) internal _allowance; string public override name = "???"; string public override symbol = "???"; uint8 public override decimals = 18; /** * @dev Sets the values for {name}, {symbol} and {decimals}. */ constructor(string memory name_, string memory symbol_, uint8 decimals_) { name = name_; symbol = symbol_; decimals = decimals_; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() external view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address guy) external view virtual override returns (uint256) { return _balanceOf[guy]; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) external view virtual override returns (uint256) { return _allowance[owner][spender]; } /** * @dev See {IERC20-approve}. */ function approve(address spender, uint wad) external virtual override returns (bool) { return _setAllowance(msg.sender, spender, wad); } /** * @dev See {IERC20-transfer}. * * Requirements: * * - the caller must have a balance of at least `wad`. */ function transfer(address dst, uint wad) external virtual override returns (bool) { return _transfer(msg.sender, dst, wad); } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `src` must have a balance of at least `wad`. * - the caller is not `src`, it must have allowance for ``src``'s tokens of at least * `wad`. */ /// if_succeeds {:msg "TransferFrom - decrease allowance"} msg.sender != src ==> old(_allowance[src][msg.sender]) >= wad; function transferFrom(address src, address dst, uint wad) external virtual override returns (bool) { _decreaseAllowance(src, wad); return _transfer(src, dst, wad); } /** * @dev Moves tokens `wad` from `src` to `dst`. * * Emits a {Transfer} event. * * Requirements: * * - `src` must have a balance of at least `amount`. */ /// if_succeeds {:msg "Transfer - src decrease"} old(_balanceOf[src]) >= _balanceOf[src]; /// if_succeeds {:msg "Transfer - dst increase"} _balanceOf[dst] >= old(_balanceOf[dst]); /// if_succeeds {:msg "Transfer - supply"} old(_balanceOf[src]) + old(_balanceOf[dst]) == _balanceOf[src] + _balanceOf[dst]; function _transfer(address src, address dst, uint wad) internal virtual returns (bool) { require(_balanceOf[src] >= wad, "ERC20: Insufficient balance"); unchecked { _balanceOf[src] = _balanceOf[src] - wad; } _balanceOf[dst] = _balanceOf[dst] + wad; emit Transfer(src, dst, wad); return true; } /** * @dev Sets the allowance granted to `spender` by `owner`. * * Emits an {Approval} event indicating the updated allowance. */ function _setAllowance(address owner, address spender, uint wad) internal virtual returns (bool) { _allowance[owner][spender] = wad; emit Approval(owner, spender, wad); return true; } /** * @dev Decreases the allowance granted to the caller by `src`, unless src == msg.sender or _allowance[src][msg.sender] == MAX * * Emits an {Approval} event indicating the updated allowance, if the allowance is updated. * * Requirements: * * - `spender` must have allowance for the caller of at least * `wad`, unless src == msg.sender */ /// if_succeeds {:msg "Decrease allowance - underflow"} old(_allowance[src][msg.sender]) <= _allowance[src][msg.sender]; function _decreaseAllowance(address src, uint wad) internal virtual returns (bool) { if (src != msg.sender) { uint256 allowed = _allowance[src][msg.sender]; if (allowed != type(uint).max) { require(allowed >= wad, "ERC20: Insufficient approval"); unchecked { _setAllowance(src, msg.sender, allowed - wad); } } } return true; } /** @dev Creates `wad` tokens and assigns them to `dst`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. */ /// if_succeeds {:msg "Mint - balance overflow"} old(_balanceOf[dst]) >= _balanceOf[dst]; /// if_succeeds {:msg "Mint - supply overflow"} old(_totalSupply) >= _totalSupply; function _mint(address dst, uint wad) internal virtual returns (bool) { _balanceOf[dst] = _balanceOf[dst] + wad; _totalSupply = _totalSupply + wad; emit Transfer(address(0), dst, wad); return true; } /** * @dev Destroys `wad` tokens from `src`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `src` must have at least `wad` tokens. */ /// if_succeeds {:msg "Burn - balance underflow"} old(_balanceOf[src]) <= _balanceOf[src]; /// if_succeeds {:msg "Burn - supply underflow"} old(_totalSupply) <= _totalSupply; function _burn(address src, uint wad) internal virtual returns (bool) { unchecked { require(_balanceOf[src] >= wad, "ERC20: Insufficient balance"); _balanceOf[src] = _balanceOf[src] - wad; _totalSupply = _totalSupply - wad; emit Transfer(src, address(0), wad); } return true; } }