UserRegistry is an upgradeable version of PermissionedRegistry designed for user-created subregistries. It implements the UUPS (Universal Upgradeable Proxy Standard) pattern, allowing registry administrators to upgrade the implementation while preserving all registration data.
function _authorizeUpgrade( address newImplementation) internal override onlyRootRoles(RegistryRolesLib.ROLE_UPGRADE)
Authorizes an upgrade to a new implementation contract.Requires: ROLE_UPGRADE on ROOT_RESOURCEParameters:
newImplementation - Address of the new implementation contract
Example Upgrade Flow:
// 1. Deploy new implementationUserRegistryV2 newImplementation = new UserRegistryV2( hcaFactory, metadataProvider);// 2. Upgrade the proxy (must have ROLE_UPGRADE)UserRegistry proxy = UserRegistry(proxyAddress);proxy.upgradeToAndCall( address(newImplementation), "" // Optional initialization data for new version);// 3. Proxy now uses new implementation// All data (registrations, roles, etc.) preserved
The upgrade authorization happens automatically through the onlyRootRoles modifier. Only accounts with ROLE_UPGRADE can successfully upgrade.
// Deploy registry for dao.ethUserRegistry daoRegistry = UserRegistry( verifiableFactory.deployProxy( implementation, keccak256(abi.encodePacked("dao.eth", block.timestamp)), abi.encodeCall( UserRegistry.initialize, ( daoGovernance, RegistryRolesLib.ROLE_REGISTRAR | RegistryRolesLib.ROLE_REGISTRAR_ADMIN | RegistryRolesLib.ROLE_UPGRADE | RegistryRolesLib.ROLE_UPGRADE_ADMIN ) ) ));// Set as subregistry of dao.ethethRegistry.setSubregistry(daoTokenId, IRegistry(address(daoRegistry)));// DAO can now manage its subdomains// governance.dao.eth, treasury.dao.eth, etc.
// Initialize with primary adminregistry.initialize( projectLead, RegistryRolesLib.ROLE_REGISTRAR | RegistryRolesLib.ROLE_REGISTRAR_ADMIN);// Grant registrar rights to team membersregistry.grantRoles( ROOT_RESOURCE, RegistryRolesLib.ROLE_REGISTRAR, teamMember1);registry.grantRoles( ROOT_RESOURCE, RegistryRolesLib.ROLE_REGISTRAR, teamMember2);// Separate upgrade authorityregistry.grantRoles( ROOT_RESOURCE, RegistryRolesLib.ROLE_UPGRADE, upgradeController);
// UserRegistryV2 adds new featurescontract UserRegistryV2 is UserRegistry { // New storage (must be appended) uint256 public newFeatureData; function newFeature() public { // New functionality }}// Deploy new implementationUserRegistryV2 newImpl = new UserRegistryV2(hcaFactory, metadata);// Upgrade existing proxyregistry.upgradeToAndCall(address(newImpl), "");// Existing data preserved, new features availableUserRegistryV2(address(registry)).newFeature();
Storage Layout: New versions must not modify existing storage variables. Only append new storage variables to maintain compatibility.
// Critical bug fix neededUserRegistry fixedImplementation = new UserRegistry( hcaFactory, metadata);// Admin with ROLE_UPGRADE can immediately upgraderegistry.upgradeToAndCall(address(fixedImplementation), "");// All proxies need individual upgrade calls
Only grant ROLE_UPGRADE to trusted accounts. This role allows complete replacement of registry logic.
// Separate upgrade control from other admin rolesregistry.initialize( admin, RegistryRolesLib.ROLE_REGISTRAR_ADMIN // Deliberately omit ROLE_UPGRADE);// Grant upgrade rights to separate secure accountregistry.grantRoles( ROOT_RESOURCE, RegistryRolesLib.ROLE_UPGRADE, upgradeController);