The tokenURI
function in the SoulboundProfileNFT
contract uses ownerOf(tokenId) == address(0)
to check if a token exists. However, this check is incorrect because ownerOf(tokenId)
reverts if the token does not exist, instead of returning address(0)
. As a result, calling tokenURI
with an invalid tokenId
will cause a transaction failure instead of handling the error gracefully.
In the tokenURI
function, the following check is used to verify whether a token exists:
However, this approach is flawed because:
ownerOf(tokenId)
Does Not Return address(0)
for Invalid Tokens
The ownerOf
function in OpenZeppelin’s ERC721
contract is designed to revert if the token does not exist.
It does not return address(0)
.
This means the if-condition will never execute; instead, the function will revert immediately when calling ownerOf
with a non-existent tokenId
.
How the Issue Manifests
If a user queries tokenURI(nonExistentTokenId)
, the transaction will fail with a revert error from ownerOf
, rather than the intended ERC721Metadata__URI_QueryFor_NonExistentToken()
error.
This makes error handling inconsistent and unexpected.
Add the test below in the testSoulboundProfileNFT.t.sol
and run the command forge test --mt testTokenURI_ShouldRevertForNonExistentToken -vvvv
Your Output should look like the one below:
Looking at the Logs, you will see that the contract reverted with ERC721NonexistentToken(999)
, proving that ownerOf(tokenId) == address(0)
does not correctly check token existence.
Unexpected Reverts: Calling tokenURI
with an invalid token ID will revert due to ownerOf
, rather than executing the intended error-handling logic.
Inconsistent Error Handling: The contract's ERC721Metadata__URI_QueryFor_NonExistentToken()
error is never actually used, making debugging more difficult.
Manual Code Review
OpenZeppelin ERC721 Documentation
Use _exists(tokenId)
Instead of ownerOf(tokenId) == address(0)
OpenZeppelin provides an _exists(tokenId)
function that safely checks if a token exists without reverting. Update tokenURI
as follows:
Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.