@@ -3,6 +3,7 @@ pragma solidity =0.8.24;
33
44import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol " ;
55import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol " ;
6+ import {EnumerableSetUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol " ;
67import {IL2TokenRegistry} from "./IL2TokenRegistry.sol " ;
78
89interface IERC20Infos {
@@ -15,6 +16,7 @@ interface IERC20Infos {
1516 * @notice In the transaction scenario where ERC20 is used as gas fee payment, used for storing prices and token registration functionality
1617 */
1718contract L2TokenRegistry is IL2TokenRegistry , OwnableUpgradeable , ReentrancyGuardUpgradeable {
19+ using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet;
1820
1921 /// @notice Mapping from tokenID to TokenInfo
2022 mapping (uint16 => TokenInfo) public tokenRegistry;
@@ -32,6 +34,9 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
3234 /// @notice Whether whitelist is enabled
3335 bool public allowListEnabled = true ;
3436
37+ /// @notice Set of supported token IDs
38+ EnumerableSetUpgradeable.UintSet private supportedTokenSet;
39+
3540 /*//////////////////////////////////////////////////////////////
3641 Modifier
3742 //////////////////////////////////////////////////////////////*/
@@ -137,6 +142,22 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
137142 _registerSingleToken (_tokenID, _tokenAddress, _balanceSlot, _scale);
138143 }
139144
145+ /**
146+ * @notice Internal function: Add token ID to supported list
147+ * @param _tokenID Token ID to add
148+ */
149+ function _addTokenToList (uint16 _tokenID ) internal {
150+ supportedTokenSet.add (uint256 (_tokenID));
151+ }
152+
153+ /**
154+ * @notice Internal function: Remove token ID from supported list
155+ * @param _tokenID Token ID to remove
156+ */
157+ function _removeTokenFromList (uint16 _tokenID ) internal {
158+ supportedTokenSet.remove (uint256 (_tokenID));
159+ }
160+
140161 /**
141162 * @notice Internal function: Register a single token
142163 */
@@ -170,6 +191,7 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
170191 scale: _scale
171192 });
172193 tokenRegistration[_tokenAddress] = _tokenID;
194+ _addTokenToList (_tokenID);
173195 emit TokenRegistered (_tokenID, _tokenAddress, _balanceSlot, false , decimals, _scale);
174196 }
175197
@@ -221,9 +243,32 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
221243 tokenRegistration[_tokenAddress] = _tokenID;
222244 }
223245
246+ // Note: tokenID should already be in supportedTokenSet from registration
247+ // No need to add again as EnumerableSet.add() is idempotent but wastes gas
248+
224249 emit TokenInfoUpdated (_tokenID, _tokenAddress, _balanceSlot, _isActive, decimals, _scale);
225250 }
226251
252+ /**
253+ * @notice Remove a token from registry
254+ * @param _tokenID Token ID to remove
255+ */
256+ function removeToken (uint16 _tokenID ) external onlyOwner nonReentrant {
257+ // Check if token exists
258+ address tokenAddress = tokenRegistry[_tokenID].tokenAddress;
259+ if (tokenAddress == address (0 )) revert TokenNotFound ();
260+
261+ // Remove from mappings
262+ delete tokenRegistry[_tokenID];
263+ delete tokenRegistration[tokenAddress];
264+ delete priceRatio[_tokenID];
265+
266+ // Remove from supported list
267+ _removeTokenFromList (_tokenID);
268+
269+ emit TokenRemoved (_tokenID, tokenAddress);
270+ }
271+
227272 /**
228273 * @notice Batch update token activation status
229274 * @param _tokenIDs Array of token IDs
@@ -400,6 +445,58 @@ contract L2TokenRegistry is IL2TokenRegistry, OwnableUpgradeable, ReentrancyGuar
400445 return tokenRegistry[_tokenID].isActive;
401446 }
402447
448+ /**
449+ * @notice Check if a token ID is in the supported list
450+ * @param _tokenID Token ID to check
451+ * @return Whether the token ID is registered
452+ */
453+ function isTokenSupported (uint16 _tokenID ) external view returns (bool ) {
454+ return supportedTokenSet.contains (uint256 (_tokenID));
455+ }
456+
457+ /**
458+ * @notice Get all supported token IDs and their addresses
459+ * @return Array of TokenEntry containing token ID and address pairs
460+ */
461+ function getSupportedTokenList () external view returns (TokenEntry[] memory ) {
462+ uint256 [] memory values = supportedTokenSet.values ();
463+ TokenEntry[] memory tokenList = new TokenEntry [](values.length );
464+
465+ for (uint256 i = 0 ; i < values.length ; ++ i) {
466+ uint16 tokenID = uint16 (values[i]);
467+ address tokenAddress = tokenRegistry[tokenID].tokenAddress;
468+ tokenList[i] = TokenEntry ({
469+ tokenID: tokenID,
470+ tokenAddress: tokenAddress
471+ });
472+ }
473+
474+ return tokenList;
475+ }
476+
477+ /**
478+ * @notice Get all supported token IDs
479+ * @return Array of all registered token IDs
480+ */
481+ function getSupportedIDList () external view returns (uint16 [] memory ) {
482+ uint256 [] memory values = supportedTokenSet.values ();
483+ uint16 [] memory tokenIDs = new uint16 [](values.length );
484+
485+ for (uint256 i = 0 ; i < values.length ; ++ i) {
486+ tokenIDs[i] = uint16 (values[i]);
487+ }
488+
489+ return tokenIDs;
490+ }
491+
492+ /**
493+ * @notice Get the count of supported tokens
494+ * @return The number of registered tokens
495+ */
496+ function getSupportedTokenCount () external view returns (uint256 ) {
497+ return supportedTokenSet.length ();
498+ }
499+
403500 // Reserve storage space to allow future layout changes
404501 uint256 [50 ] private __gap;
405502}
0 commit comments