The ERC20 standard does not specify the mint
and burn
mechanisms, it is therefore up to the developer to define them.
The OpenZeppelin ERC20 reference implementation implements a burn
function that decreases both the account balance and the token total supply :
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
}
The account balance and the total supply are respectively decremented with _balances[account] = accountBalance - amount;
and _totalSupply -= amount;
.
Although the event Transfer
assimilates the burn
operation to a transfer to the zero address, this is not the case, and this event is purely conventional.
This _burn
function is internal
and therefore can only be called within the smart contract and derived contracts. It is up to the developer to decide how to use this feature, if necessary. For example, to allow users to burn their token, you could create a public burn
function wrapping the subfunction :
function burn(uint256 amount) public {
_burn(msg.sender, amount)
}
Regarding the zero address, it is true that you can burn tokens by transferring them directly to it. However, the tokens will not be destroyed and the total supply will remain the same. So we can say that may be using the burn
function is more appropriate, although no one can prevent a user from sending and forever locking tokens at addresses 0x0
(OpenZeppelin does for this one but this is not required by the standard) or 0x1
for example.
The Consensys Smart Contract Best Practices
- I disagree. The person who wrote the guide unlikely understood the all the implications. The answer below is good.