@perfect-abstractions/compose/token/ERC20/Burn/ERC20BurnFacet.solDestroy tokens and reduce the total supply
burn destroys the caller's own tokens. burnFrom destroys someone else's using an allowance.balanceOf and totalSupply in ERC20Storage at erc8042:erc20.Transfer to address(0), which is the ERC-20 convention for a burn.STORAGE_POSITIONbytes32keccak256("erc20"))Destroys _value of the caller's own tokens and reduces the total supply by the same amount.
Burning 0 is allowed and still emits Transfer. Neither function returns a value, so check for a revert rather than a boolean.
Parameters:
_valueuint256Reverts:
ERC20InsufficientBalanceerror_value tokens.Destroys _value tokens held by _account, spending the allowance that _account granted to the caller, and reduces the total supply.
The allowance is checked before the balance, so if both are insufficient the call reverts with ERC20InsufficientAllowance. When the allowance is exactly type(uint256).max it is left untouched, otherwise it is reduced by _value.
Parameters:
_accountaddress_value._valueuint256_account's balance.Reverts:
ERC20InsufficientAllowanceerror_account is below _value.ERC20InsufficientBalanceerror_account holds fewer than _value tokens.Emitted by both burn and burnFrom, always with address(0) as the destination. This is how ERC-20 represents a burn, so indexers reading Transfer see the supply decrease without a separate event.
_fromaddressmsg.sender for burn, _account for burnFrom._toaddressaddress(0)._valueuint256Thrown by burn when the caller, or by burnFrom when _account, holds less than _value.
_senderaddress_balanceuint256_neededuint256Thrown by burnFrom when the caller's allowance over _account is below _value.
_spenderaddressmsg.sender._allowanceuint256_neededuint256burnFrom needs an allowance first, from ERC20ApproveFacet or ERC20PermitFacet. It is the same allowance transferFrom spends, so burning consumes budget a spender could otherwise have transferred.ERC20DataFacet so holders can watch totalSupply fall as tokens are destroyed.ERC20MintMod, which ships without a facet of its own, or through crosschainMint on ERC20BridgeableFacet, which is restricted to holders of the trusted-bridge role.ERC20BurnMod behind your own authorization check.The totalSupply subtraction is unchecked and depends on an invariant. Both functions verify the account's balance, then subtract from the balance and totalSupply inside the same unchecked block. That is safe only while no balance exceeds totalSupply. A custom facet that writes balanceOf directly without adjusting totalSupply breaks that invariant, and a later burn can then underflow totalSupply to a huge number with no revert.
burnFrom emits no Approval when it reduces the allowance. Only the Approve and Permit contracts emit Approval anywhere in Compose, so an indexer tracking allowances from events alone will drift. Read allowance() for the current value.
burnFrom does not reject address(0) explicitly. It has no zero-address guard. A call naming address(0) fails the allowance check instead, because that allowance is always zero, unless _value is also 0, in which case the call succeeds as a no-op and emits Transfer(address(0), address(0), 0).
There are no external calls in either function, so there is no reentrancy surface here.