Token-0x

First Flight #54
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: low
Valid

Missing Transfer Event in `_burn` Function

Root + Impact

The _burn function does not emit the required Transfer(account, address(0), value) event, violating the ERC20 standard and breaking integration with external services.

Description

  • Similar to the mint function, the burn function should emit a Transfer event with the recipient being address(0).

  • This is a standard convention for ERC20 burns.

@> src/helpers/ERC20Internals.sol
function _burn(address account, uint256 value) internal {
assembly ("memory-safe") {
if iszero(account) {
mstore(0x00, shl(224, 0x96c6fd1e))
mstore(add(0x00, 4), 0x00)
revert(0x00, 0x24)
}
let ptr := mload(0x40)
let balanceSlot := _balances.slot
let supplySlot := _totalSupply.slot
let supply := sload(supplySlot)
sstore(supplySlot, sub(supply, value))
mstore(ptr, account)
mstore(add(ptr, 0x20), balanceSlot)
let accountBalanceSlot := keccak256(ptr, 0x40)
let accountBalance := sload(accountBalanceSlot)
sstore(accountBalanceSlot, sub(accountBalance, value))
@> // Missing: Transfer event emission
}
}

Risk

Likelihood:

  • Every burn operation triggers this issue

  • All contracts using this ERC20 base are affected

Impact:

  • Burn operations invisible to external tracking systems

  • Supply tracking by explorers becomes inaccurate

  • DeFi protocols depending on Transfer events for burns will fail

Proof of Concept

function test_burnNoEvent() public {
address account = makeAddr("account");
token.mint(account, 100e18);
// Expect Transfer event from account to address(0)
vm.expectEmit(true, true, false, true);
emit Transfer(account, address(0), 50e18);
// This will fail - no event emitted
token.burn(account, 50e18);
}

Recommended Mitigation

Add Transfer event emission using the log3 opcode at the end of the _burn function.

function _burn(address account, uint256 value) internal {
assembly ("memory-safe") {
if iszero(account) {
mstore(0x00, shl(224, 0x96c6fd1e))
mstore(add(0x00, 4), 0x00)
revert(0x00, 0x24)
}
let ptr := mload(0x40)
let balanceSlot := _balances.slot
let supplySlot := _totalSupply.slot
let supply := sload(supplySlot)
sstore(supplySlot, sub(supply, value))
mstore(ptr, account)
mstore(add(ptr, 0x20), balanceSlot)
let accountBalanceSlot := keccak256(ptr, 0x40)
let accountBalance := sload(accountBalanceSlot)
sstore(accountBalanceSlot, sub(accountBalance, value))
+ // Emit Transfer(account, address(0), value)
+ mstore(ptr, value)
+ log3(ptr, 0x20, 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, account, 0)
}
}
Updates

Lead Judging Commences

gaurangbrdv Lead Judge 19 days ago
Submission Judgement Published
Validated
Assigned finding tags:

missing event

missing event emission

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!