// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/AccessControl.sol"; contract StablecoinReferenceRegistry is AccessControl { bytes32 public constant STABLECOIN_REGISTRAR_ROLE = keccak256("STABLECOIN_REGISTRAR"); enum StablecoinStatus { ACTIVE, SUSPENDED, REVOKED } struct StablecoinEntry { string tokenSymbol; address tokenAddress; string issuerOrBridge; string legalClaimType; string redemptionPath; string reserveDisclosureRef; uint8 riskTier; address pauseAuthority; StablecoinStatus status; bool exists; } mapping(address => StablecoinEntry) private _byAddress; address[] private _addressList; event StablecoinRegistered( address indexed tokenAddress, string tokenSymbol, StablecoinStatus status ); event StablecoinStatusUpdated(address indexed tokenAddress, StablecoinStatus status); constructor(address admin) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(STABLECOIN_REGISTRAR_ROLE, admin); } function register( address tokenAddress, string calldata tokenSymbol, string calldata issuerOrBridge, string calldata legalClaimType, string calldata redemptionPath, string calldata reserveDisclosureRef, uint8 riskTier, address pauseAuthority ) external onlyRole(STABLECOIN_REGISTRAR_ROLE) { require(tokenAddress != address(0), "DBIS: zero address"); require(!_byAddress[tokenAddress].exists, "DBIS: already registered"); _setEntry(tokenAddress, tokenSymbol, issuerOrBridge, legalClaimType, redemptionPath, reserveDisclosureRef, riskTier, pauseAuthority); _addressList.push(tokenAddress); emit StablecoinRegistered(tokenAddress, tokenSymbol, StablecoinStatus.ACTIVE); } function _setEntry( address tokenAddress, string calldata tokenSymbol, string calldata issuerOrBridge, string calldata legalClaimType, string calldata redemptionPath, string calldata reserveDisclosureRef, uint8 riskTier, address pauseAuthority ) private { StablecoinEntry storage e = _byAddress[tokenAddress]; e.tokenSymbol = tokenSymbol; e.tokenAddress = tokenAddress; e.issuerOrBridge = issuerOrBridge; e.legalClaimType = legalClaimType; e.redemptionPath = redemptionPath; e.reserveDisclosureRef = reserveDisclosureRef; e.riskTier = riskTier; e.pauseAuthority = pauseAuthority; e.status = StablecoinStatus.ACTIVE; e.exists = true; } function setStatus(address tokenAddress, StablecoinStatus status) external onlyRole(STABLECOIN_REGISTRAR_ROLE) { require(_byAddress[tokenAddress].exists, "DBIS: not registered"); _byAddress[tokenAddress].status = status; emit StablecoinStatusUpdated(tokenAddress, status); } function getEntry(address tokenAddress) external view returns (StablecoinEntry memory) { return _byAddress[tokenAddress]; } function isActive(address tokenAddress) external view returns (bool) { return _byAddress[tokenAddress].exists && _byAddress[tokenAddress].status == StablecoinStatus.ACTIVE; } function getRegisteredCount() external view returns (uint256) { return _addressList.length; } function getRegisteredAt(uint256 index) external view returns (address) { require(index < _addressList.length, "DBIS: index"); return _addressList[index]; } }