Files
smom-dbis-138/contracts/iso4217w/registry/TokenRegistry.sol
2026-03-02 12:14:09 -08:00

156 lines
5.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "../interfaces/ITokenRegistry.sol";
import "../libraries/ISO4217WCompliance.sol";
/**
* @title TokenRegistry
* @notice Canonical registry mapping ISO-4217 codes to W token addresses
* @dev Registry is immutable once published (tokens can be deactivated but not removed)
*/
contract TokenRegistry is ITokenRegistry, AccessControl {
bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE");
// Currency code => TokenInfo
mapping(string => TokenInfo) private _tokens;
// Track all registered currency codes
string[] private _registeredCurrencies;
mapping(string => bool) private _isRegistered;
constructor(address admin) {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(REGISTRAR_ROLE, admin);
}
/**
* @notice Register a new ISO-4217 W token
* @param currencyCode ISO-4217 currency code (must be valid ISO-4217)
* @param tokenAddress Token contract address
* @param tokenSymbol Token symbol (should be <CCC>W format)
* @param decimals Token decimals (typically 2 for fiat currencies)
* @param custodian Custodian address
*/
function registerToken(
string memory currencyCode,
address tokenAddress,
string memory tokenSymbol,
uint8 decimals,
address custodian
) external override onlyRole(REGISTRAR_ROLE) {
require(tokenAddress != address(0), "TokenRegistry: zero token address");
require(custodian != address(0), "TokenRegistry: zero custodian");
require(!_isRegistered[currencyCode], "TokenRegistry: already registered");
// Validate ISO-4217 format
require(
ISO4217WCompliance.isValidISO4217Format(currencyCode),
"TokenRegistry: invalid ISO-4217 format"
);
// Validate GRU isolation
require(
!ISO4217WCompliance.violatesGRUIsolation(currencyCode),
"TokenRegistry: GRU isolation violation"
);
// Validate token symbol matches <CCC>W pattern
require(
ISO4217WCompliance.validateTokenSymbol(currencyCode, tokenSymbol),
"TokenRegistry: token symbol must be <CCC>W"
);
// Create token info
TokenInfo memory info = TokenInfo({
tokenAddress: tokenAddress,
currencyCode: currencyCode,
tokenSymbol: tokenSymbol,
decimals: decimals,
custodian: custodian,
mintController: address(0), // Set separately
burnController: address(0), // Set separately
isActive: true,
createdAt: block.timestamp
});
_tokens[currencyCode] = info;
_registeredCurrencies.push(currencyCode);
_isRegistered[currencyCode] = true;
emit TokenRegistered(currencyCode, tokenAddress, tokenSymbol, custodian);
}
/**
* @notice Set mint controller for a currency
* @param currencyCode ISO-4217 currency code
* @param mintController Mint controller address
*/
function setMintController(string memory currencyCode, address mintController) external onlyRole(REGISTRAR_ROLE) {
require(_isRegistered[currencyCode], "TokenRegistry: not registered");
require(mintController != address(0), "TokenRegistry: zero address");
_tokens[currencyCode].mintController = mintController;
}
/**
* @notice Set burn controller for a currency
* @param currencyCode ISO-4217 currency code
* @param burnController Burn controller address
*/
function setBurnController(string memory currencyCode, address burnController) external onlyRole(REGISTRAR_ROLE) {
require(_isRegistered[currencyCode], "TokenRegistry: not registered");
require(burnController != address(0), "TokenRegistry: zero address");
_tokens[currencyCode].burnController = burnController;
}
/**
* @notice Get token address for ISO-4217 code
* @param currencyCode ISO-4217 currency code
* @return tokenAddress Token contract address
*/
function getTokenAddress(string memory currencyCode) external view override returns (address tokenAddress) {
require(_isRegistered[currencyCode], "TokenRegistry: not registered");
return _tokens[currencyCode].tokenAddress;
}
/**
* @notice Get token info for ISO-4217 code
* @param currencyCode ISO-4217 currency code
* @return info Token information
*/
function getTokenInfo(string memory currencyCode) external view override returns (TokenInfo memory info) {
require(_isRegistered[currencyCode], "TokenRegistry: not registered");
return _tokens[currencyCode];
}
/**
* @notice Check if currency code is registered
* @param currencyCode ISO-4217 currency code
* @return registered True if registered
*/
function isRegistered(string memory currencyCode) external view override returns (bool registered) {
return _isRegistered[currencyCode];
}
/**
* @notice Deactivate a token (emergency)
* @param currencyCode ISO-4217 currency code
*/
function deactivateToken(string memory currencyCode) external override onlyRole(REGISTRAR_ROLE) {
require(_isRegistered[currencyCode], "TokenRegistry: not registered");
require(_tokens[currencyCode].isActive, "TokenRegistry: already inactive");
_tokens[currencyCode].isActive = false;
emit TokenDeactivated(currencyCode, block.timestamp);
}
/**
* @notice Get all registered currency codes
* @return currencies Array of registered currency codes
*/
function getRegisteredCurrencies() external view returns (string[] memory currencies) {
return _registeredCurrencies;
}
}