feat(draft): whitelist names before mainnet - #239
Conversation
CI Summary
4naly3er AnalysisMedium (5)
Low (10)
Gas (14)
Informational (11)
Slither AnalysisHigh (3)
Medium (42)
Low (60)
Informational (63)
Contract Tests (Unit + Fuzz)BasicDotnsIntegrationReverts (test/intergration/BasicDotns.reverts.t.sol)
BasicDotnsIntegration (test/intergration/BasicDotns.t.sol)
DeployCreate3FactoryTest (test/unit/deploy/DeployCreate3Factory.t.sol)
DeterministicDeploymentTest (test/unit/deploy/DeterministicDeployment.t.sol)
DotnsContentResolverTests (test/unit/resolver/DotnsContentResolver.t.sol)
DotnsNameEscrowTest (test/unit/escrow/DotnsNameEscrow.t.sol)
DotnsNameEscrowFuzzTest (test/fuzz/escrow/DotnsNameEscrowFuzz.t.sol)
DotnsNameEscrowRefundsTest (test/unit/escrow/DotnsNameEscrowRefunds.t.sol)
DotnsNameWhitelistTests (test/unit/whitelist/DotnsNameWhitelist.t.sol)
DotnsNameWhitelistFuzz (test/fuzz/whitelist/DotnsNameWhitelistFuzz.t.sol)
DotnsPopControllerTests (test/unit/registrar/DotnsPopController.t.sol)
DotnsPopControllerFuzz (test/fuzz/registrar/DotnsPopControllerFuzz.t.sol)
DotnsPopResolverTests (test/unit/resolver/DotnsPopResolver.t.sol)
DotnsProtocolRegistryTldTests (test/unit/registry/DotnsProtocolRegistry.t.sol)
DotnsProtocolRegistryFuzzTest (test/fuzz/registry/DotnsProtocolRegistryFuzz.t.sol)
DotnsRegistrarTests (test/unit/registrar/DotnsRegistrar.t.sol)
DotnsRegistrarControllerTest (test/unit/registrar/DotnsRegistrarController.t.sol)
DotnsRegistrarControllerFuzzTest (test/fuzz/registrar/DotnsRegistrarControllerFuzz.t.sol)
DotnsRegistrarControllerLifecycleTest (test/unit/registrar/DotnsRegistrarControllerLifecycle.t.sol)
DotnsRegistryTests (test/unit/registry/DotnsRegistry.t.sol)
DotnsRegistryFuzzTest (test/fuzz/registry/DotnsRegistryFuzz.t.sol)
DotnsResolverTests (test/unit/resolver/DotnsResolver.t.sol)
DotnsReverseResolverTests (test/unit/resolver/DotnsReverseResolver.t.sol)
LabelStoreTests (test/unit/store/LabelStore.t.sol)
LabelStoreFuzzTest (test/fuzz/store/LabelStoreFuzz.t.sol)
NoStatusDepositLifecycle (test/intergration/NoStatusDepositLifecycle.t.sol)
PopRulesFuzzTest (test/fuzz/pop/PopFuzz.t.sol)
PopLifecycleFlow (test/intergration/PopLifecycleFlow.t.sol)
PopRulesTests (test/unit/pop/PopRules.t.sol)
RootGatewayDispatcherTests (test/unit/registrar/RootGatewayDispatcher.t.sol)
StoreFactoryTests (test/unit/store/StoreFactory.t.sol)
StoreIntegrationTest (test/intergration/StoreIntegration.t.sol)
StoreStressTest (test/stress/store/StoreStress.t.sol)
UserStoreTests (test/unit/store/UserStore.t.sol)
UserStoreFuzzTest (test/fuzz/store/UserStoreFuzz.t.sol)
WhitelistOperatorFlow (test/intergration/WhitelistOperatorFlow.t.sol)
Contract Tests (Invariant)DotnsNameEscrowInvariantTest (test/invariant/escrow/DotnsNameEscrowInvariant.t.sol)
DotnsNameWhitelistInvariant (test/invariant/whitelist/DotnsNameWhitelistInvariant.t.sol)
DotnsPopControllerInvariant (test/invariant/registrar/DotnsPopControllerInvariant.t.sol)
DotnsRegistrarControllerInvariantTest (test/invariant/registrar/DotnsRegistrarControllerInvariant.t.sol)
DotnsRegistrarControllerRoleInvariantTest (test/invariant/registrar/DotnsRegistrarControllerRoleInvariant.t.sol)
DotnsRegistryInvariantTest (test/invariant/registry/DotnsRegistryInvariant.t.sol)
StoreInvariantTest (test/invariant/store/StoreInvariant.t.sol)
Gas ReportDotnsProtocolRegistry
DotnsRegistrar
DotnsRegistrarController
DotnsRegistry
DotnsReverseResolver
PopRules
Coverage
Deploy ContractsDeployed addresses vs DEPLOYMENTS.mdExpected is the committed manifest; actual is this CI deployment of the same pipeline.
Labelssmartcontracts, other, type: test |
re-gius
left a comment
There was a problem hiding this comment.
The contract itself is in a good state.
My comments are all about the authority model, and I think they reduce to one decision rather than a list of fixes. This is built for dev-operated pre-launch allocation, and it does that well. Mainnet needs governance-only allocation, and the contract is currently the opposite of that by construction: _checkRoleOrOwner passes for owner(), so the deployer is a first-class allocator on every path, and _authorizeUpgrade is owner-held, so any gate added later can be replaced in two transactions. A referendum, meanwhile, can't use those paths at all since it arrives as Root, which has no msg.sender.
My suggestion is adding a one-way lockToGovernance(): keep today's owner and operator paths for pre-launch, and have the lock permanently switch every allocation path to ISystem(REVIVE_SYSTEM).originIsRoot() and kill the owner and role branches.
You may also go with the current version, but we should keep in mind this is not ready for mainnet launch and should be upgraded for mainnet in a follow up (as established in #205).
| function _validateNew(string calldata label) internal view returns (bytes32 node) { | ||
| require(label.isSingleLabel(), InvalidLabel()); | ||
| node = _nodeOf(label); | ||
| require(_grants[node].status == GrantStatus.None, AlreadyExists(node)); |
There was a problem hiding this comment.
Any live entry blocks grantName, including a Requested one written by anybody, and requestName is permissionless and free beyond gas. So a malicious actor can force every desirable label into a state where allocation needs a paired revokeName first.
Suggested fix: let grantName overwrite any non-Accepted entry. That keeps Accepted protected so one grant can't silently overwrite another, preserves sticky rejection as a default against re-requests, and lets governance deliberately allocate over a blocked label in a single call.
| uint256[50] private __gap; | ||
|
|
||
| /// @notice Restricts a call to an operator or the owner. | ||
| modifier onlyOperatorOrOwner() { |
There was a problem hiding this comment.
_checkRoleOrOwner passes for caller == owner(), and initialize (line 84) sets the owner to msg.sender. So the deployer can allocate any name to any address with no referendum, which is not allowed on mainnet.
Notice that a referendum cannot use this path at all: it arrives as Root, and Root has no msg.sender. Since this contract sits behind a UUPS proxy, the check has to be ISystem(REVIVE_SYSTEM).originIsRoot(), the same reason the PoP controller needs it.
However, I'd suggest keeping these paths for devnet and adding an irreversible lockToGovernance() that permanently switches every allocation path to the Root gate and kills the owner/role branches. That preserves pre-launch ergonomics and makes the mainnet posture verifiable on-chain.
| } | ||
|
|
||
| /// @notice Restricts upgrades to the owner. | ||
| function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} |
There was a problem hiding this comment.
maybe we should reserve this for governance only? Again, if we allow an irreversible lockToGovernance(), this may only change afterwards
Description
To fill in laters :XD
Type
Scope
Related Issues
Fixes
Checklist
Code
forge buildpassesforge testpassesTesting
Security
selfdestructordelegatecallDocumentation
Breaking Changes
Breaking changes:
How to test
Notes