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

ERC721 URI Metadata is lost when bridging NFT from L2 -> L1

Summary

ERC721 URI Metadata is lost when bridging NFT from L2 -> L1, this is because ERC721Bridgeable.soldoesn't support token URIs.

Vulnerability Details

When bridging an NFT from L2 -> L1, the NFT Metadata is stored in the request as follows :

let req = Request {
header: compute_request_header_v1(ctype, use_deposit_burn_auto, use_withdraw_auto),
hash: compute_request_hash(salt, collection_l2, owner_l1, token_ids),
collection_l1,
collection_l2,
owner_l1,
owner_l2: from,
name,
symbol,
base_uri,
ids: token_ids,
values: array![].span(),
uris,
new_owners: array![].span(),
}

Here, the base_uri represents the base_uri of the NFT collection, additionally, uris contains the token-specific URIs of the individual tokens. These comprise the URI Metadata of the collection and NFT.

In the current codebase, if a native L2 NFT is bridged to L1 for the first time, the corresponding collection is created on L1 in the L1 bridge's (Bridge.sol) withdrawTokens() function.

@=> if (collectionL1 == address(0x0)) {
if (ctype == CollectionType.ERC721) {
collectionL1 = _deployERC721Bridgeable(
req.name,
req.symbol,
req.collectionL2,
req.hash
);
// update whitelist if needed
_whiteListCollection(collectionL1, true);
} else {
revert NotSupportedYetError();
}
}

As you can see, the URI data is not passed on to the _deployERC721Bridgeable() function :

function _deployERC721Bridgeable(
string memory name,
string memory symbol,
snaddress collectionL2,
uint256 reqHash
)
internal
returns (address)
{
address proxy = Deployer.deployERC721Bridgeable(name, symbol);
_l1ToL2Addresses[proxy] = collectionL2;
_l2ToL1Addresses[collectionL2] = proxy;
emit CollectionDeployedFromL2(
reqHash,
block.timestamp,
proxy,
snaddress.unwrap(collectionL2)
);
return proxy;
}

Also, in ERC721Bridgeable.sol, you can see that the contract returns an empty string in the _baseURI() function :

function _baseURI()
internal
pure
override
returns (string memory) {
return "";
}

Also, a close look at ERC721Bridgeable.sol will reveal that it doesn't support individual token URIs. Hence all ERC721 URI data is lost

also on the L2 bridge, while gathering ERC721 Metadata for L2 -> L1 bridging, base URI is set to an empty string :

fn erc721_metadata(
contract_address: ContractAddress,
token_ids: Option<Span<u256>>
) -> Option<ERC721Metadata> {
let erc721 = IERC721Dispatcher { contract_address };
let uris = match token_ids {
Option::Some(ids) => {
let mut out_uris = array![];
let mut i = 0_usize;
loop {
if i == ids.len() {
break ();
}
let token_id = *ids[i];
let token_uri =
match token_uri_from_contract_call(erc721.contract_address, token_id) {
Option::Some(uri) => uri,
Option::None => "",
};
out_uris.append(token_uri);
i += 1;
};
out_uris.span()
},
Option::None => {
array![].span()
}
};
Option::Some(
ERC721Metadata {
name: erc721.name(),
symbol: erc721.symbol(),
@=> base_uri: "",
uris
}
)
}

Impact

Native L2 NFTs that are bridged to L1 won't carry the URI data of the token to L1, and there is no way to add this data later on. The token URI points to a JSON file that contains detailed metadata about the token, including its name, description, image, and attributes. This metadata gives the token context and meaning, transforming it from just an entry on the blockchain into a unique and identifiable asset. Without it, the NFT loses its uniqueness and the rich descriptive information that makes it valuable and distinguishable from other tokens. This absence can lead to a significant loss in the NFT's perceived value and utility, as platforms, marketplaces, and users on L1 would only see a bare token without any of the critical metadata that defines its purpose and characteristics.

Tools Used

Manual Review

Recommendations

Modify the functions above and ERC721Bridgeable.solso that it supports token URI Metadata.

Updates

Lead Judging Commences

n0kto Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

invalid-NFT-minted-without-baseURI-URIs-or-bridge-with-no-metadata

URI is not lost on the origin chain and it can be modified with `ERC721UriImpl`. As explained in the TODO  below, that’s a design choice and it will be implemented as a future feature. https://github.com/Cyfrin/2024-07-ark-project/blob/main/apps/blockchain/ethereum/src/Bridge.sol#L206 `ERC721Bridgable` is out of scope.

Support

FAQs

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