When a collection
exposes a publicly-accessible baseURI()
, but it returns an empty string, the bridge fails to procure any meaningful metadata.
When bridging ERC-721s, the Bridge
will attempt to fetch the metadata for the token being bridged via a call to TokenUtil::erc721Metadata
.
This operation handles the presence of a baseURI
differently depending upon the token. If a baseURI
(or a _baseURI
) function is accessible and returns valid data, it will prefer to use this data when evaluating tokens instead of querying for each individual token URI manually:
An oversight in this implementation is what happens when _callBaseUri
indeed defines a baseURI()
function, but that function returns an empty string.
If we look at the OpenZeppelin ERC-721 implementation, we can see that the baseURI()
function is always present, regardless of whether a collection defines individual custom URIs per token or not.
Therefore, it is commonplace for many real-world collections to define a tokenURI()
function which returns an empty string.
Even the project's own ERC721Bridgeable
operates in this manner.
In the Proof of Concept below, we can determine that for an empty baseURI()
function implementation, the invocation to _callBaseUri
indeed returns successfully for an empty string:
forge test --match-test "test_with_empty_underscorebaseuri" -vv
results in the output:
Therefore, _callBaseUri
returns successfully with an empty string.
Looking back to the implementation ofTokenUtil::erc721Metadata
, we can see the empty string continues to satisfy the baseURI
case, so we opt to not define an empty baseURI
and an empty list of tokenURI
s:
This means no useful metadata is returned.
The majority of bridged tokens will emerge with non-emptytokenURI
s, despite great efforts to the contrary.
Manual Review
If _callBaseUri
returns successfully with an empty string, continue to process the token URIs individually as if it were not defined:
it should be stressed to the Ark team that the baseURI
alone is not enough when trying to reconstruct tokens, since these can optionally be concatenated with custom metadata (and not simply the tokenID
):
baseURI()
→ stringReturns the base URI set via
_setBaseURI
. This will be automatically added as a prefix intokenURI
to each token’s URI, or to the token ID if no specific URI is set for that token ID.
In this respect, it may be more accurate to unconditionally query individual tokenURI
s for each token being bridged, regardless of the presence of a (non-standard) baseURI
.
Likelyhood: Low, baseURI is not in the ERC721 standard. Impact: Low, function won’t work when it has to. But URI can be set later.
Likelyhood: Low, baseURI is not in the ERC721 standard. Impact: Low, function won’t work when it has to. But URI can be set later.
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.