Snowman Merkle Airdrop

AI First Flight #10
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Snowman.tokenURI() existence check can never run because ownerOf() reverts first

Root + Impact

Description

// src/Snowman.sol - the existence check in tokenURI() is unreachable
@> function tokenURI(uint256 tokenId) public view override returns (string memory) {
@> if (ownerOf(tokenId) == address(0)) {
@> revert ERC721Metadata__URI_QueryFor_NonExistentToken();
@> }
​
ownerOf() is OpenZeppelin ERC721.ownerOf, which reverts with ERC721NonexistentToken for a token that does not exist; it never returns address(0). The == address(0) comparison can therefore never be true, and the custom error ERC721Metadata__URI_QueryFor_NonExistentToken() declared at the top of the contract can never be returned from tokenURI(). Callers querying a nonexistent token get the generic OpenZeppelin error instead of the intended one.
​
Impact is low - error reporting only - but the check is dead code that misleads readers about the behaviour of the function.

Risk

Likelihood:

Impact:

Proof of Concept

// Explanation: the guard calls ownerOf() first, and that call reverts for a nonexistent token before the comparison is ever evaluated.
// 1. Call tokenURI(999) on a deployed Snowman contract where token 999
// was never minted.
// 2. ownerOf(999) reverts with ERC721NonexistentToken before the
// if (ownerOf(tokenId) == address(0)) comparison runs.
// 3. The custom error ERC721Metadata__URI_QueryFor_NonExistentToken()
// is therefore never returned, and the address(0) branch is dead code.
// No test in the project queries tokenURI() for a nonexistent token.

Recommended Mitigation

Explanation: check existence with the internal function that returns an address instead of reverting, or drop the check and rely on ownerOf()'s revert.
- if (ownerOf(tokenId) == address(0)) {
+ if (_ownerOf(tokenId) == address(0)) {
revert ERC721Metadata__URI_QueryFor_NonExistentToken();
}
​
_ownerOf is OpenZeppelin ERC721's internal view that returns address(0) for a nonexistent token without reverting. Alternatively, remove the check entirely and let ownerOf() revert with ERC721NonexistentToken.
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!