Skip to content

Commit e64256e

Browse files
authored
Audit Fix (#838)
1 parent 18b49b2 commit e64256e

File tree

3 files changed

+765
-63
lines changed

3 files changed

+765
-63
lines changed

contracts/contracts/l2/system/IL2TokenRegistry.sol

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,18 @@ interface IL2TokenRegistry {
5858
Errors
5959
//////////////////////////////////////////////////////////////*/
6060

61-
error TokenAlreadyRegistered();
61+
error TokenIDAlreadyRegistered();
62+
error TokenAddressAlreadyRegistered();
6263
error TokenNotFound();
6364
error InvalidTokenID();
6465
error InvalidTokenAddress();
6566
error InvalidBalanceSlot();
6667
error InvalidScale();
6768
error InvalidPrice();
68-
error InvalidPercent();
6969
error CallerNotAllowed();
7070
error InvalidArrayLength();
7171
error DifferentLength();
72-
error AlreadyInitialized();
72+
error ZeroTokenAmount();
7373

7474
/*//////////////////////////////////////////////////////////////
7575
Allow List Functions
@@ -192,9 +192,10 @@ interface IL2TokenRegistry {
192192
/**
193193
* @notice Get token information
194194
* @param _tokenID Token ID
195-
* @return TokenInfo structure
195+
* @return info TokenInfo structure with actual balanceSlot (automatically -1 from stored value)
196+
* @return hasBalanceSlot Whether balanceSlot was stored with +1 offset (true = slot was adjusted)
196197
*/
197-
function getTokenInfo(uint16 _tokenID) external view returns (TokenInfo memory);
198+
function getTokenInfo(uint16 _tokenID) external view returns (TokenInfo memory info, bool hasBalanceSlot);
198199

199200
/**
200201
* @notice Get token ID by address

contracts/contracts/l2/system/L2TokenRegistry.sol

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
3232
mapping(address user => bool allowed) public allowList;
3333

3434
/// @notice Whether whitelist is enabled
35-
bool public allowListEnabled = true;
35+
bool public allowListEnabled;
3636

3737
/// @notice Set of supported token IDs
3838
EnumerableSetUpgradeable.UintSet private supportedTokenSet;
@@ -45,7 +45,13 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
4545
* @notice Check if caller is in Allow List
4646
*/
4747
modifier onlyAllowed() {
48-
if (allowListEnabled && !allowList[msg.sender] && msg.sender != owner()) {
48+
bool isOwner = msg.sender == owner();
49+
bool isAllowedByList = allowListEnabled && allowList[msg.sender];
50+
51+
// Owner always has access
52+
// When allowList is enabled, allowList users can access
53+
// When allowList is disabled, only owner can access
54+
if (!isOwner && !isAllowedByList) {
4955
revert CallerNotAllowed();
5056
}
5157
_;
@@ -215,8 +221,8 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
215221

216222
// Forbid zero ID and enforce uniqueness for both ID and address
217223
if (_tokenID == 0) revert InvalidTokenID();
218-
if (tokenRegistry[_tokenID].tokenAddress != address(0)) revert TokenAlreadyRegistered();
219-
if (tokenRegistration[_tokenAddress] != 0) revert TokenAlreadyRegistered();
224+
if (tokenRegistry[_tokenID].tokenAddress != address(0)) revert TokenIDAlreadyRegistered();
225+
if (tokenRegistration[_tokenAddress] != 0) revert TokenAddressAlreadyRegistered();
220226

221227
// Validate scale is non-zero
222228
if (_scale == 0) revert InvalidScale();
@@ -266,9 +272,12 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
266272
// Check new information
267273
if (_tokenAddress == address(0)) revert InvalidTokenAddress();
268274

275+
// Check new scale
276+
if (_scale == 0) revert InvalidScale();
277+
269278
// Prevent address being shared across different tokenIDs
270279
uint16 existing = tokenRegistration[_tokenAddress];
271-
if (existing != 0 && existing != _tokenID) revert TokenAlreadyRegistered();
280+
if (existing != 0 && existing != _tokenID) revert TokenAddressAlreadyRegistered();
272281

273282
// Get decimals from contract
274283
uint8 decimals = 18; // Default value
@@ -294,6 +303,10 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
294303
tokenRegistration[_tokenAddress] = _tokenID;
295304
}
296305

306+
// Reset priceRatio to 0 to ensure consistency
307+
// priceRatio depends on scale and decimals, so it must be recalculated after tokenInfo changes
308+
priceRatio[_tokenID] = 0;
309+
297310
// Note: tokenID should already be in supportedTokenSet from registration
298311
// No need to add again as EnumerableSet.add() is idempotent but wastes gas
299312

@@ -403,10 +416,7 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
403416
* @notice Calculate the corresponding token amount for a given ETH amount
404417
* @dev Calculation formula:
405418
* - ratio = tokenScale * (tokenPrice / ethPrice) * 10^(ethDecimals - tokenDecimals)
406-
* - tokenAmount = (ethAmount * 10^tokenDecimals) / ratio
407-
* - Substituting ratio: tokenAmount = (ethAmount * 10^tokenDecimals) / (tokenScale * (tokenPrice / ethPrice) * 10^(18 - tokenDecimals))
408-
* - Simplified: tokenAmount = (ethAmount * 10^tokenDecimals * 10^tokenDecimals) / (tokenScale * tokenPrice * 10^18 / ethPrice)
409-
* - Final: tokenAmount = (ethAmount * ethPrice * 10^tokenDecimals) / (tokenScale * tokenPrice * 10^18)
419+
* - tokenAmount = ⌈(ethAmount × tokenScale) / tokenRate⌉
410420
* - Note: Uses ceiling division to ensure users receive fair token amounts
411421
* @param _tokenID Token ID of the ERC20 token
412422
* @param _ethAmount ETH amount (unit: wei)
@@ -432,24 +442,27 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
432442
uint256 numerator = _ethAmount * uint256(info.scale);
433443
tokenAmount = (numerator + ratio - 1) / ratio;
434444

435-
if (tokenAmount == 0) revert InvalidPrice();
445+
if (tokenAmount == 0) revert ZeroTokenAmount();
436446

437447
return tokenAmount;
438448
}
439449

440450
/**
441451
* @notice Get token information
442452
* @param _tokenID Token ID
443-
* @return TokenInfo structure with actual balanceSlot (automatically -1 from stored value)
453+
* @return info TokenInfo structure with actual balanceSlot (automatically -1 from stored value)
454+
* @return hasBalanceSlot Whether balanceSlot was stored with +1 offset (true = slot was adjusted)
444455
*/
445-
function getTokenInfo(uint16 _tokenID) external view returns (TokenInfo memory) {
456+
function getTokenInfo(uint16 _tokenID) external view returns (TokenInfo memory info, bool hasBalanceSlot) {
446457
if (tokenRegistry[_tokenID].tokenAddress == address(0)) revert TokenNotFound();
447458

448-
TokenInfo memory info = tokenRegistry[_tokenID];
459+
info = tokenRegistry[_tokenID];
460+
// Check if balanceSlot was stored (non-zero means it was stored with +1 offset)
461+
hasBalanceSlot = info.balanceSlot != bytes32(0);
449462
// Convert stored balanceSlot to actual value
450463
info.balanceSlot = _toActualBalanceSlot(info.balanceSlot);
451464

452-
return info;
465+
return (info, hasBalanceSlot);
453466
}
454467

455468
/**
@@ -481,6 +494,10 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
481494
if (_newScale == 0) revert InvalidScale();
482495
tokenRegistry[_tokenID].scale = _newScale;
483496

497+
// Reset priceRatio to 0 to ensure consistency
498+
// priceRatio depends on scale, so it must be recalculated after scale changes
499+
priceRatio[_tokenID] = 0;
500+
484501
emit TokenScaleUpdated(_tokenID, _newScale);
485502
}
486503

0 commit comments

Comments
 (0)