diff --git a/packages/contracts/deploy/helpers.ts b/packages/contracts/deploy/helpers.ts index 912853157..e5df0ca39 100644 --- a/packages/contracts/deploy/helpers.ts +++ b/packages/contracts/deploy/helpers.ts @@ -7,12 +7,14 @@ import { } from '../typechain'; import {VersionCreatedEvent} from '../typechain/PluginRepo'; import {PluginRepoRegisteredEvent} from '../typechain/PluginRepoRegistry'; +import {ensLabelHash} from '../utils/ens'; import {isLocal, pluginDomainEnv} from '../utils/environment'; import { getNetworkNameByAlias, getLatestNetworkDeployment, } from '@aragon/osx-commons-configs'; import {findEvent, findEventTopicLog, Operation} from '@aragon/osx-commons-sdk'; +import {ENSSubdomainRegistrar__factory} from '@aragon/osx-ethers-v1.2.0'; import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {Contract} from 'ethers'; import {ethers} from 'hardhat'; @@ -158,6 +160,25 @@ export async function detemineDeployerNextAddress( return futureAddress; } +export async function registerPluginRepoSubdomain( + hre: HardhatRuntimeEnvironment, + repoAddress: string, + subdomain: string, + ensRegistrar: any +): Promise { + const [deployer] = await ethers.getSigners(); + + const ensRegistrarContract = ENSSubdomainRegistrar__factory.connect( + ensRegistrar, + deployer + ); + + await ensRegistrarContract.registerSubnode( + ensLabelHash(subdomain), + repoAddress + ); +} + export async function createPluginRepo( hre: HardhatRuntimeEnvironment, pluginName: string, @@ -191,10 +212,7 @@ export async function createPluginRepo( const {deployer} = await hre.getNamedAccounts(); - const tx = await pluginRepoFactoryContract.createPluginRepo( - subdomain, - deployer - ); + const tx = await pluginRepoFactoryContract.createPluginRepo(deployer); console.log( `Creating & registering repo for ${pluginName} with tx ${tx.hash}` ); @@ -209,6 +227,14 @@ export async function createPluginRepo( hre.aragonPluginRepos[pluginName] = repoAddress; + // register subdomain + await registerPluginRepoSubdomain( + hre, + repoAddress, + subdomain, + await getContractAddress('PluginENSSubdomainRegistrarProxy', hre) + ); + console.log( `Created & registered repo for ${pluginName} at address: ${repoAddress}` //, with contentURI ${ethers.utils.toUtf8String(releaseMetadata)}` ); diff --git a/packages/contracts/deploy/new/10_framework/10_dao-registry.ts b/packages/contracts/deploy/new/10_framework/00_dao-registry.ts similarity index 84% rename from packages/contracts/deploy/new/10_framework/10_dao-registry.ts rename to packages/contracts/deploy/new/10_framework/00_dao-registry.ts index 01660a7d5..b1c99b560 100644 --- a/packages/contracts/deploy/new/10_framework/10_dao-registry.ts +++ b/packages/contracts/deploy/new/10_framework/00_dao-registry.ts @@ -15,10 +15,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { ); // Get DAO's `ENSSubdomainRegistrar` contract. - const ensSubdomainRegistrarAddress = await getContractAddress( - 'DAOENSSubdomainRegistrarProxy', - hre - ); + //! no longer neede + // const ensSubdomainRegistrarAddress = await getContractAddress( + // 'DAOENSSubdomainRegistrarProxy', + // hre + // ); await deploy('DAORegistryProxy', { contract: daoRegistryArtifact, @@ -32,7 +33,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { execute: { init: { methodName: 'initialize', - args: [managementDAOAddress, ensSubdomainRegistrarAddress], + args: [managementDAOAddress], }, }, }, diff --git a/packages/contracts/deploy/new/10_framework/11_dao-registry_conclude.ts b/packages/contracts/deploy/new/10_framework/01_dao-registry_conclude.ts similarity index 100% rename from packages/contracts/deploy/new/10_framework/11_dao-registry_conclude.ts rename to packages/contracts/deploy/new/10_framework/01_dao-registry_conclude.ts diff --git a/packages/contracts/deploy/new/10_framework/20_plugin-repo-registry.ts b/packages/contracts/deploy/new/10_framework/10_plugin-repo-registry.ts similarity index 85% rename from packages/contracts/deploy/new/10_framework/20_plugin-repo-registry.ts rename to packages/contracts/deploy/new/10_framework/10_plugin-repo-registry.ts index 32f6b96ff..92152c5b1 100644 --- a/packages/contracts/deploy/new/10_framework/20_plugin-repo-registry.ts +++ b/packages/contracts/deploy/new/10_framework/10_plugin-repo-registry.ts @@ -15,10 +15,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { ); // Get DAO's `ENSSubdomainRegistrar` address. - const ensSubdomainRegistrarAddress = await getContractAddress( - 'PluginENSSubdomainRegistrarProxy', - hre - ); + // ! no longer needed + // const ensSubdomainRegistrarAddress = await getContractAddress( + // 'PluginENSSubdomainRegistrarProxy', + // hre + // ); await deploy('PluginRepoRegistryProxy', { contract: pluginRepoRegistryArtifact, @@ -32,7 +33,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { execute: { init: { methodName: 'initialize', - args: [managementDAOAddress, ensSubdomainRegistrarAddress], + args: [managementDAOAddress], }, }, }, diff --git a/packages/contracts/deploy/new/10_framework/21_plugin-repo-registry_conclude.ts b/packages/contracts/deploy/new/10_framework/11_plugin-repo-registry_conclude.ts similarity index 100% rename from packages/contracts/deploy/new/10_framework/21_plugin-repo-registry_conclude.ts rename to packages/contracts/deploy/new/10_framework/11_plugin-repo-registry_conclude.ts diff --git a/packages/contracts/deploy/new/10_framework/00_ens_registry.ts b/packages/contracts/deploy/new/10_framework/20_ens_registry.ts similarity index 100% rename from packages/contracts/deploy/new/10_framework/00_ens_registry.ts rename to packages/contracts/deploy/new/10_framework/20_ens_registry.ts diff --git a/packages/contracts/deploy/new/10_framework/01_ens_subdomains.ts b/packages/contracts/deploy/new/10_framework/21_ens_subdomains.ts similarity index 100% rename from packages/contracts/deploy/new/10_framework/01_ens_subdomains.ts rename to packages/contracts/deploy/new/10_framework/21_ens_subdomains.ts diff --git a/packages/contracts/deploy/new/10_framework/02_ens_subdomain_registrars.ts b/packages/contracts/deploy/new/10_framework/22_ens_subdomain_registrars.ts similarity index 86% rename from packages/contracts/deploy/new/10_framework/02_ens_subdomain_registrars.ts rename to packages/contracts/deploy/new/10_framework/22_ens_subdomain_registrars.ts index 003b5018d..b1f4edf42 100644 --- a/packages/contracts/deploy/new/10_framework/02_ens_subdomain_registrars.ts +++ b/packages/contracts/deploy/new/10_framework/22_ens_subdomain_registrars.ts @@ -26,6 +26,9 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const daoNode = ethers.utils.namehash(daoDomain); const pluginNode = ethers.utils.namehash(pluginDomain); + // Get DAO's `DAORegistry` address. + const daoRegistry = await getContractAddress('DAORegistryProxy', hre); + await deploy('DAOENSSubdomainRegistrarProxy', { contract: ensSubdomainRegistrarArtifact, from: deployer.address, @@ -38,7 +41,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { execute: { init: { methodName: 'initialize', - args: [managementDAOAddress, ensRegistryAddress, daoNode], + args: [ + managementDAOAddress, + ensRegistryAddress, + daoRegistry, + daoNode, + ], }, }, }, @@ -50,6 +58,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { hre ); + // Get DAO's `PluginRepoRegistry` address. + const pluginRepoRegistry = await getContractAddress( + 'PluginRepoRegistryProxy', + hre + ); + await deploy('PluginENSSubdomainRegistrarProxy', { contract: ensSubdomainRegistrarArtifact, from: deployer.address, @@ -62,7 +76,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { execute: { init: { methodName: 'initialize', - args: [managementDAOAddress, ensRegistryAddress, pluginNode], + args: [ + managementDAOAddress, + ensRegistryAddress, + pluginRepoRegistry, + pluginNode, + ], }, }, }, diff --git a/packages/contracts/deploy/new/10_framework/09_ens_conclude.ts b/packages/contracts/deploy/new/10_framework/29_ens_conclude.ts similarity index 100% rename from packages/contracts/deploy/new/10_framework/09_ens_conclude.ts rename to packages/contracts/deploy/new/10_framework/29_ens_conclude.ts diff --git a/packages/contracts/deploy/new/10_framework/99_verifiy_step.ts b/packages/contracts/deploy/new/10_framework/99_verifiy_step.ts index 30a961aaf..57b465966 100644 --- a/packages/contracts/deploy/new/10_framework/99_verifiy_step.ts +++ b/packages/contracts/deploy/new/10_framework/99_verifiy_step.ts @@ -24,6 +24,25 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { hre ); + // VERIFYING DAO REGISTRY + const DAORegistryAddress = await getContractAddress('DAORegistryProxy', hre); + const DAORegistry = DAORegistry__factory.connect( + DAORegistryAddress, + deployer + ); + + await checkSetManagementDao(DAORegistry, managementDAOAddress); + // ! not nedded as the registry no longer has the subdomain registrar + // // scope to reuse same const again + // { + // const SubdomainRegistrarAddress = await DAORegistry.subdomainRegistrar(); + // if (SubdomainRegistrarAddress !== DAOENSSubdomainRegistrarAddress) { + // throw new Error( + // `${DAORegistry} has wrong SubdomainRegistrarAddress set. Expected ${DAOENSSubdomainRegistrarAddress} to be ${SubdomainRegistrarAddress}` + // ); + // } + // } + // VERIFYING DAO ENS SUBDOMAIN REGISTRAR const DAOENSSubdomainRegistrarAddress = await getContractAddress( 'DAOENSSubdomainRegistrarProxy', @@ -33,6 +52,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { DAOENSSubdomainRegistrarAddress, deployer ); + await checkSetManagementDao(DAOENSSubdomainRegistrar, managementDAOAddress); // scope to reuse same const again { @@ -57,6 +77,42 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { } } + // check is the correct registry + { + const SubdomainRegistry = await DAOENSSubdomainRegistrar.registry(); + console.log('SubdomainRegistry', SubdomainRegistry); + console.log('DAORegistryAddress', DAORegistryAddress); + + if (SubdomainRegistry !== DAORegistryAddress) { + throw new Error( + `${DAOENSSubdomainRegistrar} has wrong Registry set. Expected ${DAORegistryAddress} to be ${SubdomainRegistry}` + ); + } + } + + // VERIFYING PLUGIN REPO REGISTRY + const PluginRepoRegistryAddress = await getContractAddress( + 'PluginRepoRegistryProxy', + hre + ); + const PluginRepoRegistry = PluginRepoRegistry__factory.connect( + PluginRepoRegistryAddress, + deployer + ); + await checkSetManagementDao(PluginRepoRegistry, managementDAOAddress); + + // ! not needed as the registry no longer has the subdomain registrar + // scope to reuse same const again + // { + // const SubdomainRegistrarAddress = + // await PluginRepoRegistry.subdomainRegistrar(); + // if (SubdomainRegistrarAddress !== PluginENSSubdomainRegistrarAddress) { + // throw new Error( + // `${PluginRepoRegistry} has wrong SubdomainRegistrarAddress set. Expected ${PluginENSSubdomainRegistrarAddress} to be ${SubdomainRegistrarAddress}` + // ); + // } + // } + // VERIFYING PLUGIN ENS SUBDOMAIN REGISTRAR const PluginENSSubdomainRegistrarAddress = await getContractAddress( 'PluginENSSubdomainRegistrarProxy', @@ -93,40 +149,14 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { } } - // VERIFYING DAO REGISTRY - const DAORegistryAddress = await getContractAddress('DAORegistryProxy', hre); - const DAORegistry = DAORegistry__factory.connect( - DAORegistryAddress, - deployer - ); - await checkSetManagementDao(DAORegistry, managementDAOAddress); - // scope to reuse same const again - { - const SubdomainRegistrarAddress = await DAORegistry.subdomainRegistrar(); - if (SubdomainRegistrarAddress !== DAOENSSubdomainRegistrarAddress) { - throw new Error( - `${DAORegistry} has wrong SubdomainRegistrarAddress set. Expected ${DAOENSSubdomainRegistrarAddress} to be ${SubdomainRegistrarAddress}` - ); - } - } - - // VERIFYING PLUGIN REPO REGISTRY - const PluginRepoRegistryAddress = await getContractAddress( - 'PluginRepoRegistryProxy', - hre - ); - const PluginRepoRegistry = PluginRepoRegistry__factory.connect( - PluginRepoRegistryAddress, - deployer - ); - await checkSetManagementDao(PluginRepoRegistry, managementDAOAddress); - // scope to reuse same const again + // check is the correct registry { - const SubdomainRegistrarAddress = - await PluginRepoRegistry.subdomainRegistrar(); - if (SubdomainRegistrarAddress !== PluginENSSubdomainRegistrarAddress) { + const SubdomainRegistry = await PluginENSSubdomainRegistrar.registry(); + console.log('SubdomainRegistry', SubdomainRegistry); + console.log('PluginRepoRegistryAddress', PluginRepoRegistryAddress); + if (SubdomainRegistry !== PluginRepoRegistryAddress) { throw new Error( - `${PluginRepoRegistry} has wrong SubdomainRegistrarAddress set. Expected ${PluginENSSubdomainRegistrarAddress} to be ${SubdomainRegistrarAddress}` + `${PluginENSSubdomainRegistrar} has wrong Registry set. Expected ${PluginRepoRegistryAddress} to be ${SubdomainRegistry}` ); } } diff --git a/packages/contracts/deploy/new/40_finalize-management-dao/20_register-management-dao-on-dao-registry.ts b/packages/contracts/deploy/new/40_finalize-management-dao/20_register-management-dao-on-dao-registry.ts index 38d56eed5..5c7a25835 100644 --- a/packages/contracts/deploy/new/40_finalize-management-dao/20_register-management-dao-on-dao-registry.ts +++ b/packages/contracts/deploy/new/40_finalize-management-dao/20_register-management-dao-on-dao-registry.ts @@ -55,8 +55,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { // Register `managementDAO` on `DAORegistry`. const registerTx = await daoRegistryContract.register( managementDAOAddress, - deployer.address, - daoSubdomain + deployer.address ); await registerTx.wait(); console.log( diff --git a/packages/contracts/src/framework/dao/DAOFactory.sol b/packages/contracts/src/framework/dao/DAOFactory.sol index 7a0d2d743..11b731d96 100644 --- a/packages/contracts/src/framework/dao/DAOFactory.sol +++ b/packages/contracts/src/framework/dao/DAOFactory.sol @@ -39,7 +39,6 @@ contract DAOFactory is ERC165, ProtocolVersion { struct DAOSettings { address trustedForwarder; string daoURI; - string subdomain; bytes metadata; } @@ -78,7 +77,8 @@ contract DAOFactory is ERC165, ProtocolVersion { /// @param _pluginSettings The array containing references to plugins and their settings to be installed after the DAO has been created. function createDao( DAOSettings calldata _daoSettings, - PluginSettings[] calldata _pluginSettings + PluginSettings[] calldata _pluginSettings, + IDAO.Action[] calldata _actions ) external returns (DAO createdDao) { // Check if no plugin is provided. if (_pluginSettings.length == 0) { @@ -89,7 +89,7 @@ contract DAOFactory is ERC165, ProtocolVersion { createdDao = _createDAO(_daoSettings); // Register DAO. - daoRegistry.register(createdDao, msg.sender, _daoSettings.subdomain); + daoRegistry.register(createdDao, msg.sender); // Get Permission IDs bytes32 rootPermissionID = createdDao.ROOT_PERMISSION_ID(); @@ -133,6 +133,18 @@ contract DAOFactory is ERC165, ProtocolVersion { ); } + if (_actions.length > 0) { + // grant temporary execute action permission to this DAOFactory + bytes32 executeActionPermissionID = createdDao.EXECUTE_PERMISSION_ID(); + createdDao.grant(address(createdDao), address(this), executeActionPermissionID); + + // Execute actions on the newly created DAO. + createdDao.execute(bytes32("callID"), _actions, 0); + + // revoke the execute action permission + createdDao.revoke(address(createdDao), address(this), executeActionPermissionID); + } + // Set the rest of DAO's permissions. _setDAOPermissions(createdDao); diff --git a/packages/contracts/src/framework/dao/DAORegistry.sol b/packages/contracts/src/framework/dao/DAORegistry.sol index 507fed64d..61b20a196 100644 --- a/packages/contracts/src/framework/dao/DAORegistry.sol +++ b/packages/contracts/src/framework/dao/DAORegistry.sol @@ -9,7 +9,7 @@ import {ENSSubdomainRegistrar} from "../utils/ens/ENSSubdomainRegistrar.sol"; import {InterfaceBasedRegistry} from "../utils/InterfaceBasedRegistry.sol"; import {isSubdomainValid} from "../utils/RegistryUtils.sol"; -/// @title Register your unique DAO subdomain +/// @title Register your unique DAO /// @author Aragon Association - 2022-2023 /// @notice This contract provides the possibility to register a DAO. /// @custom:security-contact sirt@aragon.org @@ -18,16 +18,13 @@ contract DAORegistry is InterfaceBasedRegistry, ProtocolVersion { bytes32 public constant REGISTER_DAO_PERMISSION_ID = keccak256("REGISTER_DAO_PERMISSION"); /// @notice The ENS subdomain registrar registering the DAO subdomains. + /// ! removed, but keeping it for storage layout compatibility ENSSubdomainRegistrar public subdomainRegistrar; - /// @notice Thrown if the DAO subdomain doesn't match the regex `[0-9a-z\-]` - error InvalidDaoSubdomain(string subdomain); - /// @notice Emitted when a new DAO is registered. /// @param dao The address of the DAO contract. /// @param creator The address of the creator. - /// @param subdomain The DAO subdomain. - event DAORegistered(address indexed dao, address indexed creator, string subdomain); + event DAORegistered(address indexed dao, address indexed creator); /// @dev Used to disallow initializing the implementation contract by an attacker for extra safety. /// @custom:oz-upgrades-unsafe-allow constructor @@ -37,40 +34,20 @@ contract DAORegistry is InterfaceBasedRegistry, ProtocolVersion { /// @notice Initializes the contract. /// @param _managingDao the managing DAO address. - /// @param _subdomainRegistrar The `ENSSubdomainRegistrar` where `ENS` subdomain will be registered. - function initialize( - IDAO _managingDao, - ENSSubdomainRegistrar _subdomainRegistrar - ) external initializer { + function initialize(IDAO _managingDao) external initializer { __InterfaceBasedRegistry_init(_managingDao, type(IDAO).interfaceId); - subdomainRegistrar = _subdomainRegistrar; } /// @notice Registers a DAO by its address. If a non-empty subdomain name is provided that is not taken already, the DAO becomes the owner of the ENS name. /// @dev A subdomain is unique within the Aragon DAO framework and can get stored here. /// @param dao The address of the DAO contract. /// @param creator The address of the creator. - /// @param subdomain The DAO subdomain. - function register( - IDAO dao, - address creator, - string calldata subdomain - ) external auth(REGISTER_DAO_PERMISSION_ID) { + function register(IDAO dao, address creator) external auth(REGISTER_DAO_PERMISSION_ID) { address daoAddr = address(dao); _register(daoAddr); - if ((bytes(subdomain).length > 0)) { - if (!isSubdomainValid(subdomain)) { - revert InvalidDaoSubdomain({subdomain: subdomain}); - } - - bytes32 labelhash = keccak256(bytes(subdomain)); - - subdomainRegistrar.registerSubnode(labelhash, daoAddr); - } - - emit DAORegistered(daoAddr, creator, subdomain); + emit DAORegistered(daoAddr, creator); } /// @notice This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain (see [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)). diff --git a/packages/contracts/src/framework/plugin/repo/PluginRepoFactory.sol b/packages/contracts/src/framework/plugin/repo/PluginRepoFactory.sol index 1c155eaaf..8b83351ef 100644 --- a/packages/contracts/src/framework/plugin/repo/PluginRepoFactory.sol +++ b/packages/contracts/src/framework/plugin/repo/PluginRepoFactory.sol @@ -40,31 +40,25 @@ contract PluginRepoFactory is ERC165, ProtocolVersion { } /// @notice Creates a plugin repository proxy pointing to the `pluginRepoBase` implementation and registers it in the Aragon plugin registry. - /// @param _subdomain The plugin repository subdomain. /// @param _initialOwner The plugin maintainer address. - function createPluginRepo( - string calldata _subdomain, - address _initialOwner - ) external returns (PluginRepo) { - return _createPluginRepo(_subdomain, _initialOwner); + function createPluginRepo(address _initialOwner) external returns (PluginRepo) { + return _createPluginRepo(_initialOwner); } /// @notice Creates and registers a `PluginRepo` with an ENS subdomain and publishes an initial version `1.1`. - /// @param _subdomain The plugin repository subdomain. /// @param _pluginSetup The plugin factory contract associated with the plugin version. /// @param _maintainer The maintainer of the plugin repo. This address has permission to update metadata, upgrade the repo logic, and manage the repo permissions. /// @param _releaseMetadata The release metadata URI. /// @param _buildMetadata The build metadata URI. /// @dev After the creation of the `PluginRepo` and release of the first version by the factory, ownership is transferred to the `_maintainer` address. function createPluginRepoWithFirstVersion( - string calldata _subdomain, address _pluginSetup, address _maintainer, bytes memory _releaseMetadata, bytes memory _buildMetadata ) external returns (PluginRepo pluginRepo) { // Sets `address(this)` as initial owner which is later replaced with the maintainer address. - pluginRepo = _createPluginRepo(_subdomain, address(this)); + pluginRepo = _createPluginRepo(address(this)); pluginRepo.createVersion(1, _pluginSetup, _buildMetadata, _releaseMetadata); @@ -124,12 +118,8 @@ contract PluginRepoFactory is ERC165, ProtocolVersion { /// @notice Internal method creating a `PluginRepo` via the [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) proxy pattern from the provided base contract and registering it in the Aragon plugin registry. /// @dev Passing an empty `_subdomain` will cause the transaction to revert. - /// @param _subdomain The plugin repository subdomain. /// @param _initialOwner The initial owner address. - function _createPluginRepo( - string calldata _subdomain, - address _initialOwner - ) internal returns (PluginRepo pluginRepo) { + function _createPluginRepo(address _initialOwner) internal returns (PluginRepo pluginRepo) { pluginRepo = PluginRepo( createERC1967Proxy( pluginRepoBase, @@ -137,6 +127,6 @@ contract PluginRepoFactory is ERC165, ProtocolVersion { ) ); - pluginRepoRegistry.registerPluginRepo(_subdomain, address(pluginRepo)); + pluginRepoRegistry.registerPluginRepo(address(pluginRepo)); } } diff --git a/packages/contracts/src/framework/plugin/repo/PluginRepoRegistry.sol b/packages/contracts/src/framework/plugin/repo/PluginRepoRegistry.sol index f80955a62..b62d9b41e 100644 --- a/packages/contracts/src/framework/plugin/repo/PluginRepoRegistry.sol +++ b/packages/contracts/src/framework/plugin/repo/PluginRepoRegistry.sol @@ -19,18 +19,12 @@ contract PluginRepoRegistry is InterfaceBasedRegistry, ProtocolVersion { keccak256("REGISTER_PLUGIN_REPO_PERMISSION"); /// @notice The ENS subdomain registrar registering the PluginRepo subdomains. + /// ! removed, but keeping it for storage layout compatibility ENSSubdomainRegistrar public subdomainRegistrar; /// @notice Emitted if a new plugin repository is registered. - /// @param subdomain The subdomain of the plugin repository. /// @param pluginRepo The address of the plugin repository. - event PluginRepoRegistered(string subdomain, address pluginRepo); - - /// @notice Thrown if the plugin subdomain doesn't match the regex `[0-9a-z\-]` - error InvalidPluginSubdomain(string subdomain); - - /// @notice Thrown if the plugin repository subdomain is empty. - error EmptyPluginRepoSubdomain(); + event PluginRepoRegistered(address pluginRepo); /// @dev Used to disallow initializing the implementation contract by an attacker for extra safety. /// @custom:oz-upgrades-unsafe-allow constructor @@ -40,35 +34,19 @@ contract PluginRepoRegistry is InterfaceBasedRegistry, ProtocolVersion { /// @notice Initializes the contract by setting calling the `InterfaceBasedRegistry` base class initialize method. /// @param _dao The address of the managing DAO. - /// @param _subdomainRegistrar The `ENSSubdomainRegistrar` where `ENS` subdomain will be registered. - function initialize(IDAO _dao, ENSSubdomainRegistrar _subdomainRegistrar) external initializer { + function initialize(IDAO _dao) external initializer { bytes4 pluginRepoInterfaceId = type(IPluginRepo).interfaceId; __InterfaceBasedRegistry_init(_dao, pluginRepoInterfaceId); - - subdomainRegistrar = _subdomainRegistrar; } /// @notice Registers a plugin repository with a subdomain and address. - /// @param subdomain The subdomain of the PluginRepo. /// @param pluginRepo The address of the PluginRepo contract. function registerPluginRepo( - string calldata subdomain, address pluginRepo ) external auth(REGISTER_PLUGIN_REPO_PERMISSION_ID) { - if (!(bytes(subdomain).length > 0)) { - revert EmptyPluginRepoSubdomain(); - } - - if (!isSubdomainValid(subdomain)) { - revert InvalidPluginSubdomain({subdomain: subdomain}); - } - - bytes32 labelhash = keccak256(bytes(subdomain)); - subdomainRegistrar.registerSubnode(labelhash, pluginRepo); - _register(pluginRepo); - emit PluginRepoRegistered(subdomain, pluginRepo); + emit PluginRepoRegistered(pluginRepo); } /// @notice This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain (see [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)). diff --git a/packages/contracts/src/framework/utils/ens/ENSSubdomainRegistrar.sol b/packages/contracts/src/framework/utils/ens/ENSSubdomainRegistrar.sol index 2d2f8f926..d4b07e184 100644 --- a/packages/contracts/src/framework/utils/ens/ENSSubdomainRegistrar.sol +++ b/packages/contracts/src/framework/utils/ens/ENSSubdomainRegistrar.sol @@ -11,6 +11,9 @@ import {ProtocolVersion} from "@aragon/osx-commons-contracts/src/utils/versionin import {DaoAuthorizableUpgradeable} from "@aragon/osx-commons-contracts/src/permission/auth/DaoAuthorizableUpgradeable.sol"; import {IDAO} from "@aragon/osx-commons-contracts/src/dao/IDAO.sol"; +import {InterfaceBasedRegistry} from "../../utils/InterfaceBasedRegistry.sol"; +import {PluginRepo} from "../../plugin/repo/PluginRepo.sol"; + /// @title ENSSubdomainRegistrar /// @author Aragon Association - 2022-2023 /// @notice This contract registers ENS subdomains under a parent domain specified in the initialization process and maintains ownership of the subdomain since only the resolver address is set. This contract must either be the domain node owner or an approved operator of the node owner. The default resolver being used is the one specified in the parent domain. @@ -33,15 +36,19 @@ contract ENSSubdomainRegistrar is UUPSUpgradeable, DaoAuthorizableUpgradeable, P /// @notice The address of the ENS resolver resolving the names to an address. address public resolver; + InterfaceBasedRegistry public registry; + /// @notice Thrown if the subnode is already registered. /// @param subnode The subnode namehash. /// @param nodeOwner The node owner address. error AlreadyRegistered(bytes32 subnode, address nodeOwner); + error NotRegistered(bytes32 subnode, address nodeOwner); /// @notice Thrown if node's resolver is invalid. /// @param node The node namehash. /// @param resolver The node resolver address. error InvalidResolver(bytes32 node, address resolver); + error Unauthorized(); /// @dev Used to disallow initializing the implementation contract by an attacker for extra safety. /// @custom:oz-upgrades-unsafe-allow constructor @@ -57,11 +64,17 @@ contract ENSSubdomainRegistrar is UUPSUpgradeable, DaoAuthorizableUpgradeable, P /// @param _managingDao The interface of the DAO managing the components permissions. /// @param _ens The interface of the ENS registry to be used. /// @param _node The ENS parent domain node under which the subdomains are to be registered. - function initialize(IDAO _managingDao, ENS _ens, bytes32 _node) external initializer { + function initialize( + IDAO _managingDao, + ENS _ens, + InterfaceBasedRegistry _registry, + bytes32 _node + ) external initializer { __DaoAuthorizableUpgradeable_init(_managingDao); ens = _ens; node = _node; + registry = _registry; address nodeResolver = ens.resolver(_node); @@ -78,6 +91,34 @@ contract ENSSubdomainRegistrar is UUPSUpgradeable, DaoAuthorizableUpgradeable, P address ) internal virtual override auth(UPGRADE_REGISTRAR_PERMISSION_ID) {} + modifier isAllowed( + bool isRegistered, + bool isPlugin, + address _targetAddress + ) { + if (!isRegistered) revert Unauthorized(); + + if (isPlugin) { + if ( + !PluginRepo(_targetAddress).isGranted( + _targetAddress, + _msgSender(), + PluginRepo(_targetAddress).MAINTAINER_PERMISSION_ID(), + bytes("") + ) + ) revert Unauthorized(); + } + + _; + } + + function registerSubnode( + bytes32 _label + ) external isAllowed(registry.entries(_msgSender()), false, address(0)) { + // is a registered dao + _registerSubnode(_label, _msgSender()); + } + /// @notice Registers a new subdomain with this registrar as the owner and set the target address in the resolver. /// @dev It reverts with no message if this contract isn't the owner nor an approved operator for the given node. /// @param _label The labelhash of the subdomain name. @@ -85,7 +126,12 @@ contract ENSSubdomainRegistrar is UUPSUpgradeable, DaoAuthorizableUpgradeable, P function registerSubnode( bytes32 _label, address _targetAddress - ) external auth(REGISTER_ENS_SUBDOMAIN_PERMISSION_ID) { + ) external isAllowed(registry.entries(_targetAddress), true, _targetAddress) { + // is registered plugin and the caller has maintainer permission + _registerSubnode(_label, _targetAddress); + } + + function _registerSubnode(bytes32 _label, address _targetAddress) internal { bytes32 subnode = keccak256(abi.encodePacked(node, _label)); address currentOwner = ens.owner(subnode); @@ -96,6 +142,39 @@ contract ENSSubdomainRegistrar is UUPSUpgradeable, DaoAuthorizableUpgradeable, P ens.setSubnodeOwner(node, _label, address(this)); ens.setResolver(subnode, resolver); Resolver(resolver).setAddr(subnode, _targetAddress); + + // TODO add the reverse registrar record as highlighted by Cristiano + } + + function unregisterSubnode( + bytes32 _label + ) external isAllowed(registry.entries(_msgSender()), false, address(0)) { + // is a registered dao + _unregisterSubnode(_label); + } + + function unregisterSubnode( + bytes32 _label, + address _targetAddress + ) external isAllowed(registry.entries(_targetAddress), true, _targetAddress) { + // is registered plugin and the caller has maintainer permission + _unregisterSubnode(_label); + } + + function _unregisterSubnode(bytes32 _label) internal { + // ! mock implementation, need to review the correct way to unregister a subdomain + bytes32 subnode = keccak256(abi.encodePacked(node, _label)); + address currentOwner = ens.owner(subnode); + + if (currentOwner != address(this)) { + revert NotRegistered(subnode, currentOwner); + } + + ens.setSubnodeOwner(node, _label, address(0)); + ens.setResolver(subnode, address(0)); + Resolver(resolver).setAddr(subnode, address(0)); + + // TODO unregister the reverse registrar } /// @notice Sets the default resolver contract address that the subdomains being registered will use. diff --git a/packages/contracts/test/deploy/managing-dao.ts b/packages/contracts/test/deploy/managing-dao.ts index a82fdcbc5..a6f4949fc 100644 --- a/packages/contracts/test/deploy/managing-dao.ts +++ b/packages/contracts/test/deploy/managing-dao.ts @@ -34,7 +34,7 @@ async function deployAll() { await initializeDeploymentFixture('New'); } -describe('Management DAO', function () { +describe.only('Management DAO', function () { let deployer: SignerWithAddress; let approvers: SignerWithAddress[]; let minApprovals: number; diff --git a/packages/contracts/test/framework/dao/dao-factory.ts b/packages/contracts/test/framework/dao/dao-factory.ts index 0c65dd70c..a23c1f797 100644 --- a/packages/contracts/test/framework/dao/dao-factory.ts +++ b/packages/contracts/test/framework/dao/dao-factory.ts @@ -23,10 +23,13 @@ import { IProtocolVersion__factory, IERC165__factory, PluginRepoRegistry__factory, + ENSRegistry__factory, + PublicResolver__factory, } from '../../../typechain'; import {DAORegisteredEvent} from '../../../typechain/DAORegistry'; import {PluginRepoRegisteredEvent} from '../../../typechain/PluginRepoRegistry'; import {InstallationPreparedEvent} from '../../../typechain/PluginSetupProcessor'; +import {ensDomainHash, ensLabelHash} from '../../../utils/ens'; import {daoExampleURI, deployNewDAO} from '../../test-utils/dao'; import {deployENSSubdomainRegistrar} from '../../test-utils/ens'; import {deployPluginSetupProcessor} from '../../test-utils/plugin-setup-processor'; @@ -57,6 +60,7 @@ import { PLUGIN_SETUP_PROCESSOR_PERMISSIONS, getInterfaceId, } from '@aragon/osx-commons-sdk'; +import {ENSSubdomainRegistrar} from '@aragon/osx-ethers-v1.2.0'; import {anyValue} from '@nomicfoundation/hardhat-chai-matchers/withArgs'; import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {expect} from 'chai'; @@ -86,7 +90,6 @@ const AddressZero = ethers.constants.AddressZero; async function extractInfoFromCreateDaoTx(tx: any): Promise<{ dao: any; creator: any; - subdomain: any; plugin: any; helpers: any; permissions: any; @@ -107,7 +110,6 @@ async function extractInfoFromCreateDaoTx(tx: any): Promise<{ return { dao: daoRegisteredEvent.args.dao, creator: daoRegisteredEvent.args.creator, - subdomain: daoRegisteredEvent.args.subdomain, plugin: installationPreparedEvent.args.plugin, helpers: installationPreparedEvent.args.preparedSetupData.helpers, permissions: installationPreparedEvent.args.preparedSetupData.permissions, @@ -123,7 +125,7 @@ async function getAnticipatedAddress(from: string) { return anticipatedAddress; } -describe('DAOFactory: ', function () { +describe.only('DAOFactory: ', function () { let daoFactory: DAOFactory; let managingDao: any; @@ -142,6 +144,8 @@ describe('DAOFactory: ', function () { let signers: SignerWithAddress[]; let ownerAddress: string; + let ensSubdomainRegistrar: ENSSubdomainRegistrar; + before(async () => { signers = await ethers.getSigners(); ownerAddress = await signers[0].getAddress(); @@ -151,28 +155,28 @@ describe('DAOFactory: ', function () { // Managing DAO managingDao = await deployNewDAO(signers[0]); - // ENS subdomain Registry - const ensSubdomainRegistrar = await deployENSSubdomainRegistrar( - signers[0], - managingDao, - registrarManagedDomain - ); - // DAO Registry const DAORegistry = new DAORegistry__factory(signers[0]); daoRegistry = await deployWithProxy(DAORegistry); await daoRegistry.initialize( - managingDao.address, - ensSubdomainRegistrar.address + managingDao.address + // ensSubdomainRegistrar.address ); // Plugin Repo Registry pluginRepoRegistry = await deployPluginRepoRegistry( managingDao, - ensSubdomainRegistrar, signers[0] ); + // ENS subdomain Registry + ensSubdomainRegistrar = await deployENSSubdomainRegistrar( + signers[0], + managingDao, + daoRegistry.address, + registrarManagedDomain + ); + // Plugin Setup Processor psp = await deployPluginSetupProcessor(pluginRepoRegistry); @@ -223,7 +227,7 @@ describe('DAOFactory: ', function () { pluginSetupV1Mock = await PluginUUPSUpgradeableSetupV1Mock.deploy(); const tx = await pluginRepoFactory.createPluginRepoWithFirstVersion( - 'plugin-uupsupgradeable-setup-v1-mock', + // 'plugin-uupsupgradeable-setup-v1-mock', pluginSetupV1Mock.address, ownerAddress, '0x00', @@ -288,23 +292,59 @@ describe('DAOFactory: ', function () { it('reverts if no plugin is provided', async () => { await expect( - daoFactory.createDao(daoSettings, []) + daoFactory.createDao(daoSettings, [], []) ).to.be.revertedWithCustomError(daoFactory, 'NoPluginProvided'); }); + async function createAction() { + const to = ensSubdomainRegistrar.address; + const value = 0; + const data = (ensSubdomainRegistrar.interface as any).encodeFunctionData( + 'registerSubnode(bytes32)', + [ensLabelHash(daoDummySubdomain)] + ); + return {to, value, data}; + } + it('creates a dao and initializes with correct args', async () => { const dao = await getAnticipatedAddress(daoFactory.address); const factory = new DAO__factory(signers[0]); const daoContract = factory.attach(dao); - expect(await daoFactory.createDao(daoSettings, [pluginInstallationData])) + const action = await createAction(); + expect( + await daoFactory.createDao( + daoSettings, + [pluginInstallationData], + [action] + ) + ) .to.emit(daoContract, EVENTS.MetadataSet) .withArgs(daoSettings.metadata) .to.emit(daoContract, EVENTS.TrustedForwarderSet) .withArgs(daoSettings.trustedForwarder) .to.emit(daoContract, EVENTS.NewURI) .withArgs(daoSettings.daoURI); + + // check the new subdomain owner is the registrar + const fullDomain = `${daoDummySubdomain}.${registrarManagedDomain}`; + const ENSRegistry = new ENSRegistry__factory(signers[0]); + const ens = ENSRegistry.attach(await ensSubdomainRegistrar.ens()); + + expect(await ens.owner(ensDomainHash(fullDomain))).to.equal( + ensSubdomainRegistrar.address + ); + + // check the new subdomain resolver target + const PublicResolverFactory = new PublicResolver__factory(signers[0]); + const resolver = PublicResolverFactory.attach( + await ensSubdomainRegistrar.resolver() + ); + + expect( + await await resolver['addr(bytes32)'](ensDomainHash(fullDomain)) + ).to.equal(daoContract.address); }); it('creates a dao with a plugin and emits correct events', async () => { @@ -321,9 +361,11 @@ describe('DAOFactory: ', function () { pluginInstallationData.data ); - const tx = await daoFactory.createDao(daoSettings, [ - pluginInstallationData, - ]); + const tx = await daoFactory.createDao( + daoSettings, + [pluginInstallationData], + [] + ); const {dao} = await extractInfoFromCreateDaoTx(tx); const pluginRepoPointer: PluginRepoPointer = [ @@ -337,7 +379,7 @@ describe('DAOFactory: ', function () { await expect(tx) .to.emit(daoRegistry, EVENTS.DAORegistered) - .withArgs(dao, ownerAddress, daoSettings.subdomain) + .withArgs(dao, ownerAddress) .to.emit(psp, EVENTS.InstallationPrepared) .withArgs( daoFactory.address, @@ -359,9 +401,11 @@ describe('DAOFactory: ', function () { }); it('creates a dao with a plugin and sets plugin permissions on dao correctly', async () => { - const tx = await daoFactory.createDao(daoSettings, [ - pluginInstallationData, - ]); + const tx = await daoFactory.createDao( + daoSettings, + [pluginInstallationData], + [] + ); const {dao, permissions} = await extractInfoFromCreateDaoTx(tx); const factory = new DAO__factory(signers[0]); @@ -381,9 +425,11 @@ describe('DAOFactory: ', function () { }); it('creates a dao and sets its own permissions correctly on itself', async () => { - const tx = await daoFactory.createDao(daoSettings, [ - pluginInstallationData, - ]); + const tx = await daoFactory.createDao( + daoSettings, + [pluginInstallationData], + [] + ); const {dao} = await extractInfoFromCreateDaoTx(tx); const factory = new DAO__factory(signers[0]); @@ -433,9 +479,11 @@ describe('DAOFactory: ', function () { }); it('revokes all temporarly granted permissions', async () => { - const tx = await daoFactory.createDao(daoSettings, [ - pluginInstallationData, - ]); + const tx = await daoFactory.createDao( + daoSettings, + [pluginInstallationData], + [] + ); const {dao} = await extractInfoFromCreateDaoTx(tx); const factory = new DAO__factory(signers[0]); @@ -518,7 +566,7 @@ describe('DAOFactory: ', function () { }; const plugins = [plugin1, plugin2]; - const tx = await daoFactory.createDao(daoSettings, plugins); + const tx = await daoFactory.createDao(daoSettings, plugins, []); // Count how often the event was emitted by inspecting the logs const receipt = await tx.wait(); @@ -561,7 +609,6 @@ describe('DAOFactory: ', function () { adminPluginSetup = await AdminPluginSetupFactory.deploy(); let tx = await pluginRepoFactory.createPluginRepoWithFirstVersion( - 'admin', adminPluginSetup.address, ownerAddress, '0x11', @@ -593,7 +640,11 @@ describe('DAOFactory: ', function () { adminPluginRepoPointer, data ); - tx = await daoFactory.createDao(daoSettings, [adminPluginInstallation]); + tx = await daoFactory.createDao( + daoSettings, + [adminPluginInstallation], + [] + ); { const installationPreparedEvent = await findEventTopicLog( diff --git a/packages/contracts/test/framework/dao/dao-registry.ts b/packages/contracts/test/framework/dao/dao-registry.ts index 552a063e1..49d3ca8df 100644 --- a/packages/contracts/test/framework/dao/dao-registry.ts +++ b/packages/contracts/test/framework/dao/dao-registry.ts @@ -29,7 +29,7 @@ const EVENTS = { DAORegistered: 'DAORegistered', }; -describe('DAORegistry', function () { +describe.only('DAORegistry', function () { let signers: SignerWithAddress[]; let daoRegistry: DAORegistry; let managingDao: DAO; @@ -51,13 +51,6 @@ describe('DAORegistry', function () { // Managing DAO managingDao = await deployNewDAO(signers[0]); - // ENS - ensSubdomainRegistrar = await deployENSSubdomainRegistrar( - signers[0], - managingDao, - topLevelDomain - ); - // Target DAO to be used as an example DAO to be registered targetDao = await deployNewDAO(signers[0]); @@ -66,9 +59,15 @@ describe('DAORegistry', function () { daoRegistry = await deployWithProxy(Registry); - await daoRegistry.initialize( - managingDao.address, - ensSubdomainRegistrar.address + await daoRegistry.initialize(managingDao.address); + + // ENS + // ! not needed but used in previous version tets + ensSubdomainRegistrar = await deployENSSubdomainRegistrar( + signers[0], + managingDao, + daoRegistry.address, + topLevelDomain ); // Grant the `REGISTER_DAO_PERMISSION_ID` permission in the DAO registry to `signers[0]` @@ -79,37 +78,35 @@ describe('DAORegistry', function () { ); // Grant the `REGISTER_ENS_SUBDOMAIN_PERMISSION_ID` permission on the ENS subdomain registrar to the DAO registry contract - await managingDao.grant( - ensSubdomainRegistrar.address, - daoRegistry.address, - ENS_REGISTRAR_PERMISSIONS.REGISTER_ENS_SUBDOMAIN_PERMISSION_ID - ); + // await managingDao.grant( + // ensSubdomainRegistrar.address, + // daoRegistry.address, + // ENS_REGISTRAR_PERMISSIONS.REGISTER_ENS_SUBDOMAIN_PERMISSION_ID + // ); }); it('succeeds even if the dao subdomain is empty', async function () { - await expect(daoRegistry.register(targetDao.address, ownerAddress, '')).to - .not.be.reverted; + await expect(daoRegistry.register(targetDao.address, ownerAddress)).to.not + .be.reverted; }); - it('successfully sets subdomainregistrar', async () => { - expect(await daoRegistry.subdomainRegistrar()).to.equal( - ensSubdomainRegistrar.address - ); - }); + // it('successfully sets subdomainregistrar', async () => { + // expect(await daoRegistry.subdomainRegistrar()).to.equal( + // ensSubdomainRegistrar.address + // ); + // }); it('Should register a new DAO successfully', async function () { - await expect( - daoRegistry.register(targetDao.address, ownerAddress, daoSubdomain) - ) + await expect(daoRegistry.register(targetDao.address, ownerAddress)) .to.emit(daoRegistry, EVENTS.DAORegistered) - .withArgs(targetDao.address, ownerAddress, daoSubdomain); + .withArgs(targetDao.address, ownerAddress); expect(await daoRegistry.entries(targetDao.address)).to.equal(true); }); it('fails to register if the sender lacks the required role', async () => { // Register a DAO successfully - await daoRegistry.register(targetDao.address, ownerAddress, daoSubdomain); + await daoRegistry.register(targetDao.address, ownerAddress); // Revoke the permission await managingDao.revoke( @@ -120,9 +117,7 @@ describe('DAORegistry', function () { const newTargetDao = await deployNewDAO(signers[0]); - await expect( - daoRegistry.register(newTargetDao.address, ownerAddress, daoSubdomain) - ) + await expect(daoRegistry.register(newTargetDao.address, ownerAddress)) .to.be.revertedWithCustomError(daoRegistry, 'DaoUnauthorized') .withArgs( managingDao.address, @@ -133,119 +128,109 @@ describe('DAORegistry', function () { }); it('fails to register if DAO already exists', async function () { - await daoRegistry.register( - targetDao.address, - ownerAddress, - daoSubdomainEnsLabelhash - ); + await daoRegistry.register(targetDao.address, ownerAddress); - await expect( - daoRegistry.register(targetDao.address, ownerAddress, daoSubdomain) - ) + await expect(daoRegistry.register(targetDao.address, ownerAddress)) .to.be.revertedWithCustomError(daoRegistry, 'ContractAlreadyRegistered') .withArgs(targetDao.address); }); it('fails to register a DAO with the same name twice', async function () { // Register the DAO name under the top level domain - await daoRegistry.register(targetDao.address, ownerAddress, daoSubdomain); + await daoRegistry.register(targetDao.address, ownerAddress); const newTargetDao = await deployNewDAO(signers[0]); const otherOwnerAddress = await (await ethers.getSigners())[1].getAddress(); + // ! no longer valid due to ens no longer part of the DAORegistry // Try to register the DAO name under the top level domain a second time - await expect( - daoRegistry.register( - newTargetDao.address, - otherOwnerAddress, - daoSubdomain - ) - ) - .to.be.revertedWithCustomError(ensSubdomainRegistrar, 'AlreadyRegistered') - .withArgs(daoDomainHash, ensSubdomainRegistrar.address); + // await expect(daoRegistry.register(newTargetDao.address, otherOwnerAddress)) + // .to.be.revertedWithCustomError(ensSubdomainRegistrar, 'AlreadyRegistered') + // .withArgs(daoDomainHash, ensSubdomainRegistrar.address); }); // without mocking we have to repeat the tests here to make sure the validation is correct - describe('subdomain validation', () => { - it('should validate the passed subdomain correctly (< 32 bytes long subdomain)', async () => { - const baseSubdomain = 'this-is-my-super-valid-subdomain'; - - // loop through the ascii table - for (let i = 0; i < 127; i++) { - const newTargetDao = await deployNewDAO(signers[0]); - - // replace the 10th char in the baseSubdomain - const subdomainName = - baseSubdomain.substring(0, 10) + - String.fromCharCode(i) + - baseSubdomain.substring(10 + 1); - - // test success if it is a valid char [0-9a-z\-] - if ((i > 47 && i < 58) || (i > 96 && i < 123) || i === 45) { - await expect( - daoRegistry.register( - newTargetDao.address, - ownerAddress, - subdomainName - ) - ) - .to.emit(daoRegistry, EVENTS.DAORegistered) - .withArgs(newTargetDao.address, ownerAddress, subdomainName); - continue; - } - - await expect( - daoRegistry.register( - newTargetDao.address, - ownerAddress, - subdomainName - ) - ) - .to.be.revertedWithCustomError(daoRegistry, 'InvalidDaoSubdomain') - .withArgs(subdomainName); - } - }).timeout(120000); - - it('should validate the passed subdomain correctly (> 32 bytes long subdomain)', async () => { - const baseSubdomain = - 'this-is-my-super-looooooooooooooooooooooooooong-valid-subdomain'; - - // loop through the ascii table - for (let i = 0; i < 127; i++) { - const newTargetDao = await deployNewDAO(signers[0]); - - // replace the 40th char in the baseSubdomain - const subdomainName = - baseSubdomain.substring(0, 40) + - String.fromCharCode(i) + - baseSubdomain.substring(40 + 1); - - // test success if it is a valid char [0-9a-z\-] - if ((i > 47 && i < 58) || (i > 96 && i < 123) || i === 45) { - await expect( - daoRegistry.register( - newTargetDao.address, - ownerAddress, - subdomainName - ) - ) - .to.emit(daoRegistry, EVENTS.DAORegistered) - .withArgs(newTargetDao.address, ownerAddress, subdomainName); - continue; - } - - await expect( - daoRegistry.register( - newTargetDao.address, - ownerAddress, - subdomainName - ) - ) - .to.be.revertedWithCustomError(daoRegistry, 'InvalidDaoSubdomain') - .withArgs(subdomainName); - } - }).timeout(120000); - }); + // ! not needed as ENS no longer part of the DAORegistry + // describe('subdomain validation', () => { + // it('should validate the passed subdomain correctly (< 32 bytes long subdomain)', async () => { + // const baseSubdomain = 'this-is-my-super-valid-subdomain'; + + // // loop through the ascii table + // for (let i = 0; i < 127; i++) { + // const newTargetDao = await deployNewDAO(signers[0]); + + // // replace the 10th char in the baseSubdomain + // const subdomainName = + // baseSubdomain.substring(0, 10) + + // String.fromCharCode(i) + + // baseSubdomain.substring(10 + 1); + + // // test success if it is a valid char [0-9a-z\-] + // if ((i > 47 && i < 58) || (i > 96 && i < 123) || i === 45) { + // await expect( + // daoRegistry.register( + // newTargetDao.address, + // ownerAddress, + // subdomainName + // ) + // ) + // .to.emit(daoRegistry, EVENTS.DAORegistered) + // .withArgs(newTargetDao.address, ownerAddress, subdomainName); + // continue; + // } + + // await expect( + // daoRegistry.register( + // newTargetDao.address, + // ownerAddress, + // subdomainName + // ) + // ) + // .to.be.revertedWithCustomError(daoRegistry, 'InvalidDaoSubdomain') + // .withArgs(subdomainName); + // } + // }).timeout(120000); + + // it('should validate the passed subdomain correctly (> 32 bytes long subdomain)', async () => { + // const baseSubdomain = + // 'this-is-my-super-looooooooooooooooooooooooooong-valid-subdomain'; + + // // loop through the ascii table + // for (let i = 0; i < 127; i++) { + // const newTargetDao = await deployNewDAO(signers[0]); + + // // replace the 40th char in the baseSubdomain + // const subdomainName = + // baseSubdomain.substring(0, 40) + + // String.fromCharCode(i) + + // baseSubdomain.substring(40 + 1); + + // // test success if it is a valid char [0-9a-z\-] + // if ((i > 47 && i < 58) || (i > 96 && i < 123) || i === 45) { + // await expect( + // daoRegistry.register( + // newTargetDao.address, + // ownerAddress, + // subdomainName + // ) + // ) + // .to.emit(daoRegistry, EVENTS.DAORegistered) + // .withArgs(newTargetDao.address, ownerAddress, subdomainName); + // continue; + // } + + // await expect( + // daoRegistry.register( + // newTargetDao.address, + // ownerAddress, + // subdomainName + // ) + // ) + // .to.be.revertedWithCustomError(daoRegistry, 'InvalidDaoSubdomain') + // .withArgs(subdomainName); + // } + // }).timeout(120000); + // }); describe('Protocol version', async () => { it('returns the current protocol version', async () => { @@ -272,6 +257,9 @@ describe('DAORegistry', function () { }); it('upgrades to a new implementation', async () => { + // remove ensSubdomainRegistrar since is no longer needed + delete initArgs.ensSubdomainRegistrar; + await deployAndUpgradeSelfCheck( signers[0], signers[1], @@ -305,7 +293,6 @@ describe('DAORegistry', function () { const toProtocolVersion = await getProtocolVersion( currentContractFactory.attach(toImplementation) ); - expect(fromProtocolVersion).to.not.deep.equal(toProtocolVersion); expect(fromProtocolVersion).to.deep.equal([1, 0, 0]); expect(toProtocolVersion).to.deep.equal(osxContractsVersion()); diff --git a/packages/contracts/test/test-utils/ens.ts b/packages/contracts/test/test-utils/ens.ts index 8559affaa..adce365bf 100644 --- a/packages/contracts/test/test-utils/ens.ts +++ b/packages/contracts/test/test-utils/ens.ts @@ -13,10 +13,12 @@ import {ensDomainHash, ensLabelHash} from '../../utils/ens'; import {deployWithProxy} from '../test-utils/proxy'; import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {ethers} from 'hardhat'; +import {Address} from 'hardhat-deploy/types'; export async function deployENSSubdomainRegistrar( owner: SignerWithAddress, managingDao: DAO, + registry: Address, domain: string ): Promise { const ENSRegistryFactory = new ENSRegistry__factory(owner); @@ -64,6 +66,7 @@ export async function deployENSSubdomainRegistrar( await ensSubdomainRegistrar.initialize( managingDao.address, ensRegistry.address, + registry, node ); diff --git a/packages/contracts/test/test-utils/repo.ts b/packages/contracts/test/test-utils/repo.ts index b3e1da063..6834cdfd8 100644 --- a/packages/contracts/test/test-utils/repo.ts +++ b/packages/contracts/test/test-utils/repo.ts @@ -46,7 +46,6 @@ export async function deployPluginRepoFactory( export async function deployPluginRepoRegistry( managingDao: any, - ensSubdomainRegistrar: any, signer: SignerWithAddress ): Promise { const PluginRepoRegistry = new PluginRepoRegistry__factory(signer); @@ -55,10 +54,7 @@ export async function deployPluginRepoRegistry( PluginRepoRegistry ); - await pluginRepoRegistry.initialize( - managingDao.address, - ensSubdomainRegistrar.address - ); + await pluginRepoRegistry.initialize(managingDao.address); return pluginRepoRegistry; }