Overview
TheUnlockedMigrationController handles migration of unlocked .eth second-level domain (2LD) names from ENS v1 to the v2 registry system. This includes both unwrapped names (ERC721 tokens from the Registrar) and wrapped names without the CANNOT_UNWRAP fuse set.
Contract Location:
contracts/src/migration/UnlockedMigrationController.solImplements IERC1155Receiver and IERC721Receiver to accept transfers from both NameWrapper and Registrar.Supported Name Types
The controller handles two categories of unlocked names:Unwrapped Names
ERC721 tokens held in the v1 Base Registrar, never wrapped in NameWrapper.
Unlocked Wrapped Names
ERC1155 tokens in NameWrapper without
CANNOT_UNWRAP fuse, allowing unwrapping.Architecture
Interface Implementation
Key Components
IERC1155Receiver
IERC1155Receiver
Handles wrapped name transfers from NameWrapper:
onERC1155Received(): Single name transferonERC1155BatchReceived(): Batch name transfer- Validates sender is NameWrapper
- Unwraps names before migration
IERC721Receiver
IERC721Receiver
Handles unwrapped name transfers from Registrar:
onERC721Received(): Single name transfer- Validates sender is the Base Registrar
- Directly migrates without unwrapping
ETH Registry
ETH Registry
Target registry for v2 names:
- Direct registration without reserved status
- Accepts full configuration in migration data
- No subregistry deployment needed
Contract Interface
Constructor
nameWrapper: The v1 NameWrapper contractethRegistry: The v2 ETH Registry contract
Immutable State
Interface Support
Migration Flows
Unwrapped Name Migration (ERC721)
Wrapped Unlocked Name Migration (ERC1155)
Migration Data Structures
TransferData
Contains the complete registration information:dnsEncodedName
dnsEncodedName
Type:
bytesDNS wire format encoding of the name:- First byte: label length
- Next N bytes: label characters
- Continues for each label
- Terminates with 0x00
0x066d796e616d6503657468000x06: Length of “myname” (6)0x6d796e616d65: “myname” in hex0x03: Length of “eth” (3)0x657468: “eth” in hex0x00: Terminator
owner
owner
Type:
addressOwner of the name in v2 system.Constraints:- Cannot be zero address
- Receives roles specified in
roleBitmap
subregistry
subregistry
Type:
addressOptional subregistry contract.Usage:address(0): No subregistry, standard name- Custom address: Specific subregistry implementation
- Unlike locked migration, no automatic deployment
resolver
resolver
Type:
addressResolver contract for name resolution.Usage:- Can be any valid resolver
- Owner needs
ROLE_SET_RESOLVERto change later
roleBitmap
roleBitmap
Type:
uint256Bitmap of roles to grant the owner.Common Roles:ROLE_RENEW: Can extend expiryROLE_SET_RESOLVER: Can change resolverROLE_CAN_TRANSFER_ADMIN: Can transfer nameROLE_REGISTRAR: Can create subdomains (if has subregistry)
expires
expires
Type:
uint64Expiration timestamp (Unix time).Constraints:- Must be in the future
- Should match or extend v1 expiry
MigrationData
Wrapper for transfer data with optional salt:The
salt field is present for consistency with locked migration but is not used by UnlockedMigrationController.Batch Migration
Migrate multiple wrapped unlocked names in one transaction:Security Validations
Caller Authorization
Lock Status Verification
Locked names (with
CANNOT_UNWRAP) are rejected. They must use LockedMigrationController instead.Token ID Validation
- Migrating wrong name for a token
- Name/token mismatch attacks
- Data encoding errors
Error Reference
Selector:
0x315ec9f5Transfer not from NameWrapper or Registrar.Solutions:- Use
NameWrapper.safeTransferFrom()for wrapped names - Use
Registrar.safeTransferFrom()for unwrapped names
Selector:
0x4fa09b3fToken ID doesn’t match label hash from DNS-encoded name.Solutions:- Verify DNS encoding is correct
- Ensure label matches the token being transferred
- Check for encoding errors
Selector:
0x80da7148Attempted to migrate a locked name through unlocked controller.Solution: Use LockedMigrationController for locked namesComplete Example
Migrating an Unwrapped Name
Migrating a Wrapped Unlocked Name
Comparison with Locked Migration
| Feature | Unlocked Migration | Locked Migration |
|---|---|---|
| Name State | Unlocked or unwrapped | Locked with CANNOT_UNWRAP |
| Token Type | ERC721 or unlocked ERC1155 | Locked ERC1155 |
| Unwrapping | Automatic if wrapped | Not supported |
| Subregistry | Optional, user-specified | Automatic WrapperRegistry deployment |
| Roles | User-specified via roleBitmap | Translated from fuses |
| Reservation | Not required | Must be pre-reserved |
| Complexity | Simpler | More complex |
| Use Case | Standard names | Premium/locked names |
Best Practices
Verify Lock Status
Always check
CANNOT_UNWRAP before choosing controller.Preserve Expiry
Use the current expiry from v1 to maintain registration period.
Set Appropriate Roles
Grant roles based on intended name usage and management needs.
Validate DNS Encoding
Ensure DNS-encoded name is correctly formatted to avoid mismatches.
Test on Testnet
Test migration flow on testnet before migrating mainnet names.
Handle Both Types
Support both wrapped and unwrapped migrations in your integration.
Common Patterns
Helper: DNS Encoding
Helper: Standard Roles
Helper: Check Lock Status
Related Documentation
Migration Overview
Understand the complete migration system
Locked Migration
Learn about locked name migration
Registry Roles
Understand the role-based permission system
ETH Registrar
Learn about the v2 ETH Registrar