Burnable Token
Problem
I need token holders to be able to permanently destroy (burn) their own tokens, reducing total supply.
Solution
token BurnableToken {
name: "Burnable Token"
symbol: "BTK"
decimals: 18
supply: 10_000_000 tokens
initial_holder: deployer
event Burned(from: address indexed, amount: amount)
error InsufficientBalance()
error ZeroAmount()
action burn(amount: amount) {
given amount > 0 or revert_with ZeroAmount()
given balances[caller] >= amount or revert_with InsufficientBalance()
balances[caller] = balances[caller] - amount
total_supply = total_supply - amount
emit Burned(caller, amount)
}
action burn_from(owner: address, amount: amount) {
given amount > 0 or revert_with ZeroAmount()
given allowances[owner][caller] >= amount or revert_with Unauthorized()
given balances[owner] >= amount or revert_with InsufficientBalance()
allowances[owner][caller] = allowances[owner][caller] - amount
balances[owner] = balances[owner] - amount
total_supply = total_supply - amount
emit Burned(owner, amount)
}
}
Explanation
burn lets callers destroy their own tokens. burn_from uses the allowance mechanism (standard ERC-20 approve/transferFrom) to let approved spenders burn on behalf of a holder — useful for DeFi protocols (lending, AMMs) that need to destroy collateral tokens.
Both actions decrement total_supply, making burns visible to anyone querying supply.
Gas Estimate
| Operation | Gas |
|---|---|
burn | ~35,000 |
burn_from | ~45,000 |
Common Pitfalls
- Not decrementing
total_supply: If you only zero the balance,total_supplybecomes inconsistent. Always update both. - Burning more than balance: The
>=check prevents underflow. Without it, Covenant’samounttype would revert on underflow, but the error message is less clear. - Missing allowance decrement in
burn_from: The allowance must be reduced before the balance — CEI pattern. - No
burn_from-> no DeFi compatibility: Protocols like Aave expectburnFromto exist. Include it even if you don’t plan to use it immediately.
Variations
Owner-only burning
action burn(target: address, amount: amount) only owner {
balances[target] = balances[target] - amount
total_supply = total_supply - amount
emit Burned(target, amount)
}