156 lines
5.8 KiB
Solidity
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;
|
|
}
|
|
}
|