The following standard allows for the implementation of a standard API for tokens within smart contracts. This standard provides basic functionality to transfer tokens, as well as allow tokens to be approved so they can be spent by another on-chain third party.
Motivation
A standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges.
OpenZeppelin Implementation
Important functions:
transfer()
approve()
transferFrom()
transfer
/** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */functiontransfer(address to,uint256 amount) publicvirtualoverridereturns (bool) {address owner =_msgSender();_transfer(owner, to, amount);returntrue; }
/** * @dev Moves `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. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */function_transfer(address from,address to,uint256 amount) internalvirtual {require(from !=address(0),"ERC20: transfer from the zero address");require(to !=address(0),"ERC20: transfer to the zero address");_beforeTokenTransfer(from, to, amount);uint256 fromBalance = _balances[from];require(fromBalance >= amount,"ERC20: transfer amount exceeds balance");unchecked { _balances[from] = fromBalance - amount;// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by// decrementing then incrementing. _balances[to] += amount; }emitTransfer(from, to, amount);_afterTokenTransfer(from, to, amount); }
_beforeTokenTransfer() and _afterTokenTransfer()are called hooks. They are empty functions waiting to be implemented.
This is the basic transfer that transfers token from A to B. Nothing to comment here.
approve
/** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */functionapprove(address spender,uint256 amount) publicvirtualoverridereturns (bool) {address owner =_msgSender();_approve(owner, spender, amount);returntrue; }
/** * @dev Sets `amount` 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. */function_approve(address owner,address spender,uint256 amount) internalvirtual {require(owner !=address(0),"ERC20: approve from the zero address");require(spender !=address(0),"ERC20: approve to the zero address"); _allowances[owner][spender] = amount;emitApproval(owner, spender, amount); }
approve() is used before transferFrom() to give allowance to some other account.
transferFrom
/** * @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}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */functiontransferFrom(address from,address to,uint256 amount) publicvirtualoverridereturns (bool) {address spender =_msgSender();_spendAllowance(from, spender, amount);_transfer(from, to, amount);returntrue; }
/** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */function_spendAllowance(address owner,address spender,uint256 amount) internalvirtual {uint256 currentAllowance =allowance(owner, spender);if (currentAllowance != type(uint256).max) {require(currentAllowance >= amount,"ERC20: insufficient allowance");unchecked {_approve(owner, spender, currentAllowance - amount); } } }
type(uint256).max is unlimited allowance. The transfer part is the same with transfer().