Skip to content

feat: add DOS testnet ENSv2 deployment - #2

Merged
JOY (JOY) merged 1 commit into
dosfrom
codex/ensv2-testnet-deploy
Aug 5, 2026
Merged

feat: add DOS testnet ENSv2 deployment#2
JOY (JOY) merged 1 commit into
dosfrom
codex/ensv2-testnet-deploy

Conversation

@JOY

Copy link
Copy Markdown

Summary

  • add a standard wrapped-native WDOS contract for DOS Chain Testnet
  • deploy the complete ENSv2 .dos stack with WDOS payment support
  • transfer all registry, resolver, pricing, registrar, contract-namer, and gateway administration from the temporary broadcaster to the external protocol owner

Verification

  • forge test: 903 passed, 0 failed
  • forge fmt --check
  • git diff --check
  • deployment dry-run against chain 3939: estimated 38,908,141 gas and 0.077816282038908141 DOS

Security

  • no private key or secret material is committed
  • the test asserts that the temporary deployer retains no registry, resolver, user-registry, or pricing roles
  • registrar revenue beneficiary and final owner are externally configured

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the deployment scripts and contracts for the DOS Name Service on testnet, including a standard wrapped-native token WrappedDOS and its corresponding unit tests. The review feedback highlights a critical handoff gap where ownership of the core TLD tokens is retained by the temporary deployer instead of being transferred to the final owner, and recommends adding a zero-address validation check for the final owner during the handoff process to prevent accidental loss of protocol control.

Comment on lines +57 to +83
function _handoff(Deployment memory deployment, address initialOwner, address owner) internal {
if (owner == initialOwner) {
return;
}

_handoffRoles(deployment.rootRegistry, initialOwner, owner, _rootRegistryRoles());
_handoffRoles(deployment.dosRegistry, initialOwner, owner, _dosRegistryRoles());
_handoffRoles(deployment.reverseRegistry, initialOwner, owner, _rootRegistryRoles());
_handoffRoles(deployment.priceOracle, initialOwner, owner, DEFAULT_ROLE_BITMAP);
_handoffRoles(
deployment.permissionedResolverImplementation,
initialOwner,
owner,
PermissionedResolverLib.ROLE_CAN_NAME
| PermissionedResolverLib.ROLE_CAN_NAME_ADMIN
);
_handoffRoles(
deployment.userRegistryImplementation,
initialOwner,
owner,
RegistryRolesLib.ROLE_CAN_NAME | RegistryRolesLib.ROLE_CAN_NAME_ADMIN
);

deployment.contractNamer.transferOwnership(owner);
deployment.gatewayProvider.transferOwnership(owner);
deployment.dosRegistrar.transferOwnership(owner);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Critical Handoff Gap: TLD Token Ownership Retained by Deployer

During the deployment phase, deploy is called with initialOwner (the temporary broadcaster) as the owner parameter. This registers the core TLDs ("dos" and "reverse" on rootRegistry, and reverseLabel on reverseRegistry) under the ownership of initialOwner, minting the corresponding ERC1155 tokens to them.

However, in _handoff, these ERC1155 tokens are never transferred to the final owner. Because these tokens are registered without RegistryRolesLib.ROLE_CAN_TRANSFER_ADMIN (and with 0 roles for reverseLabel), they are permanently non-transferable by default. This leaves the temporary deployer as the permanent owner of the core TLDs, retaining ultimate admin control and preventing the final owner from fully managing them.

Suggested Fix:

  1. Modify DeployDOS.s.sol to include RegistryRolesLib.ROLE_CAN_TRANSFER_ADMIN in _tldTokenRoles() and when registering reverseLabel so that they can be transferred.
  2. In _handoff, transfer the tokens to the final owner using safeTransferFrom:
uint256 dosTokenId = deployment.rootRegistry.getTokenId(uint256(keccak256("dos")));
uint256 reverseTokenId = deployment.rootRegistry.getTokenId(uint256(keccak256("reverse")));
deployment.rootRegistry.safeTransferFrom(initialOwner, owner, dosTokenId, 1, "");
deployment.rootRegistry.safeTransferFrom(initialOwner, owner, reverseTokenId, 1, "");

uint256 reverseLabelTokenId = deployment.reverseRegistry.getTokenId(uint256(keccak256(bytes(deployment.reverseRegistrar.reverseLabel()))));
deployment.reverseRegistry.safeTransferFrom(initialOwner, owner, reverseLabelTokenId, 1, "");

Comment on lines +57 to +60
function _handoff(Deployment memory deployment, address initialOwner, address owner) internal {
if (owner == initialOwner) {
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent accidental loss of ownership or administrative control over the entire protocol, it is highly recommended to validate that the final owner address is not address(0) before proceeding with the handoff.

    function _handoff(Deployment memory deployment, address initialOwner, address owner) internal {
        require(owner != address(0), "DeployDOSTestnet: owner cannot be zero address");
        if (owner == initialOwner) {
            return;
        }

@JOY
JOY (JOY) force-pushed the codex/ensv2-testnet-deploy branch from c9a4da1 to e78a0a7 Compare August 5, 2026 05:11
@JOY
JOY (JOY) merged commit 627ae52 into dos Aug 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant