Add a function to read which address burned a given ERC-721 token.
The problem. A contract that has to decide something in the middle of a transaction cannot know who burned a token. The answer sits in the from field of the Transfer to address(0), but the EVM cannot read logs, so a lending protocol, a marketplace or a redemption contract is blind to it exactly when it matters. Indexers cover everyone except the contracts. One use case I have in mind is a redemption flow where a claim belongs only to whoever burned the token, but burn-to-mint flows and destruction receipts hit the same wall.
/// @dev The ERC-165 identifier for this interface is 0x43470a89
interface IERC721BurnRecord /* is IERC721, IERC165 */ {
/// @notice Get the address recorded as having burned a token
/// @dev Returns address(0) when no burn record exists for `tokenId`
/// @param tokenId The token to query
/// @return The address that burned the token, or address(0)
function burnedBy(uint256 tokenId) external view returns (address);
}
Proposed semantics.
-
address(0)means “no burn record for this tokenId”. It does not mean “not burned”. -
The recorded address MUST equal the
fromof theTransferevent emitted for the burn, so a contract reading this function and an indexer reading the logs never disagree. -
Burned means the token no longer exists and a
Transfertoaddress(0)was emitted. A token held by a conventionally dead address still has an owner and is out of scope. -
While a token exists,
burnedByMUST returnaddress(0). A contract that re-mints a token id therefore reports its most recent burn only.
The guarantee runs one way, and that is the heart of it: a non-zero answer is proof, a zero answer proves nothing. Combined with ownerOf, which throws for tokens that do not exist, a caller can separate a live token from a burned one with a known burner, and is left with a single ambiguous case: never minted, or burned before the record existed.
On indexing. The burner can of course be derived from Transfer events, and off-chain that is the right tool. Contracts have no access to it. Two Final ERC-721 extensions already made the same call: ERC-7634 emits TransferCountIncreased and also exposes transferCountOf, ERC-6672 emits Redeem and also exposes isRedeemed. In both cases the same fact lives in the log for indexers and in a getter for contracts.
Adjacent work, as far as I could find: ERC-5484 fixes who may burn, ahead of time; ERC-5679 standardises the burn operation itself. Neither keeps a record of who performed it. Pointers to prior art I missed are welcome.
Two notes for integrators. If a router or a marketplace owns the token at the moment of the burn, the record names that contract and not the person behind it. That is an application-level concern, and no choice of rule here avoids it. And a contract that guards value on the strength of this record should read it once, at burn time, and store the result, rather than consulting it on every call.
Deliberately left out: the time of the burn. It would pack into the same storage slot, so cost is not the argument, scope is. It could live in a separate optional interface if there is demand.
My question: is a one-directional guarantee enough for the cases you would use this in, or would a consumer need to tell “never existed” from “burned before the record existed”?
@jay, this is the first of the two threads you suggested. I would value your review of the semantics above whenever you have time.
If the shape holds up, I will open a PR on ethereum/ERCs.