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

Some dynamic and on-chain NFTs are unbridgable from `L1`

Vulnerability Details

There is a check that prevents Bridging large NFTs from L1 to L2 where there is a variable MAX_PAYLOAD_LENGTH which prevents the data we are bridging from L1 to L2 to exceeds.

Bridge.sol#L134-L136

uint256 constant MAX_PAYLOAD_LENGTH = 300;
...
function depositTokens( ... ) {
...
uint256[] memory payload = Protocol.requestSerialize(req);
❌️ if (payload.length >= MAX_PAYLOAD_LENGTH) {
revert TooManyTokensError();
}
...
}

The current value is 300 (300 elements in an array), which ensures that the user will not get their NFTs stuck in the bridge.

We are talking about transferring a single NFT token now.

This check is used to prevent bridging large numbers of NFTs, by doing calculations we will find that we are using.

  • 7 slots: header, hash, collectionL1/L2, ownerL1/L2

  • 9 slots: name, symbol, baseURI (this is the minimum)

  • 3 slots: single tokenId (1 for length two for u256 value)

  • 2 slots: tokenValues[] and newOwners[] array if they are empty

So the total is 21 slots are used in minimum with + the slots used for tokenURI array.

So we will end up having 279 slot for our NFT token. 2 are used for string length and pendingString length, so we only have 277 slots.

Each slot takes 31 character length at max (flet252 in Starknet). so the number of characters we can transfer is 31 * 277 = 8587.

Now we need to check is 8587 string length is enough for a single tokenURI?

If we are talking about normal NFTs (off-chain), then the answer is yes. But what if the NFT is a dynamic NFT that stores the data on-chain?

Dynamic NFTs (on-chain) NFTs store the SVG image as Base64 encoding in the tokenURI, this means that the full data of the NFT is on-chain, and they are storing it in the tokenURI. so the value returned from tokenURI is a large-length string output.

Since the maximum number of characters we can put for transferring a single NFT is 8587, this will prevent us from transferring these NFTs (an SVG with 5KB size can take 8000 characters in some situations) and 5KB size is a relatively small sized/quality SVG image.

This will make some on-chain/dynamic NFTs unable to be Bridged from L1 to L2 as even transferring a single NFT will exceed the payload length.

Proof of Concept

We will prove that a small-sized SVG image is encoded into more than 8587 characters.

  1. Open this website base64.guru that is used to convert SVG into a Base64.

  2. We uploaded an image of ~23.3KB for testing, link.

  3. Download the image, upload it, and encode it.

  4. Choose the Data URI encoding type.

  5. Copy the output Base64 and check for its length.

  6. You can use node script to declare the string to it, and then retrieve its length.

  7. The output length is 31031.

By doing calculations to determine the minimum SVG image size that will exceed 300 payload length: (8587 ÷ 31031) × 23.3 ~= 6.45 KB.

So if the SVG image size is >= 6.45 KB and it is an on-chain/dynamic NFT encoded on-chain, bridging even a single token for that NFT collection is impossible.

Impact

Inability to bridge some on-chain/dynamic NFTs from L1 to L2.

Tools Used

Manual Review

Recommendations

Since limiting the Payload length is important, and even increasing it is not the best solution. We need to support transferring NFTs without tokenURIs, whether they have a base URI or not.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid-dynamic-NFT-on-chain-not-supported-if-too-large

Great catch ! Unfortunately, there is no real impact here. Impact: Informational, no deposit possible and transmit the token URI is a design choice. Likelyhood: Very Low because those specific token are rare.

Support

FAQs

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