Files
smom-dbis-138/contracts/tokens/CompliantWrappedToken.sol

291 lines
12 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "../interfaces/IRegulatedAssetMetadata.sol";
/**
* @title CompliantWrappedToken
* @notice ERC-20 wrapper for bridged compliant tokens (cWUSDT, cWUSDC, etc.) on public chains.
* @dev Only MINTER_ROLE can mint (e.g. CCIP receiver/bridge); BURNER_ROLE can burn (bridge-back).
* Admin can grant/revoke roles. Used for cW* representation of Chain 138 compliant tokens.
*/
contract CompliantWrappedToken is ERC20, AccessControl, IRegulatedAssetMetadata {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE");
bytes32 public constant JURISDICTION_ADMIN_ROLE = keccak256("JURISDICTION_ADMIN_ROLE");
bytes32 public constant REGULATOR_ROLE = keccak256("REGULATOR_ROLE");
bytes32 public constant SUPERVISOR_ROLE = keccak256("SUPERVISOR_ROLE");
bytes32 public constant EMERGENCY_ADMIN_ROLE = keccak256("EMERGENCY_ADMIN_ROLE");
uint8 private immutable _decimalsStorage;
bool public operationalRolesFrozen;
address public governanceController;
bytes32 public immutable assetId;
bytes32 public immutable assetVersionId;
bytes32 public governanceProfileId;
bytes32 public supervisionProfileId;
bytes32 public storageNamespace;
string public primaryJurisdiction;
string private _regulatoryDisclosureURI;
string private _reportingURI;
address public canonicalUnderlyingAsset;
bool public supervisionRequired;
bool public governmentApprovalRequired;
uint256 public minimumUpgradeNoticePeriod;
event OperationalRolesFrozen(address indexed caller);
event GovernanceProfileUpdated(bytes32 governanceProfileId);
event SupervisionProfileUpdated(bytes32 supervisionProfileId);
event StorageNamespaceUpdated(bytes32 storageNamespace);
event PrimaryJurisdictionUpdated(string jurisdiction);
event RegulatoryDisclosureURIUpdated(string disclosureURI);
event ReportingURIUpdated(string reportingURI);
event CanonicalUnderlyingAssetUpdated(address canonicalUnderlyingAsset);
event SupervisionConfigurationUpdated(
bool supervisionRequired,
bool governmentApprovalRequired,
uint256 minimumUpgradeNoticePeriod
);
event RegulatoryApprovalRecorded(bytes32 indexed approvalId, string actionType, bytes32 referenceHash);
event SupervisoryNoticeRecorded(bytes32 indexed noticeId, string category, string uri);
error OperationalRolesAreFrozen();
error GovernanceControllerOnly(address caller);
error GovernanceControllerNotConfigured();
error ZeroGovernanceController();
modifier onlyGovernanceExecution() {
if (governanceController == address(0)) revert GovernanceControllerNotConfigured();
if (msg.sender != governanceController) revert GovernanceControllerOnly(msg.sender);
_;
}
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
address admin_
) ERC20(name_, symbol_) {
_decimalsStorage = decimals_;
assetId = keccak256(bytes(string.concat("GRU:", symbol_)));
assetVersionId = keccak256(bytes(string.concat("GRU:", symbol_, ":transport")));
governanceProfileId = keccak256(bytes(string.concat("GRU:GOV:", symbol_, ":transport")));
supervisionProfileId = keccak256(bytes(string.concat("GRU:SUP:", symbol_, ":transport")));
storageNamespace = keccak256(bytes(string.concat("gru.storage.transport.", symbol_)));
primaryJurisdiction = "Destination Public Network";
supervisionRequired = true;
minimumUpgradeNoticePeriod = 7 days;
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
_grantRole(MINTER_ROLE, admin_);
_grantRole(BURNER_ROLE, admin_);
_grantRole(GOVERNANCE_ROLE, admin_);
_grantRole(JURISDICTION_ADMIN_ROLE, admin_);
_grantRole(REGULATOR_ROLE, admin_);
_grantRole(SUPERVISOR_ROLE, admin_);
_grantRole(EMERGENCY_ADMIN_ROLE, admin_);
}
function decimals() public view override returns (uint8) {
return _decimalsStorage;
}
function wrappedTransport() external pure returns (bool) {
return true;
}
function regulatoryDisclosureURI() external view returns (string memory) {
return _regulatoryDisclosureURI;
}
function reportingURI() external view returns (string memory) {
return _reportingURI;
}
/**
* @notice Permanently freeze future MINTER_ROLE / BURNER_ROLE changes.
* @dev Existing bridge roles keep working; only admin churn is disabled.
*/
function freezeOperationalRoles() external onlyRole(DEFAULT_ADMIN_ROLE) {
if (operationalRolesFrozen) {
return;
}
operationalRolesFrozen = true;
emit OperationalRolesFrozen(msg.sender);
}
function grantRole(bytes32 role, address account) public override onlyRole(getRoleAdmin(role)) {
_revertIfFrozenOperationalRole(role);
super.grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public override onlyRole(getRoleAdmin(role)) {
_revertIfFrozenOperationalRole(role);
super.revokeRole(role, account);
}
function setGovernanceController(address governanceController_) external onlyRole(EMERGENCY_ADMIN_ROLE) {
if (governanceController_ == address(0)) revert ZeroGovernanceController();
governanceController = governanceController_;
}
function setGovernanceProfileId(bytes32 governanceProfileId_) external onlyGovernanceExecution {
_setGovernanceProfileIdValue(governanceProfileId_);
}
function setSupervisionProfileId(bytes32 supervisionProfileId_) external onlyGovernanceExecution {
_setSupervisionProfileIdValue(supervisionProfileId_);
}
function setStorageNamespace(bytes32 storageNamespace_) external onlyGovernanceExecution {
_setStorageNamespaceValue(storageNamespace_);
}
function setPrimaryJurisdiction(string calldata jurisdiction_) external onlyGovernanceExecution {
_setPrimaryJurisdictionValue(jurisdiction_);
}
function setRegulatoryDisclosureURI(string calldata disclosureURI_) external onlyGovernanceExecution {
_setRegulatoryDisclosureURIValue(disclosureURI_);
}
function setReportingURI(string calldata reportingURI_) external onlyGovernanceExecution {
_setReportingURIValue(reportingURI_);
}
function setCanonicalUnderlyingAsset(address canonicalUnderlyingAsset_) external onlyGovernanceExecution {
_setCanonicalUnderlyingAssetValue(canonicalUnderlyingAsset_);
}
function setSupervisionConfiguration(
bool supervisionRequired_,
bool governmentApprovalRequired_,
uint256 minimumUpgradeNoticePeriod_
) external onlyGovernanceExecution {
_setSupervisionConfigurationValue(
supervisionRequired_,
governmentApprovalRequired_,
minimumUpgradeNoticePeriod_
);
}
function emergencySetGovernanceMetadata(
bytes32 governanceProfileId_,
bytes32 supervisionProfileId_,
bytes32 storageNamespace_,
string calldata jurisdiction_,
address canonicalUnderlyingAsset_,
bool supervisionRequired_,
bool governmentApprovalRequired_,
uint256 minimumUpgradeNoticePeriod_
) external onlyRole(EMERGENCY_ADMIN_ROLE) {
_setGovernanceProfileIdValue(governanceProfileId_);
_setSupervisionProfileIdValue(supervisionProfileId_);
_setStorageNamespaceValue(storageNamespace_);
_setPrimaryJurisdictionValue(jurisdiction_);
_setCanonicalUnderlyingAssetValue(canonicalUnderlyingAsset_);
_setSupervisionConfigurationValue(
supervisionRequired_,
governmentApprovalRequired_,
minimumUpgradeNoticePeriod_
);
}
function emergencySetDisclosureMetadata(
string calldata disclosureURI_,
string calldata reportingURI_
) external onlyRole(EMERGENCY_ADMIN_ROLE) {
_setRegulatoryDisclosureURIValue(disclosureURI_);
_setReportingURIValue(reportingURI_);
}
function recordRegulatoryApproval(
bytes32 approvalId,
string calldata actionType,
bytes32 referenceHash
) external onlyRole(REGULATOR_ROLE) {
emit RegulatoryApprovalRecorded(approvalId, actionType, referenceHash);
}
function recordSupervisoryNotice(
bytes32 noticeId,
string calldata category,
string calldata uri
) external onlyRole(SUPERVISOR_ROLE) {
emit SupervisoryNoticeRecorded(noticeId, category, uri);
}
/// @notice Mint to account (only MINTER_ROLE, e.g. bridge receiver).
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
/// @notice Burn from account (only BURNER_ROLE, e.g. bridge for burn-on-exit).
function burn(address from, uint256 amount) external onlyRole(BURNER_ROLE) {
_burn(from, amount);
}
/// @notice Burn from account (only BURNER_ROLE). Enables TwoWayTokenBridgeL2 and other bridges that call burnFrom(user, amount) for outbound.
function burnFrom(address from, uint256 amount) external onlyRole(BURNER_ROLE) {
_burn(from, amount);
}
function _revertIfFrozenOperationalRole(bytes32 role) internal view {
if (operationalRolesFrozen && (role == MINTER_ROLE || role == BURNER_ROLE)) {
revert OperationalRolesAreFrozen();
}
}
function _setGovernanceProfileIdValue(bytes32 governanceProfileId_) internal {
governanceProfileId = governanceProfileId_;
emit GovernanceProfileUpdated(governanceProfileId_);
}
function _setSupervisionProfileIdValue(bytes32 supervisionProfileId_) internal {
supervisionProfileId = supervisionProfileId_;
emit SupervisionProfileUpdated(supervisionProfileId_);
}
function _setStorageNamespaceValue(bytes32 storageNamespace_) internal {
storageNamespace = storageNamespace_;
emit StorageNamespaceUpdated(storageNamespace_);
}
function _setPrimaryJurisdictionValue(string memory jurisdiction_) internal {
primaryJurisdiction = jurisdiction_;
emit PrimaryJurisdictionUpdated(jurisdiction_);
}
function _setRegulatoryDisclosureURIValue(string memory disclosureURI_) internal {
_regulatoryDisclosureURI = disclosureURI_;
emit RegulatoryDisclosureURIUpdated(disclosureURI_);
}
function _setReportingURIValue(string memory reportingURI_) internal {
_reportingURI = reportingURI_;
emit ReportingURIUpdated(reportingURI_);
}
function _setCanonicalUnderlyingAssetValue(address canonicalUnderlyingAsset_) internal {
canonicalUnderlyingAsset = canonicalUnderlyingAsset_;
emit CanonicalUnderlyingAssetUpdated(canonicalUnderlyingAsset_);
}
function _setSupervisionConfigurationValue(
bool supervisionRequired_,
bool governmentApprovalRequired_,
uint256 minimumUpgradeNoticePeriod_
) internal {
supervisionRequired = supervisionRequired_;
governmentApprovalRequired = governmentApprovalRequired_;
minimumUpgradeNoticePeriod = minimumUpgradeNoticePeriod_;
emit SupervisionConfigurationUpdated(
supervisionRequired_,
governmentApprovalRequired_,
minimumUpgradeNoticePeriod_
);
}
}