NFTBridge
60,000 USDC
View results
Submission Details
Severity: low
Valid

TokenUtil::_getBaseUri will not work as expected because of using wrong signature `_baseUri()` and `baseUri()`

Summary

OpenZeppelin provides the baseURI() function to retrieve the base URL of an NFT collection. There are no functions defined as _baseUri() or baseUri() in any implementation or standard of OpenZeppelin's ERC721.

Vulnerability Details

The Ark Project will fetch the baseURI of an NFT collection if the collection implements the MetadataInterface. First, it will check if the collection implements the baseUri function. If so, it will retrieve the URL from that function and pass it to the depositTokens function, which will then send this baseURI along with the request to Layer 2 Starknet.

function erc721Metadata(
address collection,
uint256[] memory tokenIds
)
internal
view
returns (string memory, string memory, string memory, string[] memory)
{
bool supportsMetadata = ERC165Checker.supportsInterface(
collection,
type(IERC721Metadata).interfaceId
);
if (!supportsMetadata) {
return ("", "", "", new string[](0));
}
IERC721Metadata c = IERC721Metadata(collection);
// How the URI must be handled.
// if a base URI is already present, we ignore individual URI
// else, each token URI must be bridged and then the owner of the collection
// can decide what to do
(bool success, string memory _baseUri) = _callBaseUri(collection);
if (success) {
return (c.name(), c.symbol(), _baseUri, new string[](0));
}

_callBaseUri function :

function _callBaseUri(
address collection
)
internal
view
returns (bool, string memory)
{
bool success;
uint256 returnSize;
uint256 returnValue;
bytes memory ret;
@>-- bytes[2] memory encodedSignatures = [abi.encodeWithSignature("_baseUri()"), abi.encodeWithSignature("baseUri()")];
for (uint256 i = 0; i < 2; i++) {
bytes memory encodedParams = encodedSignatures[i];
assembly {
success := staticcall(gas(), collection, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
if success {
returnSize := returndatasize()
returnValue := mload(0x00)
ret := mload(0x40)
mstore(ret, returnSize)
returndatacopy(add(ret, 0x20), 0, returnSize)
// update free memory pointer
mstore(0x40, add(add(ret, 0x20), add(returnSize, 0x20)))
}
}
if (success && returnSize >= 0x20 && returnValue > 0) {
return (true, abi.decode(ret, (string)));
}
}
return (false, "");
}

The above function uses the signatures of _baseUri() and baseUri() functions to fetch the base URI of a collection. However, the issue is that these functions are not defined in the ERC721 standard. It's important to note that OpenZeppelin, up until version 3, provided a baseURI function as a public or external function, which can be verified in the documentation: OpenZeppelin ERC721Metadata baseURI.

In the current version, there is no baseURI external/public function available. Moreover, the functions that the Ark Project uses are not included in any ERC721 standard implementation. Therefore, it is assumed that these functions will only work if the NFT collection is using OpenZeppelin version 3 or earlier.

Impact

NFT collections that implement the baseURI function following the ERC721 standard are not compatible with the Ark Project and will return an empty value in this context. Many NFT collections use the baseURI function to retrieve the base URL of the collection and then append the tokenId to it, without implementing the tokenURI function. All of these collections will be incompatible with the Ark Project, potentially resulting in the loss of NFTs on the Starknet Layer 2.

Tools Used

Manual Review

Recommendations

One fix would be to add baseURI() and _baseURI() function to encodedSignatures array.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-baseUri-selector-instead-of-baseURI

Likelyhood: Medium, no token using OZ version 2.X and 3.X will work. Impact: Low, Valid standard token won’t be mint with the URI but owner can use ERC721UriImpl function on the deployed token.

Support

FAQs

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