Era

ZKsync
FoundryLayer 2
500,000 USDC
View results
Submission Details
Severity: medium
Valid

Missing Return Value in _ensureTokenRegisteredWithNTV Function

Here's a potential security report for this issue:

Missing Return Value in _ensureTokenRegisteredWithNTV Function

Impact

High. The _ensureTokenRegisteredWithNTV function declares a return value (bytes32 assetId) but fails to assign or return any value. This causes the function to return bytes32(0) by default, which is then used in critical withdrawal functionality through the withdrawToken function.

Proof of Concept

// Function declares return value but doesn't return anything
function _ensureTokenRegisteredWithNTV(address _token) internal override returns (bytes32 assetId) {
IL2NativeTokenVault nativeTokenVault = IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR);
nativeTokenVault.ensureTokenIsRegistered(_token);
// No return statement or named return value assignment
}
// The zero assetId is then used here
function withdrawToken(address _l2NativeToken, bytes memory _assetData) public returns (bytes32) {
// ... previous checks ...
bytes32 assetId = _ensureTokenRegisteredWithNTV(_l2NativeToken); // Will always be bytes32(0)
return _withdrawSender(assetId, _assetData, msg.sender, true); // Withdrawal uses incorrect assetId
}

Description

The _ensureTokenRegisteredWithNTV function is intended to ensure a token is registered with the Native Token Vault and return its corresponding assetId. However, while the function declares it will return a bytes32 assetId, it never actually assigns or returns a value. In Solidity, when a function declares a return value but doesn't explicitly return anything, it returns the default value for that type (in this case bytes32(0)).

This zero value is then used in the withdrawToken function as the assetId parameter for _withdrawSender, which could lead to:

  1. Failed withdrawals

  2. Potential loss of assets if the zero assetId is interpreted as a valid asset identifier

  3. Inconsistent state between L1 and L2

Recommended Mitigation

The function should properly return the asset ID after registering the token:

function _ensureTokenRegisteredWithNTV(address _token) internal override returns (bytes32 assetId) {
IL2NativeTokenVault nativeTokenVault = IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR);
nativeTokenVault.ensureTokenIsRegistered(_token);
return nativeTokenVault.assetId(_token); // Return the actual assetId
}

Tools Used

Manual review

Updates

Lead Judging Commences

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`L2AssetRouter._ensureTokenRegisteredWithNTV` `assetId` return value is never assigned, which will cause `withdrawToken` to fail

Appeal created

inallhonesty Lead Judge
5 months ago
inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`L2AssetRouter._ensureTokenRegisteredWithNTV` `assetId` return value is never assigned, which will cause `withdrawToken` to fail

Support

FAQs

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