From d9093d538eda3ad90fcb3bb66266096d6f549a5c Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Thu, 3 Jul 2025 19:02:48 -0700 Subject: [PATCH 01/26] Started updating SubReg test. Changed rootDomains registration to register them using Domain class. --- test/ZNSSubRegistrar.test.ts | 134 ++++++++++++++++++---------------- test/helpers/domain/domain.ts | 4 +- 2 files changed, 72 insertions(+), 66 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index ba5bf4813..94c297f79 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -59,6 +59,7 @@ import { deployCustomDecToken } from "./helpers/deploy/mocks"; import { getProxyImplAddress } from "./helpers/utils"; import { ICurvePriceConfig, IFixedPriceConfig } from "../src/deploy/missions/types"; import { IZNSContracts } from "../src/deploy/campaign/types"; +import Domain from "./helpers/domain/domain"; describe("ZNSSubRegistrar", () => { @@ -82,7 +83,7 @@ describe("ZNSSubRegistrar", () => { let zns : IZNSContracts; let zeroVault : SignerWithAddress; - let rootHash : string; + let domain : Domain; let rootPriceConfig : IFixedPriceConfig; const subTokenURI = "https://token-uri.com/8756a4b6f"; @@ -126,13 +127,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - // register root domain - rootHash = await registrationWithSetup({ + domain = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - domainLabel: "root", - fullConfig: { + domainConfig: { + owner: rootOwner, + label: "root", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig(rootPriceConfig), @@ -145,6 +146,8 @@ describe("ZNSSubRegistrar", () => { }, }, }); + + await domain.register(); }); it("Sets the payment config when given", async () => { @@ -155,7 +158,7 @@ describe("ZNSSubRegistrar", () => { await defaultSubdomainRegistration({ user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: subdomain, domainContent: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -166,7 +169,7 @@ describe("ZNSSubRegistrar", () => { }, }); - const subHash = await zns.subRegistrar.hashWithParent(rootHash, subdomain); + const subHash = await zns.subRegistrar.hashWithParent(domain.hash, subdomain); const config = await zns.treasury.paymentConfigs(subHash); expect(config.token).to.eq(await zns.meowToken.getAddress()); expect(config.beneficiary).to.eq(lvl2SubOwner.address); @@ -178,12 +181,12 @@ describe("ZNSSubRegistrar", () => { await defaultSubdomainRegistration({ zns, user: lvl2SubOwner, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: subdomain, tokenURI: subTokenURI, }); - const subHash = await zns.subRegistrar.hashWithParent(rootHash, subdomain); + const subHash = await zns.subRegistrar.hashWithParent(domain.hash, subdomain); const config = await zns.treasury.paymentConfigs(subHash); expect(config.token).to.eq(ethers.ZeroAddress); expect(config.beneficiary).to.eq(ethers.ZeroAddress); @@ -267,7 +270,7 @@ describe("ZNSSubRegistrar", () => { // try to register a subdomain await expect( zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: rootHash, + parentHash: domain.hash, label: "subpaused", domainAddress: lvl2SubOwner.address, tokenOwner: ethers.ZeroAddress, @@ -299,7 +302,7 @@ describe("ZNSSubRegistrar", () => { await registrationWithSetup({ user: admin, zns, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "subadmin", }); @@ -322,7 +325,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "sub", tokenURI: subTokenURI, fullConfig: { @@ -360,7 +363,7 @@ describe("ZNSSubRegistrar", () => { { user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: alphaNumeric, domainContent: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -373,12 +376,12 @@ describe("ZNSSubRegistrar", () => { await defaultSubdomainRegistration({ user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: "subbbb", tokenOwner: zeroVault.address, // <-- }); - const subHash = await zns.subRegistrar.hashWithParent(rootHash, "subbbb"); + const subHash = await zns.subRegistrar.hashWithParent(domain.hash, "subbbb"); // check owners of hash and token const ownerFromReg = await zns.registry.getDomainOwner(subHash); @@ -398,7 +401,7 @@ describe("ZNSSubRegistrar", () => { { user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: nameA, domainContent: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -411,7 +414,7 @@ describe("ZNSSubRegistrar", () => { { user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: nameB, domainContent: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -424,7 +427,7 @@ describe("ZNSSubRegistrar", () => { { user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: nameC, domainContent: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -437,7 +440,7 @@ describe("ZNSSubRegistrar", () => { { user: lvl2SubOwner, zns, - parentHash: rootHash, + parentHash: domain.hash, subdomainLabel: nameD, domainContent: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -486,7 +489,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "a", tokenURI: subTokenURI, fullConfig: { @@ -522,7 +525,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "a".repeat(100000), tokenURI: subTokenURI, fullConfig: FULL_DISTR_CONFIG_EMPTY, @@ -550,7 +553,7 @@ describe("ZNSSubRegistrar", () => { await expect( zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: rootHash, + parentHash: domain.hash, label: "subfunds", domainAddress: lvl2SubOwner.address, tokenOwner: ethers.ZeroAddress, @@ -576,7 +579,7 @@ describe("ZNSSubRegistrar", () => { await expect( zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: rootHash, + parentHash: domain.hash, label: "suballowance", domainAddress: lvl2SubOwner.address, tokenOwner: ethers.ZeroAddress, @@ -685,7 +688,7 @@ describe("ZNSSubRegistrar", () => { const isOdd = i % 2 !== 0; const subdomainObj : ISubRegistrarConfig = { - parentHash: rootHash, + parentHash: domain.hash, label: `subdomain${i + 1}`, domainAddress: admin.address, tokenOwner: ethers.ZeroAddress, @@ -728,7 +731,7 @@ describe("ZNSSubRegistrar", () => { // "DomainRegistered" event log const { parentHash, domainHash, label, tokenOwner, tokenURI, domainOwner, domainAddress } = logs[i].args; - expect(parentHash).to.eq(rootHash); + expect(parentHash).to.eq(domain.hash); expect(domainHashExpected).to.eq(domainHash); expect(label).to.eq(subdomain.label); expect(tokenURI).to.eq(subdomain.tokenURI); @@ -749,7 +752,7 @@ describe("ZNSSubRegistrar", () => { const isOdd = i % 2 !== 0; const subdomainObj : ISubRegistrarConfig = { - parentHash: rootHash, + parentHash: domain.hash, label: `sub${i + 1}`, domainAddress: lvl3SubOwner.address, tokenOwner: ethers.ZeroAddress, @@ -773,7 +776,7 @@ describe("ZNSSubRegistrar", () => { // first goes with rootHash parentHashes.push( await zns.subRegistrar.hashWithParent( - i === 0 ? rootHash : parentHashes[i - 1], + i === 0 ? domain.hash : parentHashes[i - 1], subdomainObj.label ) ); @@ -797,7 +800,7 @@ describe("ZNSSubRegistrar", () => { i > 0 ? expect(parentHash).to.eq(parentHashes[i - 1]) : - expect(parentHash).to.eq(rootHash); + expect(parentHash).to.eq(domain.hash); expect(domainHash).to.eq(parentHashes[i]); expect(label).to.eq(subdomain.label); expect(tokenURI).to.eq(subdomain.tokenURI); @@ -809,7 +812,7 @@ describe("ZNSSubRegistrar", () => { it("Should revert when register the same domain twice using #registerSubdomainBulk", async () => { const subdomainObj : ISubRegistrarConfig = { - parentHash: rootHash, + parentHash: domain.hash, label: "subdomain1", domainAddress: admin.address, tokenOwner: ethers.ZeroAddress, @@ -909,7 +912,7 @@ describe("ZNSSubRegistrar", () => { let referenceParentHash; if (i === 0) { - parentHash = rootHash; + parentHash = domain.hash; referenceParentHash = parentHash; } else if (i > 0 && i < 5) { parentHash = ethers.ZeroHash; @@ -993,7 +996,7 @@ describe("ZNSSubRegistrar", () => { const registrations : Array = [ { - parentHash: rootHash, + parentHash: domain.hash, label: "subpaused", domainAddress: lvl2SubOwner.address, tokenOwner: ethers.ZeroAddress, @@ -1865,7 +1868,6 @@ describe("ZNSSubRegistrar", () => { }); describe("Token movements with different distr setups", () => { - let rootHash : string; let fixedPrice : bigint; let feePercentage : bigint; let token2 : CustomDecimalTokenMock; @@ -1938,12 +1940,13 @@ describe("ZNSSubRegistrar", () => { await zns.meowToken.connect(rootOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); // register root domain - rootHash = await registrationWithSetup({ + domain = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - domainLabel: "root", - fullConfig: { + domainConfig: { + owner: rootOwner, + tokenOwner: rootOwner.address, + label: "root", + parentHash: ethers.ZeroHash, distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig({ @@ -1959,6 +1962,8 @@ describe("ZNSSubRegistrar", () => { }, }, }); + + await domain.register(); }); it("FixedPricer - StakePayment - stake fee - 5 decimals", async () => { @@ -1977,7 +1982,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "fixedstake", fullConfig: { distrConfig: { @@ -2057,7 +2062,7 @@ describe("ZNSSubRegistrar", () => { zns, tokenOwner: rootOwner.address, user: rootOwner, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "subdomain", }); @@ -2079,7 +2084,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "fixedstakenofee", fullConfig: { distrConfig: { @@ -2158,7 +2163,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "fixeddirectnofee", fullConfig: { distrConfig: { @@ -2243,7 +2248,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "asympstake", fullConfig: { distrConfig: { @@ -2331,7 +2336,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "curvestakenofee", fullConfig: { distrConfig: { @@ -2410,7 +2415,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "curvedirectnofee", fullConfig: { distrConfig: { @@ -2482,7 +2487,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "zeroprice", fullConfig: { distrConfig: { @@ -2569,7 +2574,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "zeropricead", fullConfig: { distrConfig: { @@ -2659,7 +2664,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "zeropriceas", fullConfig: { distrConfig: { @@ -2748,7 +2753,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "zeropricefs", fullConfig: { distrConfig: { @@ -2841,7 +2846,7 @@ describe("ZNSSubRegistrar", () => { zns, user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, - parentHash: rootHash, + parentHash: domain.hash, domainLabel: "incorrectparent", fullConfig: { distrConfig: { @@ -4129,7 +4134,6 @@ describe("ZNSSubRegistrar", () => { describe("UUPS", () => { let fixedPrice : bigint; - let rootHash : string; beforeEach(async () => { [ @@ -4160,12 +4164,12 @@ describe("ZNSSubRegistrar", () => { fixedPrice = ethers.parseEther("397.13"); // register root domain - rootHash = await registrationWithSetup({ + domain = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - domainLabel: "root", - fullConfig: { + domainConfig: { + owner: rootOwner, + tokenOwner: rootOwner.address, + label: "root", distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig({ @@ -4181,6 +4185,8 @@ describe("ZNSSubRegistrar", () => { }, }, }); + + await domain.register(); }); it("Allows an authorized user to upgrade the contract", async () => { @@ -4248,7 +4254,7 @@ describe("ZNSSubRegistrar", () => { user: lvl2SubOwner, tokenOwner: lvl2SubOwner.address, domainLabel, - parentHash: rootHash, + parentHash: domain.hash, fullConfig: { distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), @@ -4268,7 +4274,7 @@ describe("ZNSSubRegistrar", () => { await zns.subRegistrar.setRootRegistrar(lvl2SubOwner.address); - const rootDistrConfig = await zns.subRegistrar.distrConfigs(rootHash); + const rootDistrConfig = await zns.subRegistrar.distrConfigs(domain.hash); const contractCalls = [ zns.subRegistrar.getAccessController(), @@ -4300,7 +4306,7 @@ describe("ZNSSubRegistrar", () => { const newRegistrarProxy = factory.attach(await zns.subRegistrar.getAddress()) as ZNSSubRegistrarUpgradeMock; // check values in storage - const rootConfigBefore = await newRegistrarProxy.distrConfigs(rootHash); + const rootConfigBefore = await newRegistrarProxy.distrConfigs(domain.hash); expect(rootConfigBefore.accessType).to.eq(AccessType.OPEN); expect(rootConfigBefore.pricerContract).to.eq(await zns.fixedPricer.getAddress()); expect(rootConfigBefore.paymentType).to.eq(PaymentType.DIRECT); @@ -4319,7 +4325,7 @@ describe("ZNSSubRegistrar", () => { // register a subdomain with new logic await newRegistrarProxy.connect(lvl2SubOwner).registerSubdomain({ - parentHash: rootHash, + parentHash: domain.hash, label: "subbb", domainAddress: lvl2SubOwner.address, tokenOwner: ethers.ZeroAddress, @@ -4333,7 +4339,7 @@ describe("ZNSSubRegistrar", () => { user: lvl2SubOwner, }); - const rootConfigAfter = await zns.subRegistrar.distrConfigs(rootHash); + const rootConfigAfter = await zns.subRegistrar.distrConfigs(domain.hash); expect(rootConfigAfter.accessType).to.eq(rootConfigBefore.accessType); expect(rootConfigAfter.pricerContract).to.eq(rootConfigBefore.pricerContract); expect(rootConfigAfter.priceConfig).to.eq(rootConfigBefore.priceConfig); @@ -4351,12 +4357,12 @@ describe("ZNSSubRegistrar", () => { // try setting new fields to the new struct await newRegistrarProxy.connect(rootOwner).setDistributionConfigForDomain( - rootHash, + domain.hash, updatedStructConfig ); // check what we got for new - const rootConfigFinal = await newRegistrarProxy.distrConfigs(rootHash); + const rootConfigFinal = await newRegistrarProxy.distrConfigs(domain.hash); const subConfigAfter = await newRegistrarProxy.distrConfigs(subHash); // validate the new config has been set correctly diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 4ed8e1688..ad0e3cdc9 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -10,9 +10,9 @@ import { curvePriceConfigEmpty, distrConfigEmpty, fixedPriceConfigEmpty, payment import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { time } from "@nomicfoundation/hardhat-network-helpers"; import { fundApprove } from "../register-setup"; -import { ContractTransactionReceipt, ContractTransactionResponse } from "ethers"; +import { ContractTransactionResponse } from "ethers"; import { expect } from "chai"; -import { decodePriceConfig, encodePriceConfig } from "../pricing"; +import { encodePriceConfig } from "../pricing"; export default class Domain { From 1623b214cb94f0b6cb642cb095599e474672db59 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Fri, 1 Aug 2025 16:35:28 -0700 Subject: [PATCH 02/26] Subregistrar tests optimization --- test/ZNSSubRegistrar.test.ts | 234 +++++++++++++++++++----------- test/helpers/deploy/deploy-zns.ts | 1 - test/helpers/domain/domain.ts | 8 +- 3 files changed, 150 insertions(+), 93 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 94c297f79..abd6e78b1 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -60,9 +60,10 @@ import { getProxyImplAddress } from "./helpers/utils"; import { ICurvePriceConfig, IFixedPriceConfig } from "../src/deploy/missions/types"; import { IZNSContracts } from "../src/deploy/campaign/types"; import Domain from "./helpers/domain/domain"; +import { ZeroHash } from "ethers"; -describe("ZNSSubRegistrar", () => { +describe.only("ZNSSubRegistrar", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -84,6 +85,7 @@ describe("ZNSSubRegistrar", () => { let zeroVault : SignerWithAddress; let domain : Domain; + let subdomain : Domain; let rootPriceConfig : IFixedPriceConfig; const subTokenURI = "https://token-uri.com/8756a4b6f"; @@ -151,43 +153,52 @@ describe("ZNSSubRegistrar", () => { }); it("Sets the payment config when given", async () => { - const subdomain = "world-subdomain"; + const subdomainLabel = "world-subdomain"; await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - await defaultSubdomainRegistration({ - user: lvl2SubOwner, + subdomain = new Domain({ zns, - parentHash: domain.hash, - subdomainLabel: subdomain, - domainContent: lvl2SubOwner.address, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: lvl2SubOwner.address, + domainConfig: { + owner: lvl2SubOwner, + parentHash: domain.hash, + label: subdomainLabel, + domainAddress: lvl2SubOwner.address, + tokenURI: subTokenURI, + distrConfig: distrConfigEmpty, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, }, }); + await subdomain.register(); - const subHash = await zns.subRegistrar.hashWithParent(domain.hash, subdomain); - const config = await zns.treasury.paymentConfigs(subHash); + const config = await zns.treasury.paymentConfigs(subdomain.hash); expect(config.token).to.eq(await zns.meowToken.getAddress()); expect(config.beneficiary).to.eq(lvl2SubOwner.address); }); it("Does not set the payment config when the beneficiary is the zero address", async () => { - const subdomain = "not-world-subdomain"; + const subdomainLabel = "not-world-subdomain"; - await defaultSubdomainRegistration({ + subdomain = new Domain({ zns, - user: lvl2SubOwner, - parentHash: domain.hash, - subdomainLabel: subdomain, - tokenURI: subTokenURI, + domainConfig: { + owner: lvl2SubOwner, + parentHash: domain.hash, + label: subdomainLabel, + tokenURI: subTokenURI, + distrConfig: distrConfigEmpty, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: ethers.ZeroAddress, + }, + }, }); + await subdomain.register(); - const subHash = await zns.subRegistrar.hashWithParent(domain.hash, subdomain); - const config = await zns.treasury.paymentConfigs(subHash); + const config = await zns.treasury.paymentConfigs(subdomain.hash); expect(config.token).to.eq(ethers.ZeroAddress); expect(config.beneficiary).to.eq(ethers.ZeroAddress); }); @@ -195,13 +206,13 @@ describe("ZNSSubRegistrar", () => { // eslint-disable-next-line max-len it("should revert when trying to register a subdomain before parent has set it's config with FixedPricer", async () => { // register a new root domain - const newRootHash = await registrationWithSetup({ + domain = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - domainLabel: "rootunsetfixed", - setConfigs: false, - fullConfig: { + domainConfig: { + owner: rootOwner, + label: "rootunsetfixed", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, distrConfig: distrConfigEmpty, paymentConfig: { token: await zns.meowToken.getAddress(), @@ -209,20 +220,25 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await domain.register(); - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: newRootHash, + subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, label: "subunset", - domainAddress: lvl2SubOwner.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: subTokenURI, + parentHash: domain.hash, + tokenOwner: lvl2SubOwner.address, distrConfig: distrConfigEmpty, paymentConfig: { token: await zns.meowToken.getAddress(), - beneficiary : rootOwner.address, + beneficiary: rootOwner.address, }, - }) + }, + }); + + await expect( + subdomain.register() ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -232,13 +248,13 @@ describe("ZNSSubRegistrar", () => { // eslint-disable-next-line max-len it("should revert when trying to register a subdomain before parent has set it's config with CurvePricer", async () => { // register a new root domain - const newRootHash = await registrationWithSetup({ + + domain = new Domain({ zns, - user: rootOwner, - tokenOwner: lvl2SubOwner.address, - domainLabel: "rootunsetcurve", - setConfigs: false, - fullConfig: { + domainConfig: { + owner: rootOwner, + tokenOwner: lvl2SubOwner.address, + label: "rootunsetcurve", distrConfig: distrConfigEmpty, paymentConfig: { token: await zns.meowToken.getAddress(), @@ -246,17 +262,22 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await domain.register(); - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: newRootHash, + subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, label: "subunset", - domainAddress: lvl2SubOwner.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: subTokenURI, + parentHash: domain.hash, + tokenOwner: lvl2SubOwner.address, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + subdomain.register() ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -267,29 +288,62 @@ describe("ZNSSubRegistrar", () => { // pause the sub registrar await zns.subRegistrar.connect(admin).pauseRegistration(); + expect(await zns.subRegistrar.registrationPaused()).to.be.true; + + domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "rootpaused", + parentHash: hre.ethers.ZeroHash, + tokenOwner: rootOwner.address, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl3SubOwner, + label: "subpaused", + parentHash: domain.hash, + tokenOwner: lvl2SubOwner.address, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + }); + // try to register a subdomain await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: domain.hash, - label: "subpaused", - domainAddress: lvl2SubOwner.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - paymentConfig: paymentConfigEmpty, - }) + sub.register(lvl3SubOwner) ).to.be.revertedWithCustomError( zns.subRegistrar, REGISTRATION_PAUSED_ERR, ); - - // unpause the sub registrar - await zns.subRegistrar.connect(admin).unpauseRegistration(); }); it("should register successfully as ADMIN_ROLE during a registration pause", async () => { - // pause the sub registrar - await zns.subRegistrar.connect(admin).pauseRegistration(); + expect(await zns.accessController.isAdmin(admin.address)).to.be.true; + expect(zns.accessController.target).eq(await zns.subRegistrar.getAccessController()); + expect(await zns.subRegistrar.registrationPaused()).to.be.true; // approve treasury @@ -299,23 +353,27 @@ describe("ZNSSubRegistrar", () => { ); // try to register a subdomain as admin - await registrationWithSetup({ - user: admin, - zns, - parentHash: domain.hash, - domainLabel: "subadmin", - }); - - const domainHash = await getDomainHashFromEvent({ + subdomain = new Domain({ zns, - user: admin, + domainConfig: { + owner: admin, + label: "subadmin", + parentHash: domain.hash, + tokenOwner: admin.address, + distrConfig: distrConfigEmpty, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: admin.address, + }, + }, }); + await subdomain.register(admin); // check that the domain was registered - const owner = await zns.registry.getDomainOwner(domainHash); + const owner = await zns.registry.getDomainOwner(subdomain.hash); expect(owner).to.eq(admin.address); - // unpause the sub registrar + // unpause the sub registrar for further tests await zns.subRegistrar.connect(admin).unpauseRegistration(); expect(await zns.subRegistrar.registrationPaused()).to.be.false; }); @@ -353,23 +411,23 @@ describe("ZNSSubRegistrar", () => { it("Can register a subdomain with characters [a-z0-9-]", async () => { const alphaNumeric = "0x0dwidler0x0"; - // Add allowance - await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - // While "to.not.be.reverted" isn't really a full "test" - // we don't emit a custom event here, only in the `rootRegistrar.coreRegister` - // call. So we can't use the `.to.emit` syntax - await expect(defaultSubdomainRegistration( - { - user: lvl2SubOwner, - zns, + subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: alphaNumeric, parentHash: domain.hash, - subdomainLabel: alphaNumeric, - domainContent: lvl2SubOwner.address, + tokenOwner: lvl2SubOwner.address, tokenURI: subTokenURI, distrConfig: distrConfigEmpty, - } - )).to.not.be.reverted; + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + }); + + await subdomain.registerAndValidateDomain(); }); it("should register a subdomain with token assigned to a different address if provided", async () => { diff --git a/test/helpers/deploy/deploy-zns.ts b/test/helpers/deploy/deploy-zns.ts index 2e7e0179b..024c9dce3 100644 --- a/test/helpers/deploy/deploy-zns.ts +++ b/test/helpers/deploy/deploy-zns.ts @@ -47,7 +47,6 @@ import { import { DOMAIN_TOKEN_ROLE, REGISTRAR_ROLE } from "../../../src/deploy/constants"; import { getProxyImplAddress } from "../utils"; import { meowTokenName, meowTokenSymbol } from "../../../src/deploy/missions/contracts"; -import { IZNSContracts } from "../../../src/deploy/campaign/types"; export const deployAccessController = async ({ diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index ad0e3cdc9..aeb8c68b6 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -103,7 +103,7 @@ export default class Domain { parentHash: this.parentHash, user: user ? user : this.owner, domainLabel: this.label, - })) as Promise; + })); } async register (executor ?: SignerWithAddress) : Promise { @@ -126,7 +126,7 @@ export default class Domain { let txPromise : ContractTransactionResponse; // mint and approve strict amount of tokens for domain registration - await this.mintAndApproveForDomain(executor); + await this.mintAndApproveForDomain(executor ? executor : owner); if (this.isRoot) { txPromise = await zns.rootRegistrar.connect(executor ? executor : owner).registerRootDomain({ @@ -149,7 +149,7 @@ export default class Domain { }); } - this.hash = await this.getDomainHashFromEvent(executor); + this.hash = await this.getDomainHashFromEvent(executor ? executor : owner); return txPromise; } @@ -252,7 +252,7 @@ export default class Domain { async registerAndValidateDomain ( executor ?: SignerWithAddress ) : Promise { - const txPromise = await this.register(executor); + const txPromise = await this.register(executor ? executor : this.owner); // check domain existence with event await expect(txPromise) From 6b18561daed0b64d9bc0683dc6cfbbf7e3718ee1 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 5 Aug 2025 20:02:21 -0700 Subject: [PATCH 03/26] More test fixes according to domain registration. Changed executor if statement to signer var. --- test/ZNSSubRegistrar.test.ts | 411 +++++++++++++++++++++------------- test/helpers/domain/domain.ts | 10 +- 2 files changed, 266 insertions(+), 155 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index abd6e78b1..1fc59d44b 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-shadow, no-shadow */ import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { + IDistributionConfig, IDomainConfigForTest, IPathRegResult, ISubRegistrarConfig, @@ -84,9 +85,8 @@ describe.only("ZNSSubRegistrar", () => { let zns : IZNSContracts; let zeroVault : SignerWithAddress; - let domain : Domain; - let subdomain : Domain; let rootPriceConfig : IFixedPriceConfig; + let defaultDistrConfig : IDistributionConfig; const subTokenURI = "https://token-uri.com/8756a4b6f"; describe("Single Subdomain Registration", () => { @@ -129,50 +129,48 @@ describe.only("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - domain = new Domain({ + defaultDistrConfig = { + pricerContract: zns.fixedPricer.target, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + priceConfig: encodePriceConfig(rootPriceConfig), + }; + }); + + it("Sets the payment config when given", async () => { + const domain = new Domain({ zns, domainConfig: { owner: rootOwner, - label: "root", + label: "world1", parentHash: ethers.ZeroHash, tokenOwner: rootOwner.address, - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: encodePriceConfig(rootPriceConfig), - accessType: AccessType.OPEN, - paymentType: PaymentType.DIRECT, - }, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, paymentConfig: { token: await zns.meowToken.getAddress(), beneficiary: rootOwner.address, }, }, }); + await domain.register(rootOwner); - await domain.register(); - }); - - it("Sets the payment config when given", async () => { - const subdomainLabel = "world-subdomain"; - - await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - subdomain = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: lvl2SubOwner, parentHash: domain.hash, - label: subdomainLabel, + label: "world-subdomain", domainAddress: lvl2SubOwner.address, tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, + distrConfig: defaultDistrConfig, paymentConfig: { token: await zns.meowToken.getAddress(), beneficiary: lvl2SubOwner.address, }, }, }); - await subdomain.register(); + await subdomain.register(lvl2SubOwner); const config = await zns.treasury.paymentConfigs(subdomain.hash); expect(config.token).to.eq(await zns.meowToken.getAddress()); @@ -180,16 +178,31 @@ describe.only("ZNSSubRegistrar", () => { }); it("Does not set the payment config when the beneficiary is the zero address", async () => { - const subdomainLabel = "not-world-subdomain"; + const domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "world", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); - subdomain = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: lvl2SubOwner, parentHash: domain.hash, - label: subdomainLabel, + label: "not-world-subdomain", tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, + distrConfig: defaultDistrConfig, paymentConfig: { token: await zns.meowToken.getAddress(), beneficiary: ethers.ZeroAddress, @@ -205,8 +218,7 @@ describe.only("ZNSSubRegistrar", () => { // eslint-disable-next-line max-len it("should revert when trying to register a subdomain before parent has set it's config with FixedPricer", async () => { - // register a new root domain - domain = new Domain({ + const domain = new Domain({ zns, domainConfig: { owner: rootOwner, @@ -222,7 +234,7 @@ describe.only("ZNSSubRegistrar", () => { }); await domain.register(); - subdomain = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: lvl2SubOwner, @@ -248,8 +260,7 @@ describe.only("ZNSSubRegistrar", () => { // eslint-disable-next-line max-len it("should revert when trying to register a subdomain before parent has set it's config with CurvePricer", async () => { // register a new root domain - - domain = new Domain({ + const domain = new Domain({ zns, domainConfig: { owner: rootOwner, @@ -264,7 +275,7 @@ describe.only("ZNSSubRegistrar", () => { }); await domain.register(); - subdomain = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: lvl2SubOwner, @@ -290,19 +301,14 @@ describe.only("ZNSSubRegistrar", () => { expect(await zns.subRegistrar.registrationPaused()).to.be.true; - domain = new Domain({ + const domain = new Domain({ zns, domainConfig: { owner: rootOwner, label: "rootpaused", parentHash: hre.ethers.ZeroHash, tokenOwner: rootOwner.address, - distrConfig: { - pricerContract: ethers.ZeroAddress, - paymentType: PaymentType.DIRECT, - accessType: AccessType.OPEN, - priceConfig: ZeroHash, - }, + distrConfig: defaultDistrConfig, paymentConfig: { token: await zns.meowToken.getAddress(), beneficiary: rootOwner.address, @@ -311,7 +317,7 @@ describe.only("ZNSSubRegistrar", () => { }); await domain.register(); - const sub = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: lvl3SubOwner, @@ -333,7 +339,7 @@ describe.only("ZNSSubRegistrar", () => { // try to register a subdomain await expect( - sub.register(lvl3SubOwner) + subdomain.register(lvl3SubOwner) ).to.be.revertedWithCustomError( zns.subRegistrar, REGISTRATION_PAUSED_ERR, @@ -341,9 +347,8 @@ describe.only("ZNSSubRegistrar", () => { }); it("should register successfully as ADMIN_ROLE during a registration pause", async () => { - expect(await zns.accessController.isAdmin(admin.address)).to.be.true; expect(zns.accessController.target).eq(await zns.subRegistrar.getAccessController()); - + expect(await zns.accessController.isAdmin(admin.address)).to.be.true; expect(await zns.subRegistrar.registrationPaused()).to.be.true; // approve treasury @@ -352,8 +357,24 @@ describe.only("ZNSSubRegistrar", () => { ethers.MaxUint256, ); + const domain = new Domain({ + zns, + domainConfig: { + owner: admin, + label: "root1paused1for1sub", + parentHash: hre.ethers.ZeroHash, + tokenOwner: rootOwner.address, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + // try to register a subdomain as admin - subdomain = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: admin, @@ -367,7 +388,7 @@ describe.only("ZNSSubRegistrar", () => { }, }, }); - await subdomain.register(admin); + await subdomain.register(); // check that the domain was registered const owner = await zns.registry.getDomainOwner(subdomain.hash); @@ -379,14 +400,31 @@ describe.only("ZNSSubRegistrar", () => { }); it("should register subdomain with the correct tokenURI assigned to the domain token minted", async () => { - const subHash = await registrationWithSetup({ + const domain = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "sub", - tokenURI: subTokenURI, - fullConfig: { + domainConfig: { + owner: rootOwner, + label: "root1for1sub", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "sub", + parentHash: domain.hash, + tokenOwner: lvl2SubOwner.address, + tokenURI: subTokenURI, distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig({ @@ -402,20 +440,36 @@ describe.only("ZNSSubRegistrar", () => { }, }, }); + await sub.register(); - const tokenId = BigInt(subHash).toString(); + const tokenId = BigInt(sub.hash).toString(); const tokenURI = await zns.domainToken.tokenURI(tokenId); expect(tokenURI).to.eq(subTokenURI); }); it("Can register a subdomain with characters [a-z0-9-]", async () => { - const alphaNumeric = "0x0dwidler0x0"; + const domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "root555", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); - subdomain = new Domain({ + const subdomain = new Domain({ zns, domainConfig: { owner: lvl2SubOwner, - label: alphaNumeric, + label: "0x0dwidler0x0", // valid characters parentHash: domain.hash, tokenOwner: lvl2SubOwner.address, tokenURI: subTokenURI, @@ -431,21 +485,45 @@ describe.only("ZNSSubRegistrar", () => { }); it("should register a subdomain with token assigned to a different address if provided", async () => { - await defaultSubdomainRegistration({ - user: lvl2SubOwner, + const domain = new Domain({ zns, - parentHash: domain.hash, - subdomainLabel: "subbbb", - tokenOwner: zeroVault.address, // <-- + domainConfig: { + owner: rootOwner, + label: "root1diff1address", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, }); + await domain.register(); - const subHash = await zns.subRegistrar.hashWithParent(domain.hash, "subbbb"); + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "sub1diff1address", + parentHash: domain.hash, + tokenOwner: lvl3SubOwner.address, // different address + tokenURI: subTokenURI, + distrConfig: distrConfigEmpty, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + }); + await subdomain.register(); // check owners of hash and token - const ownerFromReg = await zns.registry.getDomainOwner(subHash); + const ownerFromReg = await zns.registry.getDomainOwner(subdomain.hash); expect(ownerFromReg).to.eq(lvl2SubOwner.address); - const ownerFromToken = await zns.domainToken.ownerOf(subHash); - expect(ownerFromToken).to.eq(zeroVault.address); + const ownerFromToken = await zns.domainToken.ownerOf(subdomain.hash); + expect(ownerFromToken).to.eq(lvl3SubOwner.address); }); it("Fails for a subdomain that uses any invalid characters", async () => { @@ -454,88 +532,80 @@ describe.only("ZNSSubRegistrar", () => { const nameC = "!%$#^*?!#👍3^29"; const nameD = "wo.rld"; - await expect( - defaultSubdomainRegistration( - { - user: lvl2SubOwner, - zns, - parentHash: domain.hash, - subdomainLabel: nameA, - domainContent: lvl2SubOwner.address, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - } - )).to.be.revertedWithCustomError(zns.curvePricer, INVALID_LABEL_ERR); - - await expect( - defaultSubdomainRegistration( - { - user: lvl2SubOwner, - zns, - parentHash: domain.hash, - subdomainLabel: nameB, - domainContent: lvl2SubOwner.address, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - } - )).to.be.revertedWithCustomError(zns.curvePricer, INVALID_LABEL_ERR); + const domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "rootin", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); - await expect( - defaultSubdomainRegistration( - { - user: lvl2SubOwner, - zns, + for (const name of [nameA, nameB, nameC, nameD]) { + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: name, parentHash: domain.hash, - subdomainLabel: nameC, - domainContent: lvl2SubOwner.address, + tokenOwner: lvl2SubOwner.address, tokenURI: subTokenURI, distrConfig: distrConfigEmpty, - } - )).to.be.revertedWithCustomError(zns.curvePricer, INVALID_LABEL_ERR); + paymentConfig: paymentConfigEmpty, + }, + }); - await expect( - defaultSubdomainRegistration( - { - user: lvl2SubOwner, - zns, - parentHash: domain.hash, - subdomainLabel: nameD, - domainContent: lvl2SubOwner.address, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - } - )).to.be.revertedWithCustomError(zns.curvePricer, INVALID_LABEL_ERR); + await expect( + subdomain.register() + ).to.be.revertedWithCustomError(zns.curvePricer, INVALID_LABEL_ERR); + } }); it("should revert when trying to register a subdomain under a non-existent parent", async () => { - // check that 0x0 hash can NOT be passed as parentHash - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ + const domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "rootnonexistent", parentHash: ethers.ZeroHash, - label: "sub", - domainAddress: lvl2SubOwner.address, - tokenOwner: ethers.ZeroAddress, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + + await domain.register(); + const nonExistentHash = domain.hash; + await domain.revoke(); + + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "subnonexistent", + parentHash: nonExistentHash, + tokenOwner: lvl2SubOwner.address, tokenURI: subTokenURI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - DISTRIBUTION_LOCKED_NOT_EXIST_ERR - ); + }, + }); - // check that a random non-existent hash can NOT be passed as parentHash - const randomHash = ethers.keccak256(ethers.toUtf8Bytes("random")); + // check that this hash can NOT be passed as parentHash await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ - parentHash: randomHash, - label: "sub", - domainAddress: lvl2SubOwner.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - paymentConfig: paymentConfigEmpty, - }) + subdomain.register(lvl2SubOwner) ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -543,14 +613,31 @@ describe.only("ZNSSubRegistrar", () => { }); it("should register subdomain with a single char label", async () => { - const subHash = await registrationWithSetup({ + const domain = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "a", - tokenURI: subTokenURI, - fullConfig: { + domainConfig: { + owner: rootOwner, + label: "root96115691", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "a", + parentHash: domain.hash, + tokenOwner: lvl2SubOwner.address, + tokenURI: subTokenURI, distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig({ @@ -566,35 +653,57 @@ describe.only("ZNSSubRegistrar", () => { }, }, }); + await subdomain.register(); - const tokenId = BigInt(subHash).toString(); + const tokenId = BigInt(subdomain.hash).toString(); const tokenURI = await zns.domainToken.tokenURI(tokenId); expect(tokenURI).to.eq(subTokenURI); // check registry - const dataFromReg = await zns.registry.getDomainRecord(subHash); + const dataFromReg = await zns.registry.getDomainRecord(subdomain.hash); expect(dataFromReg.owner).to.eq(lvl2SubOwner.address); expect(dataFromReg.resolver).to.eq(await zns.addressResolver.getAddress()); }); // ! this value can change based on the block gas limit ! it("should register subdomain with a label length of 100000 chars [ @skip-on-coverage ]", async () => { - const subHash = await registrationWithSetup({ + const domain = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "a".repeat(100000), - tokenURI: subTokenURI, - fullConfig: FULL_DISTR_CONFIG_EMPTY, + domainConfig: { + owner: lvl2SubOwner, + label: "root345678", + parentHash: ethers.ZeroHash, + tokenOwner: lvl2SubOwner.address, + tokenURI: subTokenURI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + }); + await domain.register(); + + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "a".repeat(100000), + parentHash: domain.hash, + tokenOwner: lvl2SubOwner.address, + tokenURI: subTokenURI, + distrConfig: FULL_DISTR_CONFIG_EMPTY.distrConfig, + paymentConfig: FULL_DISTR_CONFIG_EMPTY.paymentConfig, + }, }); + await subdomain.register(); - const tokenId = BigInt(subHash).toString(); + const tokenId = BigInt(subdomain.hash).toString(); const tokenURI = await zns.domainToken.tokenURI(tokenId); expect(tokenURI).to.eq(subTokenURI); // check registry - const dataFromReg = await zns.registry.getDomainRecord(subHash); + const dataFromReg = await zns.registry.getDomainRecord(subdomain.hash); expect(dataFromReg.owner).to.eq(lvl2SubOwner.address); expect(dataFromReg.resolver).to.eq(await zns.addressResolver.getAddress()); }); diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index aeb8c68b6..dc6108392 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -119,6 +119,8 @@ export default class Domain { domainAddress, } = this; + const signer = !executor ? owner : executor; + if (!distrConfig.priceConfig) { distrConfig.priceConfig = encodePriceConfig(this.priceConfig); } @@ -126,10 +128,10 @@ export default class Domain { let txPromise : ContractTransactionResponse; // mint and approve strict amount of tokens for domain registration - await this.mintAndApproveForDomain(executor ? executor : owner); + await this.mintAndApproveForDomain(signer); if (this.isRoot) { - txPromise = await zns.rootRegistrar.connect(executor ? executor : owner).registerRootDomain({ + txPromise = await zns.rootRegistrar.connect(signer).registerRootDomain({ name: label, domainAddress: hre.ethers.isAddress(domainAddress) ? domainAddress : owner.address, tokenOwner, @@ -138,7 +140,7 @@ export default class Domain { paymentConfig, }); } else { - txPromise = await zns.subRegistrar.connect(executor ? executor : owner).registerSubdomain({ + txPromise = await zns.subRegistrar.connect(signer).registerSubdomain({ parentHash, label, domainAddress: hre.ethers.isAddress(domainAddress) ? domainAddress : owner.address, @@ -149,7 +151,7 @@ export default class Domain { }); } - this.hash = await this.getDomainHashFromEvent(executor ? executor : owner); + this.hash = await this.getDomainHashFromEvent(signer); return txPromise; } From 5f08a2b04583aeb8eb66c7f94d7252fdec59c23e Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Wed, 6 Aug 2025 17:01:49 -0700 Subject: [PATCH 04/26] Test fixes. Corrected approval for a domain in the Domain class. --- test/ZNSSubRegistrar.test.ts | 125 +++++++++++++++++++++++---------- test/helpers/register-setup.ts | 6 +- 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 1fc59d44b..aa9cd7588 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -709,6 +709,23 @@ describe.only("ZNSSubRegistrar", () => { }); it("should revert when user has insufficient funds", async () => { + const domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "rootinsufficientfunds", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + const label = "subinsufficientfunds"; const { expectedPrice } = getPriceObject(label, rootPriceConfig); const userBalanceBefore = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -738,6 +755,23 @@ describe.only("ZNSSubRegistrar", () => { }); it("should revert when user has insufficient allowance", async () => { + const domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "rootinsufficientallowance", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + const label = "subinsufficientallowance"; const { expectedPrice } = getPriceObject(label, rootPriceConfig); @@ -762,12 +796,14 @@ describe.only("ZNSSubRegistrar", () => { it("should revert on payment when parent's beneficiary has not yet been set and when stakeFee is > 0", async () => { // register a new parent with direct payment and no payment config - const parentHash1 = await registrationWithSetup({ + const domain = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - domainLabel: "parentnoconfigdirect", - fullConfig: { + domainConfig: { + owner: rootOwner, + label: "parentnoconfigdirect", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: subTokenURI, distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig(rootPriceConfig), @@ -777,17 +813,20 @@ describe.only("ZNSSubRegistrar", () => { paymentConfig: paymentConfigEmpty, }, }); + await domain.register(); // set the token address - await zns.treasury.connect(rootOwner).setPaymentToken(parentHash1, await zns.meowToken.getAddress()); + await zns.treasury.connect(rootOwner).setPaymentToken(domain.hash, await zns.meowToken.getAddress()); // register a new parent with stake payment and no payment config - const parentHash2 = await registrationWithSetup({ + const domain2 = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - domainLabel: "parentnoconfigstake", - fullConfig: { + domainConfig: { + owner: rootOwner, + label: "parentnoconfigstake", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: subTokenURI, distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, @@ -797,53 +836,67 @@ describe.only("ZNSSubRegistrar", () => { paymentConfig: paymentConfigEmpty, }, }); + await domain2.register(); // set the token address - await zns.treasury.connect(rootOwner).setPaymentToken(parentHash2, await zns.meowToken.getAddress()); + await zns.treasury.connect(rootOwner).setPaymentToken(domain2.hash, await zns.meowToken.getAddress()); // register subdomains under new parents - await expect( - registrationWithSetup({ - zns, + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "sub1", + parentHash: domain.hash, tokenOwner: lvl2SubOwner.address, - user: lvl2SubOwner, - parentHash: parentHash1, - domainLabel: "sub1", - }) - ).to.be.revertedWithCustomError(zns.treasury, NO_BENEFICIARY_ERR); + tokenURI: subTokenURI, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: encodePriceConfig(rootPriceConfig), + accessType: AccessType.OPEN, + paymentType: PaymentType.STAKE, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + }); await expect( - registrationWithSetup({ - zns, + subdomain.register() + ).to.be.revertedWithCustomError(zns.treasury, NO_BENEFICIARY_ERR); + + const subdomain2 = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, + label: "sub2", + parentHash: domain2.hash, tokenOwner: lvl2SubOwner.address, - user: lvl2SubOwner, - parentHash: parentHash2, - domainLabel: "sub2", - }) + }, + }); + + await expect( + subdomain2.register() ).to.be.revertedWithCustomError(zns.treasury, NO_BENEFICIARY_ERR); // change stakeFee to 0 - const currDistrConfig = await zns.subRegistrar.distrConfigs(parentHash2); + const currDistrConfig = await zns.subRegistrar.distrConfigs(domain2.hash); const decodedConfig = decodePriceConfig(currDistrConfig.priceConfig); decodedConfig.feePercentage = BigInt(0); await zns.subRegistrar.connect(rootOwner).setPricerDataForDomain( - parentHash2, + domain2.hash, encodePriceConfig(decodedConfig), currDistrConfig.pricerContract ); // try register a subdomain again - const subHash = await registrationWithSetup({ - zns, - tokenOwner: lvl2SubOwner.address, - user: lvl2SubOwner, - parentHash: parentHash2, - domainLabel: "sub2", - }); + await subdomain2.register(); - await zns.registry.exists(subHash); + await zns.registry.exists(subdomain2.hash); }); }); diff --git a/test/helpers/register-setup.ts b/test/helpers/register-setup.ts index 81528479d..182e856b3 100644 --- a/test/helpers/register-setup.ts +++ b/test/helpers/register-setup.ts @@ -89,11 +89,7 @@ export const fundApprove = async ({ await tokenContract.connect(user).mint(user.address, toMint); } - const allowance = await tokenContract.allowance(user.address, await zns.treasury.getAddress()); - if (allowance < totalPrice) { - const toApprove = totalPrice - allowance; - return tokenContract.connect(user).approve(await zns.treasury.getAddress(), toApprove); - } + return tokenContract.connect(user).approve(await zns.treasury.getAddress(), totalPrice); }; /** From 233748d7d5c4880ea3bd12a71dc81b0ae62e05f7 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Thu, 7 Aug 2025 16:02:24 -0700 Subject: [PATCH 05/26] More registration fixes. --- test/ZNSSubRegistrar.test.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index aa9cd7588..3c5b4e18b 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -901,6 +901,27 @@ describe.only("ZNSSubRegistrar", () => { }); describe("Bulk Subdomain Registration", () => { + let domain : Domain; + + before(async () => { + domain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "root1bulk", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await domain.register(); + }); + it("Should #registerSubdomainBulk and the event must be triggered", async () => { const registrations : Array = []; @@ -2096,6 +2117,8 @@ describe.only("ZNSSubRegistrar", () => { let token13 : CustomDecimalTokenMock; let token18 : CustomDecimalTokenMock; + let domain : Domain; + const decimalValues = { two: BigInt(2), five: BigInt(5), @@ -4355,6 +4378,8 @@ describe.only("ZNSSubRegistrar", () => { describe("UUPS", () => { let fixedPrice : bigint; + let domain : Domain; + beforeEach(async () => { [ deployer, From 3ddc55dd2ff22782427c22639f087ad6b6e45225 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 12 Aug 2025 15:38:22 -0700 Subject: [PATCH 06/26] Done with all bulk registration tests. Started "Operations with domain paths" --- test/ZNSSubRegistrar.test.ts | 473 +++++++++++++++++----------------- test/helpers/ac.ts | 102 ++++++++ test/helpers/domain/domain.ts | 37 ++- 3 files changed, 368 insertions(+), 244 deletions(-) create mode 100644 test/helpers/ac.ts diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 3c5b4e18b..d01a21cf4 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -62,6 +62,7 @@ import { ICurvePriceConfig, IFixedPriceConfig } from "../src/deploy/missions/typ import { IZNSContracts } from "../src/deploy/campaign/types"; import Domain from "./helpers/domain/domain"; import { ZeroHash } from "ethers"; +import { IFullDomainConfig } from "./helpers/domain/types"; describe.only("ZNSSubRegistrar", () => { @@ -1261,9 +1262,15 @@ describe.only("ZNSSubRegistrar", () => { }); }); - describe("Operations with domain paths", () => { - let domainConfigs : Array; - let regResults : Array; + describe.only("Operations with domain paths", () => { + let domainConfigs : Array; + + interface RegRes { + domainHash : string; + label : string; + owner : SignerWithAddress; + } + const regResults : Array = []; const fixedPrice = ethers.parseEther("1375.612"); const fixedFeePercentage = BigInt(200); @@ -1273,6 +1280,50 @@ describe.only("ZNSSubRegistrar", () => { feePercentage: fixedFeePercentage, }); + const regValidateAndSaveHashes = async ({ + configs, + extrArray, + } : { + configs : Array; + extrArray ?: Array; + // TODO dom: idk, am I right here? + }) : Promise> => { + const resultArray = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < configs.length; i++) { + const config = configs[i]; + + // pass parentHash as a hash of the previous domain + // the first domain is root + if (i !== 0) { + config.parentHash = configs[i - 1].parentHash; + } + + // register each domain + const domain = new Domain({ + zns, + domainConfig: config, + }); + await domain.registerAndValidateDomain(); + + const domObj = { + domainHash: domain.hash, + label: config.label, + owner: config.owner, + }; + + if (extrArray) { + extrArray.push(domObj); + } else { + resultArray.push(domObj); + } + } + + if (resultArray.length > 0) { + return resultArray; + } + }; + before(async () => { [ deployer, @@ -1316,287 +1367,246 @@ describe.only("ZNSSubRegistrar", () => { domainConfigs = [ { - user: rootOwner, - domainLabel: "root", - fullConfig: { - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: fixedPriceConfigBytes, - paymentType: PaymentType.DIRECT, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: rootOwner.address, - }, + owner: rootOwner, + label: "root", + tokenOwner: rootOwner.address, + parentHash: ethers.ZeroHash, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: fixedPriceConfigBytes, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, }, + domainAddress: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, }, { - user: lvl2SubOwner, - domainLabel: "lvltwo", - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - paymentType: PaymentType.STAKE, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: lvl2SubOwner.address, - }, + owner: lvl2SubOwner, + label: "lvltwo", + tokenOwner: lvl2SubOwner.address, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.STAKE, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, }, + domainAddress: lvl2SubOwner.address, + tokenURI: subTokenURI, }, { - user: lvl3SubOwner, - domainLabel: "lvlthree", - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - paymentType: PaymentType.DIRECT, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: lvl3SubOwner.address, - }, + owner: lvl3SubOwner, + label: "lvlthree", + tokenOwner: lvl3SubOwner.address, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl3SubOwner.address, + }, + domainAddress: lvl3SubOwner.address, + tokenURI: subTokenURI, }, { - user: lvl4SubOwner, - domainLabel: "lvlfour", - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - paymentType: PaymentType.STAKE, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: lvl4SubOwner.address, - }, + owner: lvl4SubOwner, + label: "lvlfour", + tokenOwner: lvl4SubOwner.address, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.STAKE, + accessType: AccessType.OPEN, }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl4SubOwner.address, + }, + domainAddress: lvl4SubOwner.address, + tokenURI: subTokenURI, }, { - user: lvl5SubOwner, - domainLabel: "lvlfive", - fullConfig: { - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: fixedPriceConfigBytes, - paymentType: PaymentType.DIRECT, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: lvl5SubOwner.address, - }, + owner: lvl5SubOwner, + label: "lvlfive", + tokenOwner: lvl5SubOwner.address, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: fixedPriceConfigBytes, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl5SubOwner.address, + }, + domainAddress: lvl5SubOwner.address, + tokenURI: subTokenURI, }, { - user: lvl6SubOwner, - domainLabel: "lvlsix", - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - paymentType: PaymentType.STAKE, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: lvl6SubOwner.address, - }, + owner: lvl6SubOwner, + label: "lvlsix", + tokenOwner: lvl6SubOwner.address, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.STAKE, + accessType: AccessType.OPEN, }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl6SubOwner.address, + }, + domainAddress: lvl6SubOwner.address, + tokenURI: subTokenURI, }, ]; - - regResults = await registerDomainPath({ - zns, - domainConfigs, - zeroVaultAddress: zeroVault.address, - }); - - assert.equal(regResults.length, domainConfigs.length); }); it("should register a path of 6 domains with different configs", async () => { - await validatePathRegistration({ - zns, - domainConfigs, - regResults, + await regValidateAndSaveHashes({ + configs: domainConfigs, + extrArray: regResults, }); }); it("should be able to register multiple domains under multiple levels for the same owner", async () => { - const configs : Array = [ + domainConfigs = [ { - user: multiOwner, - domainLabel: "multiownerdomone", + owner: multiOwner, + label: "multiownerdomone", tokenOwner: multiOwner.address, - fullConfig: { - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: BigInt(0) }), - accessType: AccessType.OPEN, - paymentType: PaymentType.DIRECT, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: multiOwner.address, - }, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: BigInt(0) }), + accessType: AccessType.OPEN, + paymentType: PaymentType.DIRECT, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: multiOwner.address, }, }, { - user: multiOwner, + owner: multiOwner, + label: "multiownerdomtwo", tokenOwner: multiOwner.address, - domainLabel: "multiownerdomtwo", parentHash: regResults[0].domainHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - accessType: AccessType.LOCKED, - paymentType: PaymentType.STAKE, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: zeroVault.address, - }, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + accessType: AccessType.LOCKED, + paymentType: PaymentType.STAKE, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: zeroVault.address, }, }, { - user: multiOwner, + owner: multiOwner, + label: "multiownerdomthree", tokenOwner: multiOwner.address, - domainLabel: "multiownerdomthree", parentHash: regResults[1].domainHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - accessType: AccessType.MINTLIST, - paymentType: PaymentType.DIRECT, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: multiOwner.address, - }, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + accessType: AccessType.MINTLIST, + paymentType: PaymentType.DIRECT, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: multiOwner.address, }, }, { - user: multiOwner, + owner: multiOwner, + label: "multiownerdomfour", tokenOwner: multiOwner.address, - domainLabel: "multiownerdomfour", parentHash: regResults[2].domainHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), - accessType: AccessType.OPEN, - paymentType: PaymentType.STAKE, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: zeroVault.address, - }, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), + accessType: AccessType.OPEN, + paymentType: PaymentType.STAKE, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: zeroVault.address, }, }, { - user: multiOwner, + owner: multiOwner, + label: "multiownerdomfive", tokenOwner: multiOwner.address, - domainLabel: "multiownerdomfive", parentHash: regResults[3].domainHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - accessType: AccessType.OPEN, - paymentType: PaymentType.DIRECT, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: multiOwner.address, - }, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + accessType: AccessType.OPEN, + paymentType: PaymentType.DIRECT, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: multiOwner.address, }, }, { - user: multiOwner, + owner: multiOwner, + label: "multiownerdomsix", tokenOwner: multiOwner.address, - domainLabel: "multiownerdomsix", parentHash: regResults[4].domainHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - accessType: AccessType.OPEN, - paymentType: PaymentType.STAKE, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: zeroVault.address, - }, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + accessType: AccessType.OPEN, + paymentType: PaymentType.STAKE, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: zeroVault.address, }, }, { - user: multiOwner, + owner: multiOwner, + label: "multiownerdomseven", tokenOwner: multiOwner.address, - domainLabel: "multiownerdomseven", parentHash: regResults[5].domainHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), - accessType: AccessType.OPEN, - paymentType: PaymentType.DIRECT, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: multiOwner.address, - }, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), + accessType: AccessType.OPEN, + paymentType: PaymentType.DIRECT, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: multiOwner.address, }, }, ]; - // prep - await zns.meowToken.connect(multiOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - // register - const domainHashes = await configs.reduce( - async ( - acc : Promise>, - { - user, - tokenOwner, - parentHash, - domainLabel, - fullConfig, - }) : Promise> => { - const newAcc = await acc; - - const newHash = await registrationWithSetup({ - zns, - user, - tokenOwner, - parentHash, - domainLabel, - fullConfig, - }); - - return [...newAcc, newHash]; - }, Promise.resolve([]) - ); + const regResultsLocal = await regValidateAndSaveHashes({ + configs: domainConfigs, + }) as Array; // check - await domainHashes.reduce( + await regResultsLocal.reduce( async (acc, domainHash, idx) => { await acc; - const { owner, resolver } = await zns.registry.getDomainRecord(domainHash); + const { owner, resolver } = await zns.registry.getDomainRecord(regResultsLocal[idx].domainHash); expect(owner).to.eq(multiOwner.address); expect(resolver).to.eq(await zns.addressResolver.getAddress()); - const tokenId = BigInt(domainHash).toString(); + const tokenId = BigInt(regResultsLocal[idx].domainHash).toString(); const tokenOwner = await zns.domainToken.ownerOf(tokenId); expect(tokenOwner).to.eq(multiOwner.address); @@ -1604,19 +1614,19 @@ describe.only("ZNSSubRegistrar", () => { pricerContract, accessType, paymentType, - } = await zns.subRegistrar.distrConfigs(domainHash); - expect(pricerContract).to.eq(configs[idx].fullConfig.distrConfig.pricerContract); - expect(accessType).to.eq(configs[idx].fullConfig.distrConfig.accessType); - expect(paymentType).to.eq(configs[idx].fullConfig.distrConfig.paymentType); + } = await zns.subRegistrar.distrConfigs(regResultsLocal[idx].domainHash); + expect(pricerContract).to.eq(domainConfigs[idx].distrConfig?.pricerContract); + expect(accessType).to.eq(domainConfigs[idx].distrConfig?.accessType); + expect(paymentType).to.eq(domainConfigs[idx].distrConfig?.paymentType); const { token, beneficiary, - } = await zns.treasury.paymentConfigs(domainHash); - expect(token).to.eq(configs[idx].fullConfig.paymentConfig.token); - expect(beneficiary).to.eq(configs[idx].fullConfig.paymentConfig.beneficiary); + } = await zns.treasury.paymentConfigs(regResultsLocal[idx].domainHash); + expect(token).to.eq(domainConfigs[idx].paymentConfig?.token); + expect(beneficiary).to.eq(domainConfigs[idx].paymentConfig?.beneficiary); - const domainAddress = await zns.addressResolver.resolveDomainAddress(domainHash); + const domainAddress = await zns.addressResolver.resolveDomainAddress(regResultsLocal[idx].domainHash); expect(domainAddress).to.eq(multiOwner.address); }, Promise.resolve() ); @@ -1624,6 +1634,7 @@ describe.only("ZNSSubRegistrar", () => { it("should revoke lvl 6 domain without refund, lock registration and remove mintlist", async () => { const domainHash = regResults[5].domainHash; + const howMuch = await zns.treasury.stakedForDomain(domainHash); // add to mintlist await zns.subRegistrar.connect(lvl6SubOwner).updateMintlistForDomain( @@ -1704,7 +1715,7 @@ describe.only("ZNSSubRegistrar", () => { const parentBalAfter = await zns.meowToken.balanceOf(lvl4SubOwner.address); const paymentContractBalAfter = await zns.meowToken.balanceOf(await zns.treasury.getAddress()); - const { expectedPrice } = getPriceObject(domainConfigs[4].domainLabel); + const { expectedPrice } = getPriceObject(domainConfigs[4].label); expect( userBalAfter - userBalanceBefore @@ -1832,21 +1843,21 @@ describe.only("ZNSSubRegistrar", () => { // make sure all parent's distribution configs still exist const parentDistrConfig = await zns.subRegistrar.distrConfigs(lvl2Hash); const parentPaymentConfig = await zns.treasury.paymentConfigs(lvl2Hash); - expect(parentDistrConfig.pricerContract).to.eq(domainConfigs[1].fullConfig.distrConfig.pricerContract); + expect(parentDistrConfig.pricerContract).to.eq(domainConfigs[1].distrConfig?.pricerContract); expect( parentDistrConfig.paymentType ).to.eq( - domainConfigs[1].fullConfig.distrConfig.paymentType + domainConfigs[1].distrConfig?.paymentType ); expect( parentPaymentConfig.token ).to.eq( - domainConfigs[1].fullConfig.paymentConfig.token + domainConfigs[1].paymentConfig?.token ); expect( parentPaymentConfig.beneficiary ).to.eq( - domainConfigs[1].fullConfig.paymentConfig.beneficiary + domainConfigs[1].paymentConfig?.beneficiary ); expect(parentDistrConfig.pricerContract).to.eq(await zns.curvePricer.getAddress()); @@ -1854,7 +1865,7 @@ describe.only("ZNSSubRegistrar", () => { // check a couple of fields from price config const distrConfig = await zns.subRegistrar.distrConfigs(lvl2Hash); const priceConfig = decodePriceConfig(distrConfig.priceConfig); - const priceConfigFromDomain = decodePriceConfig(domainConfigs[1].fullConfig.distrConfig.priceConfig); + const priceConfigFromDomain = decodePriceConfig(domainConfigs[1].distrConfig.priceConfig); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if ("maxPrice" in priceConfigFromDomain) { @@ -1863,7 +1874,7 @@ describe.only("ZNSSubRegistrar", () => { // make sure the child's stake is still there const { amount: childStakedAmt } = await zns.treasury.stakedForDomain(lvl3Hash); - const { expectedPrice } = getPriceObject(domainConfigs[2].domainLabel); + const { expectedPrice } = getPriceObject(domainConfigs[2].label); expect(childStakedAmt).to.eq(expectedPrice); diff --git a/test/helpers/ac.ts b/test/helpers/ac.ts new file mode 100644 index 000000000..4af55fc49 --- /dev/null +++ b/test/helpers/ac.ts @@ -0,0 +1,102 @@ +import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { + IZNSContracts, + ZNSContract, +} from "../../src/deploy/campaign/types"; + + +export const setACTests = ({ + zns, + contract, +} : { + zns : IZNSContracts; + contract : ZNSContract; +}) => { + let deployer : SignerWithAddress; + let user : SignerWithAddress; + let admin : SignerWithAddress; + + describe("#setAccessController", () => { + beforeEach(async () => { + [deployer, user, admin] = await ethers.getSigners(); + }); + + it("should allow ADMIN to set a valid AccessController", async () => { + await zns.rootRegistrar.connect(deployer).setAccessController(zns.accessController.target); + + const currentAccessController = await zns.rootRegistrar.getAccessController(); + + expect(currentAccessController).to.equal(zns.accessController.target); + }); + + it("should allow re-setting the AccessController to another valid contract", async () => { + expect( + await zns.rootRegistrar.getAccessController() + ).to.equal( + zns.accessController.target + ); + + const ZNSAccessControllerFactory = await hre.ethers.getContractFactory("ZNSAccessController", deployer); + const newAccessController = await ZNSAccessControllerFactory.deploy( + [deployer.address], + [deployer.address] + ); + + // then change the AccessController + await zns.rootRegistrar.connect(deployer).setAccessController(newAccessController.target); + + expect( + await zns.rootRegistrar.getAccessController() + ).to.equal( + newAccessController.target + ); + }); + + it("should emit AccessControllerSet event when setting a valid AccessController", async () => { + await expect( + zns.rootRegistrar.connect(deployer).setAccessController(zns.accessController.target) + ).to.emit( + zns.rootRegistrar, + "AccessControllerSet" + ).withArgs(zns.accessController.target); + }); + + it("should revert when a non-ADMIN tries to set AccessController", async () => { + await expect( + zns.rootRegistrar.connect(user).setAccessController(zns.accessController.target) + ).to.be.revertedWithCustomError( + zns.rootRegistrar, + AC_UNAUTHORIZED_ERR + ).withArgs(user.address, ADMIN_ROLE); + }); + + it("should revert when setting an AccessController as EOA address", async () => { + await expect( + zns.rootRegistrar.connect(deployer).setAccessController(user.address) + ).to.be.revertedWithCustomError( + zns.rootRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(user.address); + }); + + it("should revert when setting an AccessController as another non-AC contract address", async () => { + await expect( + zns.rootRegistrar.connect(deployer).setAccessController(zns.rootRegistrar.target) + ).to.be.revertedWithCustomError( + zns.rootRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(zns.rootRegistrar.target); + }); + + it("should revert when setting a zero address as AccessController", async () => { + await expect( + zns.rootRegistrar.connect(admin).setAccessController(ethers.ZeroAddress) + ).to.be.revertedWithCustomError( + zns.rootRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(ethers.ZeroAddress); + }); + }); +}; \ No newline at end of file diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index dc6108392..772a9cace 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -48,15 +48,19 @@ export default class Domain { this.tokenOwner = domainConfig.tokenOwner || hre.ethers.ZeroAddress; this.distrConfig = domainConfig.distrConfig || distrConfigEmpty; - switch (this.distrConfig.pricerContract) { - case zns.curvePricer.target: - this.priceConfig = curvePriceConfigEmpty; - break; - case zns.fixedPricer.target: - this.priceConfig = fixedPriceConfigEmpty; - break; - default: - this.priceConfig = {} as ICurvePriceConfig | IFixedPriceConfig; + if (!domainConfig.priceConfig) { + switch (this.distrConfig.pricerContract) { + case zns.curvePricer.target: + this.priceConfig = curvePriceConfigEmpty; + break; + case zns.fixedPricer.target: + this.priceConfig = fixedPriceConfigEmpty; + break; + default: + this.priceConfig = {} as ICurvePriceConfig | IFixedPriceConfig; + } + } else { + this.priceConfig = domainConfig.priceConfig; } this.paymentConfig = domainConfig.paymentConfig || paymentConfigEmpty; @@ -251,11 +255,10 @@ export default class Domain { // ------------------------------------------------------ // VALIDATION // ------------------------------------------------------ - async registerAndValidateDomain ( + async validate ( + txPromise : ContractTransactionResponse, executor ?: SignerWithAddress - ) : Promise { - const txPromise = await this.register(executor ? executor : this.owner); - + ) { // check domain existence with event await expect(txPromise) .to.emit( @@ -286,4 +289,12 @@ export default class Domain { await this.zns.domainToken.tokenURI(this.hash) ).to.equal(this.tokenURI); } + + async registerAndValidateDomain ( + executor ?: SignerWithAddress + ) : Promise { + const txPromise = await this.register(executor ? executor : this.owner); + + await this.validate(txPromise, executor); + } } From 540d2dc32e78f2f1cdb341b237d0f47acbc1d1a5 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 19 Aug 2025 15:23:27 -0700 Subject: [PATCH 07/26] Fails fixes for first tests in "Operations with domain paths" --- test/ZNSSubRegistrar.test.ts | 182 +++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 71 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index d01a21cf4..7b17585c7 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -1283,20 +1283,27 @@ describe.only("ZNSSubRegistrar", () => { const regValidateAndSaveHashes = async ({ configs, extrArray, + executor, } : { configs : Array; extrArray ?: Array; + executor ?: SignerWithAddress; // TODO dom: idk, am I right here? }) : Promise> => { const resultArray = []; + let domObj; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < configs.length; i++) { const config = configs[i]; // pass parentHash as a hash of the previous domain // the first domain is root - if (i !== 0) { - config.parentHash = configs[i - 1].parentHash; + if (!config.parentHash) { + if (i !== 0) { + config.parentHash = domObj?.domainHash; + } else { + config.parentHash = ethers.ZeroHash; + } } // register each domain @@ -1304,9 +1311,9 @@ describe.only("ZNSSubRegistrar", () => { zns, domainConfig: config, }); - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain(executor ? executor : config.owner); - const domObj = { + domObj = { domainHash: domain.hash, label: config.label, owner: config.owner, @@ -1477,6 +1484,8 @@ describe.only("ZNSSubRegistrar", () => { configs: domainConfigs, extrArray: regResults, }); + + assert.equal(regResults.length, domainConfigs.length); }); it("should be able to register multiple domains under multiple levels for the same owner", async () => { @@ -1926,16 +1935,39 @@ describe.only("ZNSSubRegistrar", () => { const exists = await zns.registry.exists(lvl2Hash); if (!exists) { - const newHash = await registrationWithSetup({ + const subdomain = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash, - domainLabel: domainConfigs[1].domainLabel, - fullConfig: domainConfigs[1].fullConfig, + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash, + label: domainConfigs[1].label, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.STAKE, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + // domainConfigs[1], + // { + // owner: lvl2SubOwner, + // label: domainConfigs[1].label, + // tokenOwner: lvl2SubOwner.address, + // parentHash, + // distrConfig: domainConfigs[1].distrConfig, + // paymentConfig: domainConfigs[1].paymentConfig, + // domainAddress: lvl2SubOwner.address, + // tokenURI: subTokenURI, + // }, }); + await subdomain.register(); - expect(newHash).to.eq(lvl2Hash); + expect(subdomain.hash).to.eq(lvl2Hash); } // revoke subdomain @@ -1943,37 +1975,28 @@ describe.only("ZNSSubRegistrar", () => { lvl2Hash, ); - const newConfig = [ - { - user: branchLvl1Owner, - domainLabel: "lvltwonew", + const subdomain = new Domain({ + zns, + domainConfig: { + owner: branchLvl1Owner, + label: "lvltwonew", + tokenOwner: branchLvl1Owner.address, parentHash, - fullConfig: { - distrConfig: { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), - paymentType: PaymentType.DIRECT, - accessType: AccessType.OPEN, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: branchLvl1Owner.address, - }, + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: branchLvl1Owner.address, }, + domainAddress: branchLvl1Owner.address, + tokenURI: DEFAULT_TOKEN_URI, }, - ]; - - const newResult = await registerDomainPath({ - zns, - domainConfigs: newConfig, - zeroVaultAddress: zeroVault.address, - }); - - await validatePathRegistration({ - zns, - domainConfigs: newConfig, - regResults: newResult, }); + await subdomain.registerAndValidateDomain(); }); it("should NOT register a child (subdomain) under a parent (root domain) that has been revoked", async () => { @@ -1987,8 +2010,10 @@ describe.only("ZNSSubRegistrar", () => { const exists = await zns.registry.exists(lvl1Hash); assert.ok(!exists); - await expect( - zns.subRegistrar.connect(branchLvl1Owner).registerSubdomain({ + const subdomain = new Domain({ + zns, + domainConfig: { + owner: branchLvl1Owner, parentHash: lvl1Hash, label: "newsubdomain", domainAddress: branchLvl1Owner.address, @@ -1996,21 +2021,21 @@ describe.only("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + await expect( + subdomain.register() ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR ); // register root back for other tests - await registrationWithSetup({ + const domain = new Domain({ zns, - user: rootOwner, - tokenOwner: rootOwner.address, - parentHash: ethers.ZeroHash, - domainLabel: domainConfigs[0].domainLabel, - fullConfig: domainConfigs[0].fullConfig, + domainConfig: domainConfigs[0], }); + await domain.registerAndValidateDomain(); }); it("should NOT register a child (subdomain) under a parent (subdomain) that has been revoked", async () => { @@ -2024,8 +2049,10 @@ describe.only("ZNSSubRegistrar", () => { const exists = await zns.registry.exists(lvl4Hash); assert.ok(!exists); - await expect( - zns.subRegistrar.connect(branchLvl2Owner).registerSubdomain({ + const subdomain = new Domain({ + zns, + domainConfig: { + owner: branchLvl2Owner, parentHash: lvl4Hash, label: "newsubdomain", domainAddress: branchLvl2Owner.address, @@ -2033,7 +2060,11 @@ describe.only("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + subdomain.register(branchLvl2Owner) ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -2043,14 +2074,11 @@ describe.only("ZNSSubRegistrar", () => { // eslint-disable-next-line max-len it("should allow setting a new config and start distributing subdomain when registering a previously revoked parent", async () => { if (!await zns.registry.exists(regResults[1].domainHash)) { - await registrationWithSetup({ + const subdomain = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: regResults[0].domainHash, - domainLabel: domainConfigs[1].domainLabel, - fullConfig: domainConfigs[1].fullConfig, + domainConfig: domainConfigs[1], }); + await subdomain.register(); } // revoke parent @@ -2059,13 +2087,13 @@ describe.only("ZNSSubRegistrar", () => { expect(await zns.registry.exists(regResults[1].domainHash)).to.eq(false); // register again with new owner and config - const newHash = await registrationWithSetup({ + const subdomain = new Domain({ zns, - user: branchLvl1Owner, - tokenOwner: branchLvl1Owner.address, - parentHash: regResults[0].domainHash, - domainLabel: domainConfigs[1].domainLabel, - fullConfig: { + domainConfig: { + owner: branchLvl1Owner, + tokenOwner: branchLvl1Owner.address, + parentHash: regResults[0].domainHash, + label: domainConfigs[1].label, distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig({ @@ -2081,29 +2109,41 @@ describe.only("ZNSSubRegistrar", () => { }, }, }); + await subdomain.registerAndValidateDomain(); - expect(newHash).to.eq(regResults[1].domainHash); + expect(subdomain.hash).to.eq(regResults[1].domainHash); // add new child owner to mintlist await zns.subRegistrar.connect(branchLvl1Owner).updateMintlistForDomain( - newHash, + subdomain.hash, [ branchLvl2Owner.address ], [ true ], ); - const parentOwnerFromReg = await zns.registry.getDomainOwner(newHash); + const parentOwnerFromReg = await zns.registry.getDomainOwner(subdomain.hash); expect(parentOwnerFromReg).to.eq(branchLvl1Owner.address); const childBalBefore = await zns.meowToken.balanceOf(branchLvl2Owner.address); // try register a new child under the new parent - const newChildHash = await registrationWithSetup({ + const newChildHash = new Domain({ zns, - user: branchLvl2Owner, - tokenOwner: branchLvl2Owner.address, - parentHash: newHash, - domainLabel: "newchildddd", - fullConfig: FULL_DISTR_CONFIG_EMPTY, + domainConfig:{ + owner: branchLvl2Owner, + tokenOwner: branchLvl2Owner.address, + parentHash: subdomain.hash, + label: "newchildddd", + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.LOCKED, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: ethers.ZeroAddress, + beneficiary: ethers.ZeroAddress, + }, + }, }); const childBalAfter = await zns.meowToken.balanceOf(branchLvl2Owner.address); From fff89ac7a42d229b19e1b479176e49608a1b37cd Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Thu, 21 Aug 2025 13:35:56 -0700 Subject: [PATCH 08/26] 2nd describe test fixes --- test/ZNSSubRegistrar.test.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 7b17585c7..2393a1c82 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -65,7 +65,7 @@ import { ZeroHash } from "ethers"; import { IFullDomainConfig } from "./helpers/domain/types"; -describe.only("ZNSSubRegistrar", () => { +describe("ZNSSubRegistrar", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -1262,13 +1262,14 @@ describe.only("ZNSSubRegistrar", () => { }); }); - describe.only("Operations with domain paths", () => { + describe("Operations with domain paths", () => { let domainConfigs : Array; interface RegRes { domainHash : string; label : string; owner : SignerWithAddress; + parentHash : string | undefined; } const regResults : Array = []; @@ -1317,6 +1318,7 @@ describe.only("ZNSSubRegistrar", () => { domainHash: domain.hash, label: config.label, owner: config.owner, + parentHash: config.parentHash, }; if (extrArray) { @@ -1489,7 +1491,7 @@ describe.only("ZNSSubRegistrar", () => { }); it("should be able to register multiple domains under multiple levels for the same owner", async () => { - domainConfigs = [ + const configs = [ { owner: multiOwner, label: "multiownerdomone", @@ -1604,7 +1606,7 @@ describe.only("ZNSSubRegistrar", () => { ]; const regResultsLocal = await regValidateAndSaveHashes({ - configs: domainConfigs, + configs, }) as Array; // check @@ -1624,16 +1626,16 @@ describe.only("ZNSSubRegistrar", () => { accessType, paymentType, } = await zns.subRegistrar.distrConfigs(regResultsLocal[idx].domainHash); - expect(pricerContract).to.eq(domainConfigs[idx].distrConfig?.pricerContract); - expect(accessType).to.eq(domainConfigs[idx].distrConfig?.accessType); - expect(paymentType).to.eq(domainConfigs[idx].distrConfig?.paymentType); + expect(pricerContract).to.eq(configs[idx].distrConfig?.pricerContract); + expect(accessType).to.eq(configs[idx].distrConfig?.accessType); + expect(paymentType).to.eq(configs[idx].distrConfig?.paymentType); const { token, beneficiary, } = await zns.treasury.paymentConfigs(regResultsLocal[idx].domainHash); - expect(token).to.eq(domainConfigs[idx].paymentConfig?.token); - expect(beneficiary).to.eq(domainConfigs[idx].paymentConfig?.beneficiary); + expect(token).to.eq(configs[idx].paymentConfig?.token); + expect(beneficiary).to.eq(configs[idx].paymentConfig?.beneficiary); const domainAddress = await zns.addressResolver.resolveDomainAddress(regResultsLocal[idx].domainHash); expect(domainAddress).to.eq(multiOwner.address); @@ -1643,7 +1645,6 @@ describe.only("ZNSSubRegistrar", () => { it("should revoke lvl 6 domain without refund, lock registration and remove mintlist", async () => { const domainHash = regResults[5].domainHash; - const howMuch = await zns.treasury.stakedForDomain(domainHash); // add to mintlist await zns.subRegistrar.connect(lvl6SubOwner).updateMintlistForDomain( @@ -2145,13 +2146,10 @@ describe.only("ZNSSubRegistrar", () => { }, }, }); + await newChildHash.registerAndValidateDomain(branchLvl2Owner); const childBalAfter = await zns.meowToken.balanceOf(branchLvl2Owner.address); - // check that the new child has been registered - const childOwnerFromReg = await zns.registry.getDomainOwner(newChildHash); - expect(childOwnerFromReg).to.eq(branchLvl2Owner.address); - const protocolFee = getStakingOrProtocolFee(fixedPrice); // make sure child payed based on the new parent config From b728da03e465228b1a85bd276ad00d7c60b5c76c Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Thu, 21 Aug 2025 20:20:13 -0700 Subject: [PATCH 09/26] Added a couple of getters from the class and one setter for payment token. --- test/helpers/domain/domain.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 772a9cace..55c42a403 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -200,6 +200,20 @@ export default class Domain { ); } + // ------------------------------------------------------ + // GETTERS + // ------------------------------------------------------ + async getDomainRecord () : Promise<{ + owner : string; + resolver : string; + }> { + return this.zns.registry.getDomainRecord(this.hash); + } + + async getPaymentConfig () : Promise { + return this.zns.treasury.paymentConfigs(this.hash); + } + // ------------------------------------------------------ // SETTERS // ------------------------------------------------------ @@ -252,6 +266,20 @@ export default class Domain { ); } + async setPaymentTokenForDomain ( + tokenAddress : string, + executor ?: SignerWithAddress + ) : Promise { + if (!hre.ethers.isAddress(tokenAddress)) { + throw new Error("Domain Helper: Invalid token address provided"); + } + + return this.zns.treasury.connect(executor ? executor : this.owner).setPaymentToken( + this.hash, + tokenAddress + ); + } + // ------------------------------------------------------ // VALIDATION // ------------------------------------------------------ From cd0398eb7bcac9d7c0a36ffbffb9920811dc69c2 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Thu, 21 Aug 2025 20:21:33 -0700 Subject: [PATCH 10/26] Redundant checks removal in "Single Subdomain Registration" --- test/ZNSSubRegistrar.test.ts | 46 ++++++++++-------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 2393a1c82..955603aef 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -65,7 +65,7 @@ import { ZeroHash } from "ethers"; import { IFullDomainConfig } from "./helpers/domain/types"; -describe("ZNSSubRegistrar", () => { +describe.only("ZNSSubRegistrar", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -173,7 +173,7 @@ describe("ZNSSubRegistrar", () => { }); await subdomain.register(lvl2SubOwner); - const config = await zns.treasury.paymentConfigs(subdomain.hash); + const config = await subdomain.getPaymentConfig(); expect(config.token).to.eq(await zns.meowToken.getAddress()); expect(config.beneficiary).to.eq(lvl2SubOwner.address); }); @@ -212,7 +212,7 @@ describe("ZNSSubRegistrar", () => { }); await subdomain.register(); - const config = await zns.treasury.paymentConfigs(subdomain.hash); + const config = await subdomain.getPaymentConfig(); expect(config.token).to.eq(ethers.ZeroAddress); expect(config.beneficiary).to.eq(ethers.ZeroAddress); }); @@ -389,11 +389,10 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await subdomain.register(); + await subdomain.register(admin); // check that the domain was registered - const owner = await zns.registry.getDomainOwner(subdomain.hash); - expect(owner).to.eq(admin.address); + expect(subdomain.owner).to.eq(admin.address); // unpause the sub registrar for further tests await zns.subRegistrar.connect(admin).unpauseRegistration(); @@ -443,9 +442,7 @@ describe("ZNSSubRegistrar", () => { }); await sub.register(); - const tokenId = BigInt(sub.hash).toString(); - const tokenURI = await zns.domainToken.tokenURI(tokenId); - expect(tokenURI).to.eq(subTokenURI); + expect(sub.tokenURI).to.eq(subTokenURI); }); it("Can register a subdomain with characters [a-z0-9-]", async () => { @@ -481,7 +478,6 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await subdomain.registerAndValidateDomain(); }); @@ -606,7 +602,7 @@ describe("ZNSSubRegistrar", () => { // check that this hash can NOT be passed as parentHash await expect( - subdomain.register(lvl2SubOwner) + subdomain.register() ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -654,16 +650,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await subdomain.register(); - - const tokenId = BigInt(subdomain.hash).toString(); - const tokenURI = await zns.domainToken.tokenURI(tokenId); - expect(tokenURI).to.eq(subTokenURI); - - // check registry - const dataFromReg = await zns.registry.getDomainRecord(subdomain.hash); - expect(dataFromReg.owner).to.eq(lvl2SubOwner.address); - expect(dataFromReg.resolver).to.eq(await zns.addressResolver.getAddress()); + await subdomain.registerAndValidateDomain(); }); // ! this value can change based on the block gas limit ! @@ -697,16 +684,7 @@ describe("ZNSSubRegistrar", () => { paymentConfig: FULL_DISTR_CONFIG_EMPTY.paymentConfig, }, }); - await subdomain.register(); - - const tokenId = BigInt(subdomain.hash).toString(); - const tokenURI = await zns.domainToken.tokenURI(tokenId); - expect(tokenURI).to.eq(subTokenURI); - - // check registry - const dataFromReg = await zns.registry.getDomainRecord(subdomain.hash); - expect(dataFromReg.owner).to.eq(lvl2SubOwner.address); - expect(dataFromReg.resolver).to.eq(await zns.addressResolver.getAddress()); + await subdomain.registerAndValidateDomain(); }); it("should revert when user has insufficient funds", async () => { @@ -838,9 +816,8 @@ describe("ZNSSubRegistrar", () => { }, }); await domain2.register(); - // set the token address - await zns.treasury.connect(rootOwner).setPaymentToken(domain2.hash, await zns.meowToken.getAddress()); + await domain2.setPaymentTokenForDomain(await zns.meowToken.getAddress()); // register subdomains under new parents const subdomain = new Domain({ @@ -888,7 +865,8 @@ describe("ZNSSubRegistrar", () => { decodedConfig.feePercentage = BigInt(0); - await zns.subRegistrar.connect(rootOwner).setPricerDataForDomain( + // TODO dom: start from this + await domain2.setPricerDataForDomain( domain2.hash, encodePriceConfig(decodedConfig), currDistrConfig.pricerContract From 3cbdd97235ef9503faca39c17f3376946bb0d8c5 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Fri, 22 Aug 2025 14:49:01 -0700 Subject: [PATCH 11/26] Added passing parameters by objects in the Domain class --- test/ZNSAddressResolver.test.ts | 5 +- test/ZNSRootRegistrar.test.ts | 53 ++++++++++----- test/ZNSSubRegistrar.test.ts | 13 ++-- test/helpers/domain/domain.ts | 113 +++++++++++++++++++++----------- 4 files changed, 120 insertions(+), 64 deletions(-) diff --git a/test/ZNSAddressResolver.test.ts b/test/ZNSAddressResolver.test.ts index 1aa4e27f1..5172c6c57 100644 --- a/test/ZNSAddressResolver.test.ts +++ b/test/ZNSAddressResolver.test.ts @@ -147,7 +147,10 @@ describe("ZNSAddressResolver", () => { }); it("Should allow operator to setAddress and emit event", async () => { - await domain.setOwnersOperator(operator.address, true); + await domain.setOwnersOperator({ + operator: operator.address, + allowed: true, + }); await expect( zns.addressResolver.connect(operator) diff --git a/test/ZNSRootRegistrar.test.ts b/test/ZNSRootRegistrar.test.ts index f71d07687..89cac61d6 100644 --- a/test/ZNSRootRegistrar.test.ts +++ b/test/ZNSRootRegistrar.test.ts @@ -162,10 +162,10 @@ describe("ZNSRootRegistrar", () => { }); await domain.register(); - await domain.updateMintlistForDomain( + await domain.updateMintlistForDomain({ candidates, - allowed - ); + allowed, + }); }); it("Should NOT initialize the implementation contract", async () => { @@ -935,7 +935,10 @@ describe("ZNSRootRegistrar", () => { expect(await domain.ownerOfHash()).to.equal(user.address); // Reclaim the Domain Token - await domain.assignDomainToken(user.address, user); + await domain.assignDomainToken({ + to: user.address, + executor: user, + }); // Verify domain token is now owned by new hash owner expect(await domain.ownerOfToken()).to.equal(user.address); @@ -962,7 +965,10 @@ describe("ZNSRootRegistrar", () => { // Assign the Domain token await expect( - domain.assignDomainToken(user.address, deployer) + domain.assignDomainToken({ + to: user.address, + executor: deployer, + }) ).to.emit(zns.rootRegistrar, "DomainTokenReassigned").withArgs( domain.hash, user.address @@ -982,7 +988,10 @@ describe("ZNSRootRegistrar", () => { // Reclaim the Domain await expect( - domain.assignDomainToken(user.address, user) + domain.assignDomainToken({ + to: user.address, + executor: user, + }) ).to.be.revertedWithCustomError( zns.rootRegistrar, NOT_AUTHORIZED_ERR, @@ -1024,7 +1033,10 @@ describe("ZNSRootRegistrar", () => { await zns.registry.connect(deployer).updateDomainOwner(domain.hash, user.address); // Claim the Domain token - await domain.assignDomainToken(user.address, user); + await domain.assignDomainToken({ + to: user.address, + executor: user, + }); // Verify domain token is owned expect(await domain.ownerOfToken()).to.equal(user.address); @@ -1036,7 +1048,10 @@ describe("ZNSRootRegistrar", () => { expect(await domain.ownerOfHash()).to.equal(deployer.address); // Assign the Domain token to diff address again - await domain.assignDomainToken(user.address, deployer); + await domain.assignDomainToken({ + to: user.address, + executor: deployer, + }); // Verify domain token is owned expect(await domain.ownerOfToken()).to.equal(user.address); @@ -1065,7 +1080,7 @@ describe("ZNSRootRegistrar", () => { // Assign the Domain token await expect( - domain.assignDomainToken(deployer.address) + domain.assignDomainToken({ to: deployer.address }) ).to.be.revertedWithCustomError( zns.rootRegistrar, "AlreadyTokenOwner", @@ -1221,11 +1236,11 @@ describe("ZNSRootRegistrar", () => { const domainHash = await domain.getDomainHashFromEvent(user); // add mintlist to check revocation - await domain.updateMintlistForDomain( - [user.address, zeroVault.address], - [true, true], - user - ); + await domain.updateMintlistForDomain({ + candidates: [user.address, zeroVault.address], + allowed: [true, true], + executor: user, + }); const ogPrice = BigInt(135); @@ -1365,7 +1380,10 @@ describe("ZNSRootRegistrar", () => { await domain.ownerOfHash() ).to.not.equal(user.address); - await domain.assignDomainToken(user.address, deployer); + await domain.assignDomainToken({ + to: user.address, + executor: deployer, + }); // Try to revoke domain as a new owner of the token await expect( @@ -1392,7 +1410,10 @@ describe("ZNSRootRegistrar", () => { await domain.register(); // assign an operator - await domain.setOwnersOperator(operator.address, true); + await domain.setOwnersOperator({ + operator: operator.address, + allowed: true, + }); // Revoke the domain await domain.revoke(); diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 955603aef..d636736f5 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -65,7 +65,7 @@ import { ZeroHash } from "ethers"; import { IFullDomainConfig } from "./helpers/domain/types"; -describe.only("ZNSSubRegistrar", () => { +describe("ZNSSubRegistrar", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -817,7 +817,7 @@ describe.only("ZNSSubRegistrar", () => { }); await domain2.register(); // set the token address - await domain2.setPaymentTokenForDomain(await zns.meowToken.getAddress()); + await domain2.setPaymentTokenForDomain({ tokenAddress: await zns.meowToken.getAddress() }); // register subdomains under new parents const subdomain = new Domain({ @@ -866,11 +866,10 @@ describe.only("ZNSSubRegistrar", () => { decodedConfig.feePercentage = BigInt(0); // TODO dom: start from this - await domain2.setPricerDataForDomain( - domain2.hash, - encodePriceConfig(decodedConfig), - currDistrConfig.pricerContract - ); + await domain2.setPricerDataForDomain({ + priceConfig: decodedConfig, + pricerContract: currDistrConfig.pricerContract, + }); // try register a subdomain again await subdomain2.register(); diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 55c42a403..2f614abcc 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -164,20 +164,26 @@ export default class Domain { return this.zns.rootRegistrar.connect(executor ? executor : this.owner).revokeDomain(this.hash); } - async assignDomainToken ( - to : string, - executor ?: SignerWithAddress - ) : Promise { + async assignDomainToken ({ + to, + executor, + } : { + to : string; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.rootRegistrar.connect(executor ? executor : this.owner).assignDomainToken( this.hash, to ); } - async updateDomainRecord ( - resolverType : string, - executor ?: SignerWithAddress - ) : Promise { + async updateDomainRecord ({ + resolverType, + executor, + } : { + resolverType : string; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.registry.connect(executor ? executor : this.owner).updateDomainRecord( this.hash, this.owner, @@ -185,11 +191,15 @@ export default class Domain { ); } - async updateMintlistForDomain ( - candidates : Array, - allowed : Array, - executor ?: SignerWithAddress - ) : Promise { + async updateMintlistForDomain ({ + candidates, + allowed, + executor, + } : { + candidates : Array; + allowed : Array; + executor ?: SignerWithAddress; + }) : Promise { if (candidates.length !== allowed.length) throw new Error("Domain Helper: Candidates and allowed arrays must have the same length"); @@ -217,11 +227,15 @@ export default class Domain { // ------------------------------------------------------ // SETTERS // ------------------------------------------------------ - async setOwnersOperator ( - operator : string, - allowed : boolean, - executor ?: SignerWithAddress - ) : Promise { + async setOwnersOperator ({ + operator, + allowed, + executor, + } : { + operator : string; + allowed : boolean; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.registry.connect(executor ? executor : this.owner).setOwnersOperator(operator, allowed); } @@ -234,11 +248,15 @@ export default class Domain { ); } - async setPricerDataForDomain ( - priceConfig ?: ICurvePriceConfig | IFixedPriceConfig, - pricerContract ?: string, - executor ?: SignerWithAddress - ) : Promise { + async setPricerDataForDomain ({ + priceConfig, + pricerContract, + executor, + } : { + priceConfig ?: ICurvePriceConfig | IFixedPriceConfig; + pricerContract ?: string; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( this.hash, priceConfig ? encodePriceConfig(priceConfig) : encodePriceConfig(this.priceConfig), @@ -246,30 +264,39 @@ export default class Domain { ); } - async setPaymentTypeForDomain ( - paymentType : bigint, - executor ?: SignerWithAddress - ) : Promise { + async setPaymentTypeForDomain ({ + paymentType, + executor, + } : { + paymentType : bigint; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.subRegistrar.connect(executor ? executor : this.owner).setPaymentTypeForDomain( this.hash, paymentType, ); } - async setAccessTypeForDomain ( - accessType : bigint, - executor ?: SignerWithAddress - ) : Promise { + async setAccessTypeForDomain ({ + accessType, + executor, + } : { + accessType : bigint; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.subRegistrar.connect(executor ? executor : this.owner).setAccessTypeForDomain( this.hash, accessType, ); } - async setPaymentTokenForDomain ( - tokenAddress : string, - executor ?: SignerWithAddress - ) : Promise { + async setPaymentTokenForDomain ({ + tokenAddress, + executor, + } : { + tokenAddress : string; + executor ?: SignerWithAddress; + }) : Promise { if (!hre.ethers.isAddress(tokenAddress)) { throw new Error("Domain Helper: Invalid token address provided"); } @@ -283,10 +310,13 @@ export default class Domain { // ------------------------------------------------------ // VALIDATION // ------------------------------------------------------ - async validate ( - txPromise : ContractTransactionResponse, - executor ?: SignerWithAddress - ) { + async validate ({ + txPromise, + executor, + } : { + txPromise : ContractTransactionResponse; + executor ?: SignerWithAddress; + }) { // check domain existence with event await expect(txPromise) .to.emit( @@ -323,6 +353,9 @@ export default class Domain { ) : Promise { const txPromise = await this.register(executor ? executor : this.owner); - await this.validate(txPromise, executor); + await this.validate({ + txPromise, + executor, + }); } } From 25bbfef11a9562052af8b67cd9284820641359a5 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Mon, 25 Aug 2025 17:32:07 -0700 Subject: [PATCH 12/26] Getters have been moved to the appropriate location. More subregistrar optimization according to registration and revocation. --- test/ZNSSubRegistrar.test.ts | 416 +++++++++++++++++++--------------- test/helpers/domain/domain.ts | 16 +- 2 files changed, 244 insertions(+), 188 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index d636736f5..3de03bf58 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -63,9 +63,10 @@ import { IZNSContracts } from "../src/deploy/campaign/types"; import Domain from "./helpers/domain/domain"; import { ZeroHash } from "ethers"; import { IFullDomainConfig } from "./helpers/domain/types"; +import { child } from "winston"; -describe("ZNSSubRegistrar", () => { +describe.only("ZNSSubRegistrar", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -1931,17 +1932,6 @@ describe("ZNSSubRegistrar", () => { beneficiary: lvl2SubOwner.address, }, }, - // domainConfigs[1], - // { - // owner: lvl2SubOwner, - // label: domainConfigs[1].label, - // tokenOwner: lvl2SubOwner.address, - // parentHash, - // distrConfig: domainConfigs[1].distrConfig, - // paymentConfig: domainConfigs[1].paymentConfig, - // domainAddress: lvl2SubOwner.address, - // tokenURI: subTokenURI, - // }, }); await subdomain.register(); @@ -2092,13 +2082,12 @@ describe("ZNSSubRegistrar", () => { expect(subdomain.hash).to.eq(regResults[1].domainHash); // add new child owner to mintlist - await zns.subRegistrar.connect(branchLvl1Owner).updateMintlistForDomain( - subdomain.hash, - [ branchLvl2Owner.address ], - [ true ], - ); + await subdomain.updateMintlistForDomain({ + candidates: [ branchLvl2Owner.address ], + allowed: [ true ], + }); - const parentOwnerFromReg = await zns.registry.getDomainOwner(subdomain.hash); + const parentOwnerFromReg = await subdomain.getDomainOwner(); expect(parentOwnerFromReg).to.eq(branchLvl1Owner.address); const childBalBefore = await zns.meowToken.balanceOf(branchLvl2Owner.address); @@ -2231,7 +2220,6 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await domain.register(); }); @@ -2285,14 +2273,26 @@ describe("ZNSSubRegistrar", () => { const childBalBefore = await token5.balanceOf(lvl3SubOwner.address); const zeroVaultBalanceBefore = await token5.balanceOf(zeroVault.address); - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, - fullConfig: FULL_DISTR_CONFIG_EMPTY, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParentHash, + label, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.LOCKED, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: ethers.ZeroAddress, + beneficiary: ethers.ZeroAddress, + }, + }, }); + await child.register(); const parentBalAfter = await token5.balanceOf(lvl2SubOwner.address); const childBalAfter = await token5.balanceOf(lvl3SubOwner.address); @@ -2304,15 +2304,13 @@ describe("ZNSSubRegistrar", () => { expect(contractBalAfter - contractBalBefore).to.eq(expectedPrice); expect(zeroVaultBalanceAfter - zeroVaultBalanceBefore).to.eq(protocolFee); - const stake = await zns.treasury.stakedForDomain(childHash); + const stake = await zns.treasury.stakedForDomain(child.hash); const protocolFeeOut = getStakingOrProtocolFee(stake.amount); await token5.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should offer refund ! const contractBalAfterRevoke = await token5.balanceOf(await zns.treasury.getAddress()); @@ -2327,17 +2325,20 @@ describe("ZNSSubRegistrar", () => { }); it("Does not charge the owner of a parent domain when they revoke a subdomain", async () => { - const subdomainHash = await registrationWithSetup({ + const subdomain = new Domain({ zns, - tokenOwner: rootOwner.address, - user: rootOwner, - parentHash: domain.hash, - domainLabel: "subdomain", + domainConfig: { + tokenOwner: rootOwner.address, + owner: rootOwner, + parentHash: domain.hash, + label: "subdomain", + }, }); + await subdomain.register(); const balanceBefore = await zns.meowToken.balanceOf(rootOwner.address); - await zns.rootRegistrar.connect(rootOwner).revokeDomain(subdomainHash); + await subdomain.revoke(); const balanceAfter = await zns.meowToken.balanceOf(rootOwner.address); expect(balanceBefore).to.eq(balanceAfter); @@ -2349,13 +2350,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "fixedstakenofee", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "fixedstakenofee", distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2368,6 +2369,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const label = "fixedstakenofeechild"; @@ -2385,13 +2387,26 @@ describe("ZNSSubRegistrar", () => { const childBalBefore = await token18.balanceOf(lvl3SubOwner.address); const zeroVaultBalanceBefore = await token18.balanceOf(zeroVault.address); - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.LOCKED, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: ethers.ZeroAddress, + beneficiary: ethers.ZeroAddress, + }, + }, }); + await child.register(); const parentBalAfter = await token18.balanceOf(lvl2SubOwner.address); const childBalAfter = await token18.balanceOf(lvl3SubOwner.address); @@ -2406,9 +2421,7 @@ describe("ZNSSubRegistrar", () => { await token18.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), protocolFee); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should offer refund ! const contractBalAfterRevoke = await token18.balanceOf(await zns.treasury.getAddress()); @@ -2428,13 +2441,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "fixeddirectnofee", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "fixeddirectnofee", distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2447,6 +2460,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const label = "fixeddirectnofeechild"; const { expectedPrice } = getPriceObject(label, priceConfig); @@ -2463,31 +2477,39 @@ describe("ZNSSubRegistrar", () => { const contractBalBefore = await token8.balanceOf(await zns.treasury.getAddress()); const zeroVaultBalanceBefore = await token8.balanceOf(zeroVault.address); - - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, - fullConfig: FULL_DISTR_CONFIG_EMPTY, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.LOCKED, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: ethers.ZeroAddress, + beneficiary: ethers.ZeroAddress, + }, + }, }); + await child.register(); const parentBalAfter = await token8.balanceOf(lvl2SubOwner.address); const childBalAfter = await token8.balanceOf(lvl3SubOwner.address); const contractBalAfter = await token8.balanceOf(await zns.treasury.getAddress()); const zeroVaultBalanceAfter = await token8.balanceOf(zeroVault.address); - expect(parentBalAfter - parentBalBefore).to.eq(expectedPrice); expect(childBalBefore - childBalAfter).to.eq(expectedPrice + protocolFee); expect(contractBalAfter - contractBalBefore).to.eq(0); expect(zeroVaultBalanceAfter - zeroVaultBalanceBefore).to.eq(protocolFee); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should NOT offer refund ! const parentBalAfterRevoke = await token8.balanceOf(lvl2SubOwner.address); @@ -2513,13 +2535,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(185), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "asympstake", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "asympstake", distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2532,6 +2554,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const label = "curvestakechild"; @@ -2554,14 +2577,26 @@ describe("ZNSSubRegistrar", () => { const childBalBefore = await token13.balanceOf(lvl3SubOwner.address); const zeroVaultBalanceBefore = await token13.balanceOf(zeroVault.address); - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, - fullConfig: FULL_DISTR_CONFIG_EMPTY, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: PaymentType.DIRECT, + accessType: AccessType.LOCKED, + priceConfig: ZeroHash, + }, + paymentConfig: { + token: ethers.ZeroAddress, + beneficiary: ethers.ZeroAddress, + }, + }, }); + await child.register(); const contractBalAfter = await token13.balanceOf(await zns.treasury.getAddress()); const parentBalAfter = await token13.balanceOf(lvl2SubOwner.address); @@ -2577,7 +2612,7 @@ describe("ZNSSubRegistrar", () => { await token13.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), protocolFeeOut); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain(childHash); + await child.revoke(); // should offer refund ! const contractBalAfterRevoke = await token13.balanceOf(await zns.treasury.getAddress()); @@ -2601,13 +2636,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "curvestakenofee", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "curvestakenofee", distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2620,6 +2655,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const label = "curvestakenofeechild"; @@ -2637,13 +2673,16 @@ describe("ZNSSubRegistrar", () => { const childBalBefore = await token2.balanceOf(lvl3SubOwner.address); const zeroVaultBalanceBefore = await token2.balanceOf(zeroVault.address); - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await child.register(); const contractBalAfter = await token2.balanceOf(await zns.treasury.getAddress()); const parentBalAfter = await token2.balanceOf(lvl2SubOwner.address); @@ -2658,9 +2697,7 @@ describe("ZNSSubRegistrar", () => { await token2.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), protocolFee); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should offer refund ! const contractBalAfterRevoke = await token2.balanceOf(await zns.treasury.getAddress()); @@ -2680,13 +2717,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "curvedirectnofee", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "curvedirectnofee", distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2694,12 +2731,12 @@ describe("ZNSSubRegistrar", () => { paymentType: PaymentType.DIRECT, }, paymentConfig: { - // zero has 18 decimals token: await zns.meowToken.getAddress(), beneficiary: lvl2SubOwner.address, }, }, }); + await subdomainParent.register(); const label = "asdirectnofeechild"; @@ -2708,13 +2745,16 @@ describe("ZNSSubRegistrar", () => { const childBalBefore = await zns.meowToken.balanceOf(lvl3SubOwner.address); const zeroVaultBalanceBefore = await zns.meowToken.balanceOf(zeroVault.address); - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await child.register(); const parentBalAfter = await zns.meowToken.balanceOf(lvl2SubOwner.address); const childBalAfter = await zns.meowToken.balanceOf(lvl3SubOwner.address); @@ -2730,9 +2770,7 @@ describe("ZNSSubRegistrar", () => { expect(zeroVaultBalanceAfter - zeroVaultBalanceBefore).to.eq(protocolFee); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should NOT offer refund ! const parentBalAfterRevoke = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -2752,13 +2790,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "zeroprice", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "zeroprice", distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2771,6 +2809,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const contractBalBefore = await zns.meowToken.balanceOf(await zns.treasury.getAddress()); const parentBalBefore = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -2778,13 +2817,16 @@ describe("ZNSSubRegistrar", () => { const zeroVaultBalanceBefore = await zns.meowToken.balanceOf(zeroVault.address); const label = "zeropricechild"; - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await child.register(); const parentBalAfter = await zns.meowToken.balanceOf(lvl2SubOwner.address); const childBalAfter = await zns.meowToken.balanceOf(lvl3SubOwner.address); @@ -2817,9 +2859,7 @@ describe("ZNSSubRegistrar", () => { expect(transfersToTreasury.length).to.eq(0); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should NOT offer refund ! const parentBalAfterRevoke = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -2839,13 +2879,13 @@ describe("ZNSSubRegistrar", () => { maxPrice: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "zeropricead", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "zeropricead", distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2858,6 +2898,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const contractBalBefore = await zns.meowToken.balanceOf(await zns.treasury.getAddress()); const parentBalBefore = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -2865,13 +2906,16 @@ describe("ZNSSubRegistrar", () => { const zeroVaultBalanceBefore = await zns.meowToken.balanceOf(zeroVault.address); const label = "zeropricechildad"; - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await child.register(); const parentBalAfter = await zns.meowToken.balanceOf(lvl2SubOwner.address); const childBalAfter = await zns.meowToken.balanceOf(lvl3SubOwner.address); @@ -2907,9 +2951,7 @@ describe("ZNSSubRegistrar", () => { expect(transfersToTreasury.length).to.eq(0); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should NOT offer refund ! const parentBalAfterRevoke = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -2929,13 +2971,13 @@ describe("ZNSSubRegistrar", () => { maxPrice: BigInt(0), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "zeropriceas", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "zeropriceas", distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -2948,6 +2990,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const contractBalBefore = await zns.meowToken.balanceOf(await zns.treasury.getAddress()); const parentBalBefore = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -2955,13 +2998,16 @@ describe("ZNSSubRegistrar", () => { const zeroVaultBalanceBefore = await zns.meowToken.balanceOf(zeroVault.address); const label = "zeropricechildas"; - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await child.register(); const parentBalAfter = await zns.meowToken.balanceOf(lvl2SubOwner.address); const childBalAfter = await zns.meowToken.balanceOf(lvl3SubOwner.address); @@ -2994,9 +3040,7 @@ describe("ZNSSubRegistrar", () => { expect(transfersToTreasury.length).to.eq(0); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should NOT offer refund ! const parentBalAfterRevoke = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -3018,13 +3062,13 @@ describe("ZNSSubRegistrar", () => { feePercentage: BigInt(5), }; - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "zeropricefs", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "zeropricefs", distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig(priceConfig), @@ -3037,6 +3081,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const contractBalBefore = await zns.meowToken.balanceOf(await zns.treasury.getAddress()); const parentBalBefore = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -3044,13 +3089,16 @@ describe("ZNSSubRegistrar", () => { const zeroVaultBalanceBefore = await zns.meowToken.balanceOf(zeroVault.address); const label = "zeropricechildfs"; - const childHash = await registrationWithSetup({ + const child = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await child.register(); const parentBalAfter = await zns.meowToken.balanceOf(lvl2SubOwner.address); const childBalAfter = await zns.meowToken.balanceOf(lvl3SubOwner.address); @@ -3083,9 +3131,7 @@ describe("ZNSSubRegistrar", () => { expect(transfersToTreasury.length).to.eq(0); // revoke - await zns.rootRegistrar.connect(lvl3SubOwner).revokeDomain( - childHash, - ); + await child.revoke(); // should NOT offer refund ! const parentBalAfterRevoke = await zns.meowToken.balanceOf(lvl2SubOwner.address); @@ -3111,13 +3157,13 @@ describe("ZNSSubRegistrar", () => { }; // see `token` in paymentConfig - const subdomainParentHash = await registrationWithSetup({ + const subdomainParent = new Domain({ zns, - user: lvl2SubOwner, - tokenOwner: lvl2SubOwner.address, - parentHash: domain.hash, - domainLabel: "incorrectparent", - fullConfig: { + domainConfig: { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + parentHash: domain.hash, + label: "incorrectparent", distrConfig: { pricerContract: await zns.curvePricer.getAddress(), priceConfig: encodePriceConfig(priceConfigIncorrect), @@ -3131,6 +3177,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await subdomainParent.register(); const label = "incorrectchild"; @@ -3161,7 +3208,7 @@ describe("ZNSSubRegistrar", () => { decodePriceConfig(rootPriceConfig).feePercentage ); - const distrConfig = await zns.subRegistrar.distrConfigs(subdomainParentHash); + const distrConfig = await zns.subRegistrar.distrConfigs(subdomainParent.hash); expect(distrConfig.priceConfig).to.eq(encodePriceConfig(priceConfigIncorrect)); @@ -3204,16 +3251,22 @@ describe("ZNSSubRegistrar", () => { priceCorrect + stakeFeeCorrect + protocolFeeCorrect ); - await expect( - zns.subRegistrar.registerSubdomain({ - parentHash: subdomainParentHash, + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, label, domainAddress: lvl3SubOwner.address, tokenOwner: ethers.ZeroAddress, tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + subdomain.register() ).to.be.revertedWithCustomError( zns.meowToken, INSUFFICIENT_ALLOWANCE_ERC_ERR @@ -3222,13 +3275,16 @@ describe("ZNSSubRegistrar", () => { // let's try to buy with the incorrect price const userBalanceBefore = await token5.balanceOf(lvl3SubOwner.address); - await registrationWithSetup({ + const sub = new Domain({ zns, - tokenOwner: lvl3SubOwner.address, - user: lvl3SubOwner, - parentHash: subdomainParentHash, - domainLabel: label, + domainConfig: { + tokenOwner: lvl3SubOwner.address, + owner: lvl3SubOwner, + parentHash: subdomainParent.hash, + label, + }, }); + await sub.register(); const userBalanceAfter = await token5.balanceOf(lvl3SubOwner.address); diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 2f614abcc..aebabdf17 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -74,14 +74,6 @@ export default class Domain { return BigInt(this.hash); } - async ownerOfHash () : Promise { - return this.zns.registry.getDomainOwner(this.hash); - } - - async ownerOfToken () : Promise { - return this.zns.domainToken.ownerOf(this.tokenId); - } - async getDomainHashFromEvent (domainOwner ?: SignerWithAddress) : Promise { const latestBlock = await time.latestBlock(); const filter = this.zns.rootRegistrar.filters.DomainRegistered( @@ -224,6 +216,14 @@ export default class Domain { return this.zns.treasury.paymentConfigs(this.hash); } + async getDomainOwner () : Promise { + return this.zns.registry.getDomainOwner(this.hash); + } + + async getOwnerOf () : Promise { + return this.zns.domainToken.ownerOf(this.tokenId); + } + // ------------------------------------------------------ // SETTERS // ------------------------------------------------------ From 17954d6722d8e7f3bd7cd214d276dda627cf44a2 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 26 Aug 2025 14:44:27 -0700 Subject: [PATCH 13/26] Test failing fix --- test/ZNSSubRegistrar.test.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 3de03bf58..160d19001 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -3251,10 +3251,9 @@ describe.only("ZNSSubRegistrar", () => { priceCorrect + stakeFeeCorrect + protocolFeeCorrect ); - const subdomain = new Domain({ - zns, - domainConfig: { - owner: lvl3SubOwner, + // using direct contract call cause domain.register() prepares and + await expect( + zns.subRegistrar.connect(lvl3SubOwner).registerSubdomain({ parentHash: subdomainParent.hash, label, domainAddress: lvl3SubOwner.address, @@ -3262,11 +3261,7 @@ describe.only("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }, - }); - - await expect( - subdomain.register() + }) ).to.be.revertedWithCustomError( zns.meowToken, INSUFFICIENT_ALLOWANCE_ERC_ERR From 0eb739b99e4e6ac5ce6a8acf5d6b9ceab63f46a2 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Mon, 15 Sep 2025 17:22:53 -0700 Subject: [PATCH 14/26] RootReg test minor fixes --- test/ZNSRootRegistrar.test.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/ZNSRootRegistrar.test.ts b/test/ZNSRootRegistrar.test.ts index 89cac61d6..fd85497a5 100644 --- a/test/ZNSRootRegistrar.test.ts +++ b/test/ZNSRootRegistrar.test.ts @@ -543,7 +543,7 @@ describe("ZNSRootRegistrar", () => { }); await domain.registerAndValidateDomain(randomUser); - expect(await domain.ownerOfToken()).to.eq(randomUser.address); + expect(await domain.getOwnerOf()).to.eq(randomUser.address); }); it("Stakes and saves the correct amount and token, takes the correct fee and sends fee to Zero Vault", async () => { @@ -932,7 +932,7 @@ describe("ZNSRootRegistrar", () => { await zns.registry.connect(deployer).updateDomainOwner(domain.hash, user.address); // Verify owner in Registry is changed - expect(await domain.ownerOfHash()).to.equal(user.address); + expect(await domain.getDomainOwner()).to.equal(user.address); // Reclaim the Domain Token await domain.assignDomainToken({ @@ -941,10 +941,10 @@ describe("ZNSRootRegistrar", () => { }); // Verify domain token is now owned by new hash owner - expect(await domain.ownerOfToken()).to.equal(user.address); + expect(await domain.getOwnerOf()).to.equal(user.address); // Verify domain is still owned in registry - expect(await domain.ownerOfHash()).to.equal(user.address); + expect(await domain.getDomainOwner()).to.equal(user.address); // Verify same amount is staked const { amount: stakedAfterReclaim, token: tokenAfterReclaim } = await zns.treasury.stakedForDomain(domain.hash); @@ -999,7 +999,7 @@ describe("ZNSRootRegistrar", () => { // Verify domain is not owned in registry expect( - await domain.ownerOfHash() + await domain.getDomainOwner() ).to.equal(deployer.address); }); @@ -1038,14 +1038,14 @@ describe("ZNSRootRegistrar", () => { executor: user, }); // Verify domain token is owned - expect(await domain.ownerOfToken()).to.equal(user.address); + expect(await domain.getOwnerOf()).to.equal(user.address); // Transfer the domain token back await zns.domainToken.connect(user).transferFrom(user.address, deployer.address, domain.tokenId); // check that hash and token owners changed to the same address - expect(await domain.ownerOfToken()).to.equal(deployer.address); - expect(await domain.ownerOfHash()).to.equal(deployer.address); + expect(await domain.getOwnerOf()).to.equal(deployer.address); + expect(await domain.getDomainOwner()).to.equal(deployer.address); // Assign the Domain token to diff address again await domain.assignDomainToken({ @@ -1054,9 +1054,9 @@ describe("ZNSRootRegistrar", () => { }); // Verify domain token is owned - expect(await domain.ownerOfToken()).to.equal(user.address); + expect(await domain.getOwnerOf()).to.equal(user.address); // but not the hash - expect(await domain.ownerOfHash()).to.equal(deployer.address); + expect(await domain.getDomainOwner()).to.equal(deployer.address); // Verify same amount is staked const { amount: stakedAfterReclaim, token: tokenAfterReclaim } = await zns.treasury.stakedForDomain(domain.hash); @@ -1251,10 +1251,10 @@ describe("ZNSRootRegistrar", () => { const asBytes = encodePriceConfig(newConfig); - await domain.setPricerDataForDomain( - newConfig, - zns.fixedPricer.target as string, - ); + await domain.setPricerDataForDomain({ + priceConfig: newConfig, + pricerContract: zns.fixedPricer.target as string, + }); expect(await zns.fixedPricer.getPrice(asBytes, defaultDomain, false)).to.eq(ogPrice); @@ -1263,7 +1263,7 @@ describe("ZNSRootRegistrar", () => { // Verify token has been burned await expect( - domain.ownerOfToken() + domain.getOwnerOf() ).to.be.revertedWithCustomError( zns.domainToken, NONEXISTENT_TOKEN_ERC_ERR @@ -1355,7 +1355,7 @@ describe("ZNSRootRegistrar", () => { await domain.register(); const parentDomainHash = await domain.getDomainHashFromEvent(deployer); - const owner = await domain.ownerOfHash(); + const owner = await domain.getDomainOwner(); expect(owner).to.not.equal(user.address); // Try to revoke domain @@ -1377,7 +1377,7 @@ describe("ZNSRootRegistrar", () => { await domain.register(); expect( - await domain.ownerOfHash() + await domain.getDomainOwner() ).to.not.equal(user.address); await domain.assignDomainToken({ From a7918abc84bf7ac2f03fccb66c45dba8089bb05a Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Fri, 19 Sep 2025 15:22:44 -0700 Subject: [PATCH 15/26] Moved most part of unit tests to separate module. Updated proccess. [WIP] --- test/DeployCampaignInt.test.ts | 2 - test/ZNSSubRegistrar.test.ts | 560 +-------------------------- test/ZNSSubRegistrar.unit.test.ts | 623 ++++++++++++++++++++++++++++++ 3 files changed, 625 insertions(+), 560 deletions(-) create mode 100644 test/ZNSSubRegistrar.unit.test.ts diff --git a/test/DeployCampaignInt.test.ts b/test/DeployCampaignInt.test.ts index bd9cc6a9e..0f69cd543 100644 --- a/test/DeployCampaignInt.test.ts +++ b/test/DeployCampaignInt.test.ts @@ -943,8 +943,6 @@ describe("Deploy Campaign Test", () => { >; before(async () => { - await saveTag(); - campaignConfig = { env, confirmationsN: 0, diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 2ba4464f9..5fdff5942 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -4,11 +4,9 @@ import { IDistributionConfig, IDomainConfigForTest, IPathRegResult, - ISubRegistrarConfig, } from "./helpers/types"; import { AccessType, - ADMIN_ROLE, DEFAULT_TOKEN_URI, deployZNS, distrConfigEmpty, @@ -32,14 +30,12 @@ import { ZERO_ADDRESS_ERR, DOMAIN_EXISTS_ERR, SENDER_NOT_APPROVED_ERR, - ZERO_PARENTHASH_ERR, encodePriceConfig, DEFAULT_CURVE_PRICE_CONFIG_BYTES, DEFAULT_CURVE_PRICE_CONFIG, decodePriceConfig, DEFAULT_FIXED_PRICER_CONFIG_BYTES, - PAUSE_SAME_VALUE_ERR, REGISTRATION_PAUSED_ERR, - AC_WRONGADDRESS_ERR, + REGISTRATION_PAUSED_ERR, } from "./helpers"; import * as hre from "hardhat"; import { ethers } from "hardhat"; @@ -47,23 +43,19 @@ import { expect } from "chai"; import { registerDomainPath, validatePathRegistration } from "./helpers/flows/registration"; import assert from "assert"; import { defaultSubdomainRegistration, registrationWithSetup } from "./helpers/register-setup"; -import { getDomainHashFromEvent, getDomainRegisteredEvents } from "./helpers/events"; +import { getDomainHashFromEvent } from "./helpers/events"; import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { CustomDecimalTokenMock, - ZNSSubRegistrar, - ZNSSubRegistrar__factory, ZNSSubRegistrarUpgradeMock, ZNSSubRegistrarUpgradeMock__factory, } from "../typechain"; import { deployCustomDecToken } from "./helpers/deploy/mocks"; -import { getProxyImplAddress } from "./helpers/utils"; import { ICurvePriceConfig, IFixedPriceConfig } from "../src/deploy/missions/types"; import { IZNSContracts } from "../src/deploy/campaign/types"; import Domain from "./helpers/domain/domain"; import { ZeroHash } from "ethers"; import { IFullDomainConfig } from "./helpers/domain/types"; -import { child } from "winston"; describe.only("ZNSSubRegistrar", () => { @@ -80,7 +72,6 @@ describe.only("ZNSSubRegistrar", () => { let lvl6SubOwner : SignerWithAddress; let branchLvl1Owner : SignerWithAddress; let branchLvl2Owner : SignerWithAddress; - let random : SignerWithAddress; let operator : SignerWithAddress; let multiOwner : SignerWithAddress; @@ -866,7 +857,6 @@ describe.only("ZNSSubRegistrar", () => { decodedConfig.feePercentage = BigInt(0); - // TODO dom: start from this await domain2.setPricerDataForDomain({ priceConfig: decodedConfig, pricerContract: currDistrConfig.pricerContract, @@ -879,367 +869,6 @@ describe.only("ZNSSubRegistrar", () => { }); }); - describe("Bulk Subdomain Registration", () => { - let domain : Domain; - - before(async () => { - domain = new Domain({ - zns, - domainConfig: { - owner: rootOwner, - label: "root1bulk", - parentHash: ethers.ZeroHash, - tokenOwner: rootOwner.address, - tokenURI: DEFAULT_TOKEN_URI, - distrConfig: defaultDistrConfig, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: rootOwner.address, - }, - }, - }); - await domain.register(); - }); - - it("Should #registerSubdomainBulk and the event must be triggered", async () => { - const registrations : Array = []; - - for (let i = 0; i < 5; i++) { - const isOdd = i % 2 !== 0; - - const subdomainObj : ISubRegistrarConfig = { - parentHash: domain.hash, - label: `subdomain${i + 1}`, - domainAddress: admin.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: `0://tokenURI_${i + 1}`, - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - paymentType: isOdd ? PaymentType.STAKE : PaymentType.DIRECT, - accessType: isOdd ? AccessType.LOCKED : AccessType.OPEN, - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: isOdd ? admin.address : lvl2SubOwner.address, - }, - }; - - registrations.push(subdomainObj); - } - - // Add allowance - await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - await zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk(registrations); - - // get by `registrant` - const logs = await getDomainRegisteredEvents({ - zns, - registrant: lvl2SubOwner.address, - }); - - // eslint-disable-next-line @typescript-eslint/prefer-for-of - for (let i = logs.length - 1; i === 0; i--) { - const subdomain = registrations[i]; - - const domainHashExpected = await zns.subRegistrar.hashWithParent( - subdomain.parentHash, - subdomain.label - ); - - // "DomainRegistered" event log - const { parentHash, domainHash, label, tokenOwner, tokenURI, domainOwner, domainAddress } = logs[i].args; - - expect(parentHash).to.eq(domain.hash); - expect(domainHashExpected).to.eq(domainHash); - expect(label).to.eq(subdomain.label); - expect(tokenURI).to.eq(subdomain.tokenURI); - expect(tokenOwner).to.eq(domainOwner); - expect(domainOwner).to.eq(lvl2SubOwner.address); - expect(domainAddress).to.eq(subdomain.domainAddress); - } - }); - - it("Should register multiple NESTED subdomains using #registerSubdomainBulk", async () => { - const registrations : Array = []; - const parentHashes : Array = []; - - // how many nested domains (0://root.sub1.sub2.sub3....) - const domainLevels = 15; - - for (let i = 0; i < domainLevels; i++) { - const isOdd = i % 2 !== 0; - - const subdomainObj : ISubRegistrarConfig = { - parentHash: domain.hash, - label: `sub${i + 1}`, - domainAddress: lvl3SubOwner.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: `0://tokenURI_${i + 1}`, - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - paymentType: isOdd ? PaymentType.STAKE : PaymentType.DIRECT, - accessType: isOdd ? AccessType.LOCKED : AccessType.OPEN, - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: isOdd ? lvl3SubOwner.address : lvl2SubOwner.address, - }, - }; - - if (i > 0) subdomainObj.parentHash = ethers.ZeroHash; - - registrations.push(subdomainObj); - - // first goes with rootHash - parentHashes.push( - await zns.subRegistrar.hashWithParent( - i === 0 ? domain.hash : parentHashes[i - 1], - subdomainObj.label - ) - ); - } - - // Add allowance - await zns.meowToken.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - await zns.subRegistrar.connect(lvl3SubOwner).registerSubdomainBulk(registrations); - - const logs = await getDomainRegisteredEvents({ - zns, - registrant: lvl3SubOwner.address, - }); - - for (let i = 0; i < domainLevels; i++) { - const subdomain = registrations[i]; - - // "DomainRegistered" event log - const { parentHash, domainHash, label, tokenURI, tokenOwner, domainOwner, domainAddress } = logs[i].args; - - i > 0 ? - expect(parentHash).to.eq(parentHashes[i - 1]) : - expect(parentHash).to.eq(domain.hash); - expect(domainHash).to.eq(parentHashes[i]); - expect(label).to.eq(subdomain.label); - expect(tokenURI).to.eq(subdomain.tokenURI); - expect(domainOwner).to.eq(lvl3SubOwner.address); - expect(tokenOwner).to.eq(lvl3SubOwner.address); - expect(domainAddress).to.eq(subdomain.domainAddress); - } - }); - - it("Should revert when register the same domain twice using #registerSubdomainBulk", async () => { - const subdomainObj : ISubRegistrarConfig = { - parentHash: domain.hash, - label: "subdomain1", - domainAddress: admin.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: "0://tokenURI", - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - paymentType: PaymentType.STAKE, - accessType: AccessType.LOCKED, - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: admin.address, - }, - }; - - // Add allowance - await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk([subdomainObj, subdomainObj]) - ).to.be.revertedWithCustomError(zns.rootRegistrar, "DomainAlreadyExists"); - }); - - it("Should revert with 'ZeroAddressPassed' error when 1st subdomain in the array has zerohash", async () => { - const subdomainObj : ISubRegistrarConfig = { - parentHash: ethers.ZeroHash, - label: "subdomainzeroaAddresspassed", - domainAddress: admin.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: "0://tokenURI", - distrConfig: { - pricerContract: await zns.curvePricer.getAddress(), - paymentType: PaymentType.STAKE, - accessType: AccessType.LOCKED, - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: admin.address, - }, - }; - - // Add allowance - await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk([subdomainObj]) - ).to.be.revertedWithCustomError(zns.subRegistrar, ZERO_PARENTHASH_ERR); - }); - - it("Should register a mix of nested and non-nested subdomains and validates hashes", async () => { - // Structure of domains (- rootDomain; + subdomain): - // - // - rootHash - // + nested0 - // + nested1 - // + nested2 - // + nested3 - // - specific0parent - // + non0nested0with0specific0parent0 - // + non0nested0with0specific0parent1 - // + non0nested0with0specific0parent2 - - const subRegistrations : Array = []; - const expectedHashes : Array = []; - const labels = [ - "nested0", - "nested1", - "nested2", - "nested3", - "non0nested0with0specific0parent0", - "non0nested0with0specific0parent1", - "non0nested0with0specific0parent2", - ]; - - const specificParentHash = await registrationWithSetup({ - zns, - user: specificRootOwner, - domainLabel: "specific0parent", - fullConfig: { - distrConfig: { - accessType: AccessType.OPEN, - pricerContract: await zns.fixedPricer.getAddress(), - paymentType: PaymentType.DIRECT, - priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, - }, - paymentConfig: { - token: await zns.meowToken.getAddress(), - beneficiary: specificRootOwner.address, - }, - }, - }); - - for (let i = 0; i < labels.length; i++) { - let parentHash; - let referenceParentHash; - - if (i === 0) { - parentHash = domain.hash; - referenceParentHash = parentHash; - } else if (i > 0 && i < 5) { - parentHash = ethers.ZeroHash; - referenceParentHash = expectedHashes[i - 1]; - } else { - parentHash = specificParentHash; - referenceParentHash = parentHash; - } - - expectedHashes.push( - await zns.subRegistrar.hashWithParent(referenceParentHash, labels[i]) - ); - - subRegistrations.push({ - parentHash, - label: labels[i], - domainAddress: ethers.ZeroAddress, - tokenOwner: ethers.ZeroAddress, - tokenURI: `uri${i}`, - distrConfig: { - pricerContract: ethers.ZeroAddress, - paymentType: 0n, - accessType: 0n, - priceConfig: hre.ethers.ZeroHash, - }, - paymentConfig: { - token: ethers.ZeroAddress, - beneficiary: ethers.ZeroAddress, - }, - }); - } - - const tx = await zns.subRegistrar.connect(specificSubOwner).registerSubdomainBulk(subRegistrations); - await tx.wait(); - - const subRegEventsLog = await getDomainRegisteredEvents({ - zns, - registrant: specificSubOwner.address, - }); - - // check with the events - expect(subRegEventsLog.length).to.equal(expectedHashes.length); - - for (let i = 0; i < labels.length; i++) { - const { - args: { - domainHash, - label, - tokenURI, - domainOwner, - tokenOwner, - }, - } = subRegEventsLog[i]; - - expect(domainHash).to.equal(expectedHashes[i]); - expect(label).to.equal(labels[i]); - expect(tokenURI).to.equal(subRegistrations[i].tokenURI); - expect(domainOwner).to.equal(specificSubOwner.address); - expect(tokenOwner).to.equal(specificSubOwner.address); - } - - // check with the records - for (let i = 0; i < subRegistrations.length; i++) { - let record; - // check, does a record exist - try { - record = await zns.registry.getDomainRecord(expectedHashes[i]); - } catch (e) { - expect.fail(`Domain record for hash ${expectedHashes[i]} not found`); - } - - // check the owner - expect(record.owner).to.eq(specificSubOwner.address); - } - }); - - it("Should revert when registering during a registration pause using #registerSubdomainBulk", async () => { - // pause the sub registrar - await zns.subRegistrar.connect(admin).pauseRegistration(); - expect(await zns.subRegistrar.registrationPaused()).to.be.true; - - const registrations : Array = [ - { - parentHash: domain.hash, - label: "subpaused", - domainAddress: lvl2SubOwner.address, - tokenOwner: ethers.ZeroAddress, - tokenURI: subTokenURI, - distrConfig: distrConfigEmpty, - paymentConfig: paymentConfigEmpty, - }, - ]; - - // try to register a subdomain - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk(registrations) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - REGISTRATION_PAUSED_ERR, - ); - - // unpause the sub registrar - await zns.subRegistrar.connect(admin).unpauseRegistration(); - expect(await zns.subRegistrar.registrationPaused()).to.be.false; - }); - }); - describe("Operations with domain paths", () => { let domainConfigs : Array; @@ -4282,191 +3911,6 @@ describe.only("ZNSSubRegistrar", () => { }); }); - describe("State setters", () => { - before(async () => { - [ - deployer, - admin, - random, - ] = await hre.ethers.getSigners(); - - zns = await deployZNS({ - deployer, - governorAddresses: [deployer.address], - adminAddresses: [admin.address], - }); - }); - - it("Should NOT let initialize the implementation contract", async () => { - const factory = new ZNSSubRegistrar__factory(deployer); - const impl = await getProxyImplAddress(await zns.subRegistrar.getAddress()); - const implContract = factory.attach(impl) as ZNSSubRegistrar; - - await expect( - implContract.initialize( - deployer.address, - deployer.address, - deployer.address, - ) - ).to.be.revertedWithCustomError(implContract, INITIALIZED_ERR); - }); - - it("#setRootRegistrar() should set the new root registrar correctly and emit #RootRegistrarSet event", async () => { - const tx = await zns.subRegistrar.connect(admin).setRootRegistrar(random.address); - - await expect(tx).to.emit(zns.subRegistrar, "RootRegistrarSet").withArgs(random.address); - - expect(await zns.subRegistrar.rootRegistrar()).to.equal(random.address); - }); - - it("#setRootRegistrar() should NOT be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).setRootRegistrar(random.address)) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#setRootRegistrar should NOT set registrar as 0x0 address", async () => { - await expect( - zns.subRegistrar.connect(admin).setRootRegistrar(ethers.ZeroAddress) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - ZERO_ADDRESS_ERR - ); - }); - - it("#setRegistry() should set the new registry correctly and emit #RegistrySet event", async () => { - const tx = await zns.subRegistrar.connect(admin).setRegistry(random.address); - - await expect(tx).to.emit(zns.subRegistrar, "RegistrySet").withArgs(random.address); - - expect(await zns.subRegistrar.registry()).to.equal(random.address); - }); - - it("#setRegistry() should not be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).setRegistry(random.address)) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#pauseRegistration() should pause the registration process and emit #RegistrationPauseSet event", async () => { - const tx = await zns.subRegistrar.connect(admin).pauseRegistration(); - - await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(true); - - expect(await zns.subRegistrar.registrationPaused()).to.equal(true); - }); - - it("#pauseRegistration() should not be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).pauseRegistration()) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#pauseRegistration() should not allow to pause if already paused", async () => { - await expect(zns.subRegistrar.connect(admin).pauseRegistration()) - .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); - }); - - // eslint-disable-next-line max-len - it("#unpauseRegistration() should unpause the registration process and emit #RegistrationPauseSet event", async () => { - const tx = await zns.subRegistrar.connect(admin).unpauseRegistration(); - - await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(false); - - expect(await zns.subRegistrar.registrationPaused()).to.equal(false); - }); - - it("#unpauseRegistration() should not be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).unpauseRegistration()) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#unpauseRegistration() should not allow to unpause if already unpaused", async () => { - await expect(zns.subRegistrar.connect(admin).unpauseRegistration()) - .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); - }); - - describe("#setAccessController", () => { - it("should allow ADMIN to set a valid AccessController", async () => { - await zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target); - - const currentAccessController = await zns.subRegistrar.getAccessController(); - - expect(currentAccessController).to.equal(zns.accessController.target); - }); - - it("should allow re-setting the AccessController to another valid contract", async () => { - expect( - await zns.subRegistrar.getAccessController() - ).to.equal( - zns.accessController.target - ); - - const ZNSAccessControllerFactory = await ethers.getContractFactory("ZNSAccessController", deployer); - const newAccessController = await ZNSAccessControllerFactory.deploy( - [deployer.address], - [deployer.address] - ); - - // then change the AccessController - await zns.subRegistrar.connect(deployer).setAccessController(newAccessController.target); - - expect( - await zns.subRegistrar.getAccessController() - ).to.equal( - newAccessController.target - ); - }); - - it("should emit AccessControllerSet event when setting a valid AccessController", async () => { - await expect( - zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target) - ).to.emit( - zns.subRegistrar, - "AccessControllerSet" - ).withArgs(zns.accessController.target); - }); - - it("should revert when a non-ADMIN tries to set AccessController", async () => { - await expect( - zns.subRegistrar.connect(lvl2SubOwner).setAccessController(zns.accessController.target) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_UNAUTHORIZED_ERR - ).withArgs(lvl2SubOwner.address, GOVERNOR_ROLE); - }); - - it("should revert when setting an AccessController as EOA address", async () => { - await expect( - zns.subRegistrar.connect(deployer).setAccessController(lvl2SubOwner.address) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(lvl2SubOwner.address); - }); - - it("should revert when setting an AccessController as another non-AC contract address", async () => { - await expect( - zns.subRegistrar.connect(deployer).setAccessController(zns.subRegistrar.target) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(zns.subRegistrar.target); - }); - - it("should revert when setting a zero address as AccessController", async () => { - // deployer is the governor - await expect( - zns.subRegistrar.connect(deployer).setAccessController(ethers.ZeroAddress) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(ethers.ZeroAddress); - }); - }); - }); - describe("UUPS", () => { let fixedPrice : bigint; diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts new file mode 100644 index 000000000..9a3e3d402 --- /dev/null +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -0,0 +1,623 @@ +import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; +import { expect } from "chai"; +import hre, { ethers } from "hardhat"; +import { IZNSContracts } from "../src/deploy/campaign/types"; +import { + AC_UNAUTHORIZED_ERR, + AC_WRONGADDRESS_ERR, + AccessType, + ADMIN_ROLE, DEFAULT_CURVE_PRICE_CONFIG_BYTES, DEFAULT_FIXED_PRICER_CONFIG_BYTES, DEFAULT_TOKEN_URI, deployZNS, + distrConfigEmpty, + encodePriceConfig, + getProxyImplAddress, + GOVERNOR_ROLE, + IDistributionConfig, + IFixedPriceConfig, + INITIALIZED_ERR, + ISubRegistrarConfig, + PAUSE_SAME_VALUE_ERR, + paymentConfigEmpty, + PaymentType, + REGISTRATION_PAUSED_ERR, + ZERO_ADDRESS_ERR, + ZERO_PARENTHASH_ERR, +} from "./helpers"; +import { ZNSSubRegistrar, ZNSSubRegistrar__factory } from "../typechain"; +import Domain from "./helpers/domain/domain"; +import { getDomainRegisteredEvents } from "./helpers/events"; +import { registrationWithSetup } from "./helpers/register-setup"; + + +describe("ZNSSubRegistrar Unit Tests", () => { + let deployer : SignerWithAddress; + let rootOwner : SignerWithAddress; + let specificRootOwner : SignerWithAddress; + let specificSubOwner : SignerWithAddress; + let admin : SignerWithAddress; + let lvl2SubOwner : SignerWithAddress; + let lvl3SubOwner : SignerWithAddress; + let random : SignerWithAddress; + + let zns : IZNSContracts; + + let rootPriceConfig : IFixedPriceConfig; + let defaultDistrConfig : IDistributionConfig; + const subTokenURI = "https://token-uri.com/8756a4b6f"; + + before (async () => { + [ + deployer, + admin, + random, + lvl2SubOwner, + rootOwner, + lvl3SubOwner, + specificRootOwner, + specificSubOwner, + ] = await hre.ethers.getSigners(); + + zns = await deployZNS({ + deployer, + governorAddresses: [deployer.address], + adminAddresses: [admin.address], + }); + + rootPriceConfig = { + price: ethers.parseEther("1375.612"), + feePercentage: BigInt(0), + }; + + defaultDistrConfig = { + pricerContract: zns.fixedPricer.target, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + priceConfig: encodePriceConfig(rootPriceConfig), + }; + + await Promise.all( + [ + deployer, + admin, + random, + lvl2SubOwner, + rootOwner, + lvl3SubOwner, + specificRootOwner, + specificSubOwner, + ].map(async ({ address }) => + zns.meowToken.mint(address, ethers.parseEther("100000000000000"))) + ); + }); + + describe("State setters", () => { + it("Should NOT let initialize the implementation contract", async () => { + const factory = new ZNSSubRegistrar__factory(deployer); + const impl = await getProxyImplAddress(await zns.subRegistrar.getAddress()); + const implContract = factory.attach(impl) as ZNSSubRegistrar; + + await expect( + implContract.initialize( + deployer.address, + deployer.address, + deployer.address, + ) + ).to.be.revertedWithCustomError(implContract, INITIALIZED_ERR); + }); + + it("#setRootRegistrar() should set the new root registrar correctly and emit #RootRegistrarSet event", async () => { + const tx = await zns.subRegistrar.connect(admin).setRootRegistrar(random.address); + + await expect(tx).to.emit(zns.subRegistrar, "RootRegistrarSet").withArgs(random.address); + + expect(await zns.subRegistrar.rootRegistrar()).to.equal(random.address); + }); + + it("#setRootRegistrar() should NOT be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).setRootRegistrar(random.address)) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("#setRootRegistrar should NOT set registrar as 0x0 address", async () => { + await expect( + zns.subRegistrar.connect(admin).setRootRegistrar(ethers.ZeroAddress) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + ZERO_ADDRESS_ERR + ); + }); + + it("#setRegistry() should set the new registry correctly and emit #RegistrySet event", async () => { + const tx = await zns.subRegistrar.connect(admin).setRegistry(random.address); + + await expect(tx).to.emit(zns.subRegistrar, "RegistrySet").withArgs(random.address); + + expect(await zns.subRegistrar.registry()).to.equal(random.address); + }); + + it("#setRegistry() should not be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).setRegistry(random.address)) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("#pauseRegistration() should pause the registration process and emit #RegistrationPauseSet event", async () => { + const tx = await zns.subRegistrar.connect(admin).pauseRegistration(); + + await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(true); + + expect(await zns.subRegistrar.registrationPaused()).to.equal(true); + }); + + it("#pauseRegistration() should not be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).pauseRegistration()) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("#pauseRegistration() should not allow to pause if already paused", async () => { + await expect(zns.subRegistrar.connect(admin).pauseRegistration()) + .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); + }); + + // eslint-disable-next-line max-len + it("#unpauseRegistration() should unpause the registration process and emit #RegistrationPauseSet event", async () => { + const tx = await zns.subRegistrar.connect(admin).unpauseRegistration(); + + await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(false); + + expect(await zns.subRegistrar.registrationPaused()).to.equal(false); + }); + + it("#unpauseRegistration() should not be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).unpauseRegistration()) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("#unpauseRegistration() should not allow to unpause if already unpaused", async () => { + await expect(zns.subRegistrar.connect(admin).unpauseRegistration()) + .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); + }); + + describe("#setAccessController", () => { + it("should allow ADMIN to set a valid AccessController", async () => { + await zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target); + + const currentAccessController = await zns.subRegistrar.getAccessController(); + + expect(currentAccessController).to.equal(zns.accessController.target); + }); + + it("should allow re-setting the AccessController to another valid contract", async () => { + expect( + await zns.subRegistrar.getAccessController() + ).to.equal( + zns.accessController.target + ); + + const ZNSAccessControllerFactory = await ethers.getContractFactory("ZNSAccessController", deployer); + const newAccessController = await ZNSAccessControllerFactory.deploy( + [deployer.address], + [deployer.address] + ); + + // then change the AccessController + await zns.subRegistrar.connect(deployer).setAccessController(newAccessController.target); + + expect( + await zns.subRegistrar.getAccessController() + ).to.equal( + newAccessController.target + ); + }); + + it("should emit AccessControllerSet event when setting a valid AccessController", async () => { + await expect( + zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target) + ).to.emit( + zns.subRegistrar, + "AccessControllerSet" + ).withArgs(zns.accessController.target); + }); + + it("should revert when a non-ADMIN tries to set AccessController", async () => { + await expect( + zns.subRegistrar.connect(lvl2SubOwner).setAccessController(zns.accessController.target) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_UNAUTHORIZED_ERR + ).withArgs(lvl2SubOwner.address, GOVERNOR_ROLE); + }); + + it("should revert when setting an AccessController as EOA address", async () => { + await expect( + zns.subRegistrar.connect(deployer).setAccessController(lvl2SubOwner.address) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(lvl2SubOwner.address); + }); + + it("should revert when setting an AccessController as another non-AC contract address", async () => { + await expect( + zns.subRegistrar.connect(deployer).setAccessController(zns.subRegistrar.target) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(zns.subRegistrar.target); + }); + + it("should revert when setting a zero address as AccessController", async () => { + // deployer is the governor + await expect( + zns.subRegistrar.connect(deployer).setAccessController(ethers.ZeroAddress) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(ethers.ZeroAddress); + }); + }); + }); + + describe("Bulk Subdomain Registration", () => { + let defaultDomain : Domain; + + before(async () => { + defaultDomain = new Domain({ + zns, + domainConfig: { + owner: rootOwner, + label: "root1bulk", + parentHash: ethers.ZeroHash, + tokenOwner: rootOwner.address, + tokenURI: DEFAULT_TOKEN_URI, + distrConfig: defaultDistrConfig, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + }); + await defaultDomain.register(); + }); + + it("Should #registerSubdomainBulk and the event must be triggered", async () => { + const registrations : Array = []; + + for (let i = 0; i < 5; i++) { + const isOdd = i % 2 !== 0; + + const subdomainObj : ISubRegistrarConfig = { + parentHash: defaultDomain.hash, + label: `subdomain${i + 1}`, + domainAddress: admin.address, + tokenOwner: ethers.ZeroAddress, + tokenURI: `0://tokenURI_${i + 1}`, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + paymentType: isOdd ? PaymentType.STAKE : PaymentType.DIRECT, + accessType: isOdd ? AccessType.LOCKED : AccessType.OPEN, + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: isOdd ? admin.address : lvl2SubOwner.address, + }, + }; + + registrations.push(subdomainObj); + } + + // Add allowance + await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); + + await zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk(registrations); + + // get by `registrant` + const logs = await getDomainRegisteredEvents({ + zns, + registrant: lvl2SubOwner.address, + }); + + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = logs.length - 1; i === 0; i--) { + const subdomain = registrations[i]; + + const domainHashExpected = await zns.subRegistrar.hashWithParent( + subdomain.parentHash, + subdomain.label + ); + + // "DomainRegistered" event log + const { parentHash, domainHash, label, tokenOwner, tokenURI, domainOwner, domainAddress } = logs[i].args; + + expect(parentHash).to.eq(defaultDomain.hash); + expect(domainHashExpected).to.eq(domainHash); + expect(label).to.eq(subdomain.label); + expect(tokenURI).to.eq(subdomain.tokenURI); + expect(tokenOwner).to.eq(domainOwner); + expect(domainOwner).to.eq(lvl2SubOwner.address); + expect(domainAddress).to.eq(subdomain.domainAddress); + } + }); + + it("Should register multiple NESTED subdomains using #registerSubdomainBulk", async () => { + const registrations : Array = []; + const parentHashes : Array = []; + + // how many nested domains (0://root.sub1.sub2.sub3....) + const domainLevels = 15; + + for (let i = 0; i < domainLevels; i++) { + const isOdd = i % 2 !== 0; + + const subdomainObj : ISubRegistrarConfig = { + parentHash: defaultDomain.hash, + label: `sub${i + 1}`, + domainAddress: lvl3SubOwner.address, + tokenOwner: ethers.ZeroAddress, + tokenURI: `0://tokenURI_${i + 1}`, + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + paymentType: isOdd ? PaymentType.STAKE : PaymentType.DIRECT, + accessType: isOdd ? AccessType.LOCKED : AccessType.OPEN, + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: isOdd ? lvl3SubOwner.address : lvl2SubOwner.address, + }, + }; + + if (i > 0) subdomainObj.parentHash = ethers.ZeroHash; + + registrations.push(subdomainObj); + + // first goes with rootHash + parentHashes.push( + await zns.subRegistrar.hashWithParent( + i === 0 ? defaultDomain.hash : parentHashes[i - 1], + subdomainObj.label + ) + ); + } + + // Add allowance + await zns.meowToken.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); + + await zns.subRegistrar.connect(lvl3SubOwner).registerSubdomainBulk(registrations); + + const logs = await getDomainRegisteredEvents({ + zns, + registrant: lvl3SubOwner.address, + }); + + for (let i = 0; i < domainLevels; i++) { + const subdomain = registrations[i]; + + // "DomainRegistered" event log + const { parentHash, domainHash, label, tokenURI, tokenOwner, domainOwner, domainAddress } = logs[i].args; + + i > 0 ? + expect(parentHash).to.eq(parentHashes[i - 1]) : + expect(parentHash).to.eq(defaultDomain.hash); + expect(domainHash).to.eq(parentHashes[i]); + expect(label).to.eq(subdomain.label); + expect(tokenURI).to.eq(subdomain.tokenURI); + expect(domainOwner).to.eq(lvl3SubOwner.address); + expect(tokenOwner).to.eq(lvl3SubOwner.address); + expect(domainAddress).to.eq(subdomain.domainAddress); + } + }); + + it("Should revert when register the same domain twice using #registerSubdomainBulk", async () => { + const subdomainObj : ISubRegistrarConfig = { + parentHash: defaultDomain.hash, + label: "subdomain1", + domainAddress: admin.address, + tokenOwner: ethers.ZeroAddress, + tokenURI: "0://tokenURI", + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + paymentType: PaymentType.STAKE, + accessType: AccessType.LOCKED, + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: admin.address, + }, + }; + + // Add allowance + await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); + + await expect( + zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk([subdomainObj, subdomainObj]) + ).to.be.revertedWithCustomError(zns.rootRegistrar, "DomainAlreadyExists"); + }); + + it("Should revert with 'ZeroAddressPassed' error when 1st subdomain in the array has zerohash", async () => { + const subdomainObj : ISubRegistrarConfig = { + parentHash: ethers.ZeroHash, + label: "subdomainzeroaAddresspassed", + domainAddress: admin.address, + tokenOwner: ethers.ZeroAddress, + tokenURI: "0://tokenURI", + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + paymentType: PaymentType.STAKE, + accessType: AccessType.LOCKED, + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: admin.address, + }, + }; + + // Add allowance + await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); + + await expect( + zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk([subdomainObj]) + ).to.be.revertedWithCustomError(zns.subRegistrar, ZERO_PARENTHASH_ERR); + }); + + it("Should register a mix of nested and non-nested subdomains and validates hashes", async () => { + // Structure of domains (- rootDomain; + subdomain): + // + // - rootHash + // + nested0 + // + nested1 + // + nested2 + // + nested3 + // - specific0parent + // + non0nested0with0specific0parent0 + // + non0nested0with0specific0parent1 + // + non0nested0with0specific0parent2 + + const subRegistrations : Array = []; + const expectedHashes : Array = []; + const labels = [ + "nested0", + "nested1", + "nested2", + "nested3", + "non0nested0with0specific0parent0", + "non0nested0with0specific0parent1", + "non0nested0with0specific0parent2", + ]; + + const specificParentHash = await registrationWithSetup({ + zns, + user: specificRootOwner, + domainLabel: "specific0parent", + fullConfig: { + distrConfig: { + accessType: AccessType.OPEN, + pricerContract: await zns.fixedPricer.getAddress(), + paymentType: PaymentType.DIRECT, + priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: specificRootOwner.address, + }, + }, + }); + + for (let i = 0; i < labels.length; i++) { + let parentHash; + let referenceParentHash; + + if (i === 0) { + parentHash = defaultDomain.hash; + referenceParentHash = parentHash; + } else if (i > 0 && i < 5) { + parentHash = ethers.ZeroHash; + referenceParentHash = expectedHashes[i - 1]; + } else { + parentHash = specificParentHash; + referenceParentHash = parentHash; + } + + expectedHashes.push( + await zns.subRegistrar.hashWithParent(referenceParentHash, labels[i]) + ); + + subRegistrations.push({ + parentHash, + label: labels[i], + domainAddress: ethers.ZeroAddress, + tokenOwner: ethers.ZeroAddress, + tokenURI: `uri${i}`, + distrConfig: { + pricerContract: ethers.ZeroAddress, + paymentType: 0n, + accessType: 0n, + priceConfig: hre.ethers.ZeroHash, + }, + paymentConfig: { + token: ethers.ZeroAddress, + beneficiary: ethers.ZeroAddress, + }, + }); + } + + const tx = await zns.subRegistrar.connect(specificSubOwner).registerSubdomainBulk(subRegistrations); + await tx.wait(); + + const subRegEventsLog = await getDomainRegisteredEvents({ + zns, + registrant: specificSubOwner.address, + }); + + // check with the events + expect(subRegEventsLog.length).to.equal(expectedHashes.length); + + for (let i = 0; i < labels.length; i++) { + const { + args: { + domainHash, + label, + tokenURI, + domainOwner, + tokenOwner, + }, + } = subRegEventsLog[i]; + + expect(domainHash).to.equal(expectedHashes[i]); + expect(label).to.equal(labels[i]); + expect(tokenURI).to.equal(subRegistrations[i].tokenURI); + expect(domainOwner).to.equal(specificSubOwner.address); + expect(tokenOwner).to.equal(specificSubOwner.address); + } + + // check with the records + for (let i = 0; i < subRegistrations.length; i++) { + let record; + // check, does a record exist + try { + record = await zns.registry.getDomainRecord(expectedHashes[i]); + } catch (e) { + expect.fail(`Domain record for hash ${expectedHashes[i]} not found`); + } + + // check the owner + expect(record.owner).to.eq(specificSubOwner.address); + } + }); + + it("Should revert when registering during a registration pause using #registerSubdomainBulk", async () => { + // pause the sub registrar + await zns.subRegistrar.connect(admin).pauseRegistration(); + expect(await zns.subRegistrar.registrationPaused()).to.be.true; + + const registrations : Array = [ + { + parentHash: defaultDomain.hash, + label: "subpaused", + domainAddress: lvl2SubOwner.address, + tokenOwner: ethers.ZeroAddress, + tokenURI: subTokenURI, + distrConfig: distrConfigEmpty, + paymentConfig: paymentConfigEmpty, + }, + ]; + + // try to register a subdomain + await expect( + zns.subRegistrar.connect(lvl2SubOwner).registerSubdomainBulk(registrations) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + REGISTRATION_PAUSED_ERR, + ); + + // unpause the sub registrar + await zns.subRegistrar.connect(admin).unpauseRegistration(); + expect(await zns.subRegistrar.registrationPaused()).to.be.false; + }); + }); +}); \ No newline at end of file From 985885ab48edf0ae8d70d2988a32395ec51fd4cd Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Mon, 29 Sep 2025 18:41:45 -0700 Subject: [PATCH 16/26] Moved more unit tests to appropriated module. Corrected order of tests. Adjusted distrConfig setter for Domain class. WIP --- test/ZNSSubRegistrar.test.ts | 211 +--------- test/ZNSSubRegistrar.unit.test.ts | 632 ++++++++++++++++++++++-------- test/helpers/domain/domain.ts | 9 +- 3 files changed, 467 insertions(+), 385 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 5fdff5942..12357709a 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -58,7 +58,7 @@ import { ZeroHash } from "ethers"; import { IFullDomainConfig } from "./helpers/domain/types"; -describe.only("ZNSSubRegistrar", () => { +describe("ZNSSubRegistrar", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -3662,215 +3662,6 @@ describe.only("ZNSSubRegistrar", () => { ); }); - describe("#setDistributionConfigForDomain()", () => { - it("should re-set distribution config for an existing subdomain", async () => { - const domainHash = regResults[2].domainHash; - - const distrConfigBefore = await zns.subRegistrar.distrConfigs(domainHash); - expect(distrConfigBefore.accessType).to.not.eq(AccessType.MINTLIST); - expect(distrConfigBefore.pricerContract).to.not.eq(await zns.fixedPricer.getAddress()); - expect( - distrConfigBefore.paymentType - ).to.not.eq( - PaymentType.STAKE - ); - - const newConfig = { - pricerContract: await zns.fixedPricer.getAddress(), - priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, - paymentType: PaymentType.STAKE, - accessType: AccessType.MINTLIST, - }; - - await zns.subRegistrar.connect(lvl3SubOwner).setDistributionConfigForDomain( - domainHash, - newConfig, - ); - - const distrConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); - expect(distrConfigAfter.accessType).to.eq(newConfig.accessType); - expect(distrConfigAfter.pricerContract).to.eq(newConfig.pricerContract); - expect(distrConfigAfter.paymentType).to.eq(newConfig.paymentType); - - // assign operator in registry - await zns.registry.connect(lvl3SubOwner).setOwnersOperator( - operator.address, - true, - ); - - // reset it back - await zns.subRegistrar.connect(operator).setDistributionConfigForDomain( - domainHash, - domainConfigs[2].fullConfig.distrConfig, - ); - const origConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); - expect(origConfigAfter.accessType).to.eq(domainConfigs[2].fullConfig.distrConfig.accessType); - expect(origConfigAfter.pricerContract).to.eq(domainConfigs[2].fullConfig.distrConfig.pricerContract); - expect( - origConfigAfter.paymentType - ).to.eq( - domainConfigs[2].fullConfig.distrConfig.paymentType - ); - - // remove operator - await zns.registry.connect(lvl3SubOwner).setOwnersOperator( - operator.address, - false, - ); - }); - - it("should NOT allow to set distribution config for a non-authorized account", async () => { - const domainHash = regResults[1].domainHash; - - const newConfig = { - pricerContract: await zns.curvePricer.getAddress(), - priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, - paymentType: PaymentType.STAKE, - accessType: AccessType.MINTLIST, - }; - - await expect( - zns.subRegistrar.connect(deployer).setDistributionConfigForDomain( - domainHash, - newConfig - ) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - NOT_AUTHORIZED_ERR - ); - }); - - it("should revert if pricerContract is passed as 0x0 address", async () => { - const domainHash = regResults[2].domainHash; - - const newConfig = { - pricerContract: ethers.ZeroAddress, - priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, - paymentType: PaymentType.STAKE, - accessType: AccessType.MINTLIST, - }; - - await expect( - zns.subRegistrar.connect(lvl3SubOwner).setDistributionConfigForDomain( - domainHash, - newConfig - ) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - ZERO_ADDRESS_ERR - ); - }); - }); - - describe("#setPricerDataForDomain()", () => { - it("should re-set pricer contract for an existing subdomain", async () => { - const domainHash = regResults[2].domainHash; - - const pricerContractBefore = await zns.subRegistrar.distrConfigs(domainHash); - expect(pricerContractBefore.pricerContract).to.eq(domainConfigs[2].fullConfig.distrConfig.pricerContract); - - await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( - domainHash, - DEFAULT_CURVE_PRICE_CONFIG_BYTES, - await zns.curvePricer.getAddress(), - ); - - const pricerContractAfter = await zns.subRegistrar.distrConfigs(domainHash); - expect(pricerContractAfter.pricerContract).to.eq(await zns.curvePricer.getAddress()); - - // reset it back - await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( - domainHash, - domainConfigs[2].fullConfig.distrConfig.priceConfig, - domainConfigs[2].fullConfig.distrConfig.pricerContract, - ); - }); - - it("should NOT allow setting for non-authorized account", async () => { - const domainHash = regResults[2].domainHash; - - await expect( - zns.subRegistrar.connect(lvl2SubOwner).setPricerDataForDomain( - domainHash, - DEFAULT_CURVE_PRICE_CONFIG_BYTES, - await zns.curvePricer.getAddress() - ) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - NOT_AUTHORIZED_ERR - ); - }); - - it("should NOT set pricerContract to 0x0 address", async () => { - const domainHash = regResults[2].domainHash; - - await expect( - zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( - domainHash, - DEFAULT_FIXED_PRICER_CONFIG_BYTES, - ethers.ZeroAddress - ) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - ZERO_ADDRESS_ERR - ); - }); - }); - - describe("#setPaymentTypeForDomain()", () => { - it("should re-set payment type for an existing subdomain", async () => { - const domainHash = regResults[2].domainHash; - - const { paymentType: paymentTypeBefore } = await zns.subRegistrar.distrConfigs(domainHash); - expect(paymentTypeBefore).to.eq(domainConfigs[2].fullConfig.distrConfig.paymentType); - - await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - PaymentType.STAKE, - ); - - const { paymentType: paymentTypeAfter } = await zns.subRegistrar.distrConfigs(domainHash); - expect(paymentTypeAfter).to.eq(PaymentType.STAKE); - - // reset it back - await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - domainConfigs[2].fullConfig.distrConfig.paymentType, - ); - }); - - it("should NOT allow setting for non-authorized account", async () => { - const domainHash = regResults[2].domainHash; - - await expect( - zns.subRegistrar.connect(lvl2SubOwner).setPaymentTypeForDomain(domainHash, PaymentType.STAKE) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - NOT_AUTHORIZED_ERR - ); - }); - - it("should emit #PaymentTypeSet event with correct params", async () => { - const domainHash = regResults[2].domainHash; - - await expect( - zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - PaymentType.STAKE, - ) - ).to.emit(zns.subRegistrar, "PaymentTypeSet").withArgs( - domainHash, - PaymentType.STAKE, - ); - - // reset back - await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - domainConfigs[2].fullConfig.distrConfig.paymentType, - ); - }); - }); - // eslint-disable-next-line max-len it("should TRANSFER ownership of a subdomain and let the receiver revoke with REFUND", async () => { const { amount: stakedBefore } = await zns.treasury.stakedForDomain(regResults[1].domainHash); diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 9a3e3d402..2c1d56a1d 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -15,6 +15,7 @@ import { IFixedPriceConfig, INITIALIZED_ERR, ISubRegistrarConfig, + NOT_AUTHORIZED_ERR, PAUSE_SAME_VALUE_ERR, paymentConfigEmpty, PaymentType, @@ -26,9 +27,10 @@ import { ZNSSubRegistrar, ZNSSubRegistrar__factory } from "../typechain"; import Domain from "./helpers/domain/domain"; import { getDomainRegisteredEvents } from "./helpers/events"; import { registrationWithSetup } from "./helpers/register-setup"; +import { IFullDomainConfig } from "./helpers/domain/types"; -describe("ZNSSubRegistrar Unit Tests", () => { +describe.only("ZNSSubRegistrar Unit Tests", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; @@ -37,6 +39,7 @@ describe("ZNSSubRegistrar Unit Tests", () => { let lvl2SubOwner : SignerWithAddress; let lvl3SubOwner : SignerWithAddress; let random : SignerWithAddress; + let operator : SignerWithAddress; let zns : IZNSContracts; @@ -44,6 +47,14 @@ describe("ZNSSubRegistrar Unit Tests", () => { let defaultDistrConfig : IDistributionConfig; const subTokenURI = "https://token-uri.com/8756a4b6f"; + let fixedFeePercentage : bigint; + let fixedPrice : bigint; + let priceConfigBytes : string; + + let domainConfigs : Array; + const registeredDomainHashes : Array = []; + const domains : Array = []; + before (async () => { [ deployer, @@ -54,6 +65,7 @@ describe("ZNSSubRegistrar Unit Tests", () => { lvl3SubOwner, specificRootOwner, specificSubOwner, + operator, ] = await hre.ethers.getSigners(); zns = await deployZNS({ @@ -85,179 +97,22 @@ describe("ZNSSubRegistrar Unit Tests", () => { specificRootOwner, specificSubOwner, ].map(async ({ address }) => - zns.meowToken.mint(address, ethers.parseEther("100000000000000"))) + zns.meowToken.mint(address, ethers.parseEther("1000000000000000000000000"))) ); }); - describe("State setters", () => { - it("Should NOT let initialize the implementation contract", async () => { - const factory = new ZNSSubRegistrar__factory(deployer); - const impl = await getProxyImplAddress(await zns.subRegistrar.getAddress()); - const implContract = factory.attach(impl) as ZNSSubRegistrar; - - await expect( - implContract.initialize( - deployer.address, - deployer.address, - deployer.address, - ) - ).to.be.revertedWithCustomError(implContract, INITIALIZED_ERR); - }); - - it("#setRootRegistrar() should set the new root registrar correctly and emit #RootRegistrarSet event", async () => { - const tx = await zns.subRegistrar.connect(admin).setRootRegistrar(random.address); - - await expect(tx).to.emit(zns.subRegistrar, "RootRegistrarSet").withArgs(random.address); - - expect(await zns.subRegistrar.rootRegistrar()).to.equal(random.address); - }); - - it("#setRootRegistrar() should NOT be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).setRootRegistrar(random.address)) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#setRootRegistrar should NOT set registrar as 0x0 address", async () => { - await expect( - zns.subRegistrar.connect(admin).setRootRegistrar(ethers.ZeroAddress) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - ZERO_ADDRESS_ERR - ); - }); - - it("#setRegistry() should set the new registry correctly and emit #RegistrySet event", async () => { - const tx = await zns.subRegistrar.connect(admin).setRegistry(random.address); - - await expect(tx).to.emit(zns.subRegistrar, "RegistrySet").withArgs(random.address); - - expect(await zns.subRegistrar.registry()).to.equal(random.address); - }); - - it("#setRegistry() should not be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).setRegistry(random.address)) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#pauseRegistration() should pause the registration process and emit #RegistrationPauseSet event", async () => { - const tx = await zns.subRegistrar.connect(admin).pauseRegistration(); - - await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(true); - - expect(await zns.subRegistrar.registrationPaused()).to.equal(true); - }); - - it("#pauseRegistration() should not be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).pauseRegistration()) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#pauseRegistration() should not allow to pause if already paused", async () => { - await expect(zns.subRegistrar.connect(admin).pauseRegistration()) - .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); - }); - - // eslint-disable-next-line max-len - it("#unpauseRegistration() should unpause the registration process and emit #RegistrationPauseSet event", async () => { - const tx = await zns.subRegistrar.connect(admin).unpauseRegistration(); - - await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(false); - - expect(await zns.subRegistrar.registrationPaused()).to.equal(false); - }); - - it("#unpauseRegistration() should not be callable by anyone other than ADMIN_ROLE", async () => { - await expect(zns.subRegistrar.connect(random).unpauseRegistration()) - .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) - .withArgs(random.address, ADMIN_ROLE); - }); - - it("#unpauseRegistration() should not allow to unpause if already unpaused", async () => { - await expect(zns.subRegistrar.connect(admin).unpauseRegistration()) - .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); - }); - - describe("#setAccessController", () => { - it("should allow ADMIN to set a valid AccessController", async () => { - await zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target); - - const currentAccessController = await zns.subRegistrar.getAccessController(); - - expect(currentAccessController).to.equal(zns.accessController.target); - }); - - it("should allow re-setting the AccessController to another valid contract", async () => { - expect( - await zns.subRegistrar.getAccessController() - ).to.equal( - zns.accessController.target - ); - - const ZNSAccessControllerFactory = await ethers.getContractFactory("ZNSAccessController", deployer); - const newAccessController = await ZNSAccessControllerFactory.deploy( - [deployer.address], - [deployer.address] - ); - - // then change the AccessController - await zns.subRegistrar.connect(deployer).setAccessController(newAccessController.target); - - expect( - await zns.subRegistrar.getAccessController() - ).to.equal( - newAccessController.target - ); - }); - - it("should emit AccessControllerSet event when setting a valid AccessController", async () => { - await expect( - zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target) - ).to.emit( - zns.subRegistrar, - "AccessControllerSet" - ).withArgs(zns.accessController.target); - }); - - it("should revert when a non-ADMIN tries to set AccessController", async () => { - await expect( - zns.subRegistrar.connect(lvl2SubOwner).setAccessController(zns.accessController.target) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_UNAUTHORIZED_ERR - ).withArgs(lvl2SubOwner.address, GOVERNOR_ROLE); - }); - - it("should revert when setting an AccessController as EOA address", async () => { - await expect( - zns.subRegistrar.connect(deployer).setAccessController(lvl2SubOwner.address) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(lvl2SubOwner.address); - }); - - it("should revert when setting an AccessController as another non-AC contract address", async () => { - await expect( - zns.subRegistrar.connect(deployer).setAccessController(zns.subRegistrar.target) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(zns.subRegistrar.target); - }); - - it("should revert when setting a zero address as AccessController", async () => { - // deployer is the governor - await expect( - zns.subRegistrar.connect(deployer).setAccessController(ethers.ZeroAddress) - ).to.be.revertedWithCustomError( - zns.subRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(ethers.ZeroAddress); - }); - }); + it("Should NOT let initialize the implementation contract", async () => { + const factory = new ZNSSubRegistrar__factory(deployer); + const impl = await getProxyImplAddress(await zns.subRegistrar.getAddress()); + const implContract = factory.attach(impl) as ZNSSubRegistrar; + + await expect( + implContract.initialize( + deployer.address, + deployer.address, + deployer.address, + ) + ).to.be.revertedWithCustomError(implContract, INITIALIZED_ERR); }); describe("Bulk Subdomain Registration", () => { @@ -279,6 +134,7 @@ describe("ZNSSubRegistrar Unit Tests", () => { }, }, }); + await defaultDomain.register(); }); @@ -620,4 +476,438 @@ describe("ZNSSubRegistrar Unit Tests", () => { expect(await zns.subRegistrar.registrationPaused()).to.be.false; }); }); + + describe("State setters", () => { + before (async () => { + fixedPrice = ethers.parseEther("397"); + fixedFeePercentage = BigInt(200); + priceConfigBytes = encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }); + + domainConfigs = [ + { + owner: rootOwner, + tokenOwner: rootOwner.address, + label: "root", + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: encodePriceConfig({ price: fixedPrice, feePercentage: fixedFeePercentage }), + paymentType: PaymentType.STAKE, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: rootOwner.address, + }, + }, + { + owner: lvl2SubOwner, + tokenOwner: lvl2SubOwner.address, + label: "leveltwo", + tokenURI: "http://example.com/leveltwo", + distrConfig: { + pricerContract: await zns.fixedPricer.getAddress(), + priceConfig: priceConfigBytes, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl2SubOwner.address, + }, + }, + { + owner: lvl3SubOwner, + tokenOwner: lvl3SubOwner.address, + label: "lvlthree", + tokenURI: "http://example.com/lvlthree", + distrConfig: { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.DIRECT, + accessType: AccessType.OPEN, + }, + paymentConfig: { + token: await zns.meowToken.getAddress(), + beneficiary: lvl3SubOwner.address, + }, + }, + ]; + + for (const element of domainConfigs) { + const domain = new Domain({ zns, domainConfig: element }); + await domain.register(); + + registeredDomainHashes.push(domain.hash); + domains.push(domain); + } + }); + + describe("#setDistributionConfigForDomain()", () => { + it("should re-set distribution config for an existing subdomain", async () => { + const domainHash = registeredDomainHashes[2]; + + const distrConfigBefore = await zns.subRegistrar.distrConfigs(domainHash); + expect(distrConfigBefore.accessType).to.not.eq(AccessType.MINTLIST); + expect(distrConfigBefore.pricerContract).to.not.eq(await zns.fixedPricer.getAddress()); + expect( + distrConfigBefore.paymentType + ).to.not.eq( + PaymentType.STAKE + ); + + const newConfig = { + pricerContract: await zns.fixedPricer.getAddress(), + paymentType: PaymentType.STAKE, + accessType: AccessType.MINTLIST, + priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, + }; + + await domains[2].setDistributionConfigForDomain(newConfig); + + const distrConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); + expect(distrConfigAfter.accessType).to.eq(newConfig.accessType); + expect(distrConfigAfter.pricerContract).to.eq(newConfig.pricerContract); + expect(distrConfigAfter.paymentType).to.eq(newConfig.paymentType); + + // assign operator in registry + await zns.registry.connect(lvl3SubOwner).setOwnersOperator( + operator.address, + true, + ); + + // reset it back + await zns.subRegistrar.connect(operator).setDistributionConfigForDomain( + domainHash, + domainConfigs[2].distrConfig, + ); + const origConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); + expect(origConfigAfter.accessType).to.eq(domainConfigs[2].distrConfig.accessType); + expect(origConfigAfter.pricerContract).to.eq(domainConfigs[2].distrConfig.pricerContract); + expect( + origConfigAfter.paymentType + ).to.eq( + domainConfigs[2].distrConfig.paymentType + ); + + // remove operator + await zns.registry.connect(lvl3SubOwner).setOwnersOperator( + operator.address, + false, + ); + }); + + it("should NOT allow to set distribution config for a non-authorized account", async () => { + const domainHash = registeredDomainHashes[1]; + + const newConfig = { + pricerContract: await zns.curvePricer.getAddress(), + priceConfig: DEFAULT_CURVE_PRICE_CONFIG_BYTES, + paymentType: PaymentType.STAKE, + accessType: AccessType.MINTLIST, + }; + + await expect( + zns.subRegistrar.connect(deployer).setDistributionConfigForDomain( + domainHash, + newConfig + ) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + NOT_AUTHORIZED_ERR + ); + }); + + it("should revert if pricerContract is passed as 0x0 address", async () => { + const domainHash = registeredDomainHashes[2]; + + const newConfig = { + pricerContract: ethers.ZeroAddress, + priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, + paymentType: PaymentType.STAKE, + accessType: AccessType.MINTLIST, + }; + + await expect( + zns.subRegistrar.connect(lvl3SubOwner).setDistributionConfigForDomain( + domainHash, + newConfig + ) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + ZERO_ADDRESS_ERR + ); + }); + }); + + describe("#setPricerDataForDomain()", () => { + it("should re-set pricer contract for an existing subdomain", async () => { + const domainHash = registeredDomainHashes[2]; + + const pricerContractBefore = await zns.subRegistrar.distrConfigs(domainHash); + expect(pricerContractBefore.pricerContract).to.eq(domainConfigs[2].distrConfig.pricerContract); + + await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( + domainHash, + DEFAULT_CURVE_PRICE_CONFIG_BYTES, + await zns.curvePricer.getAddress(), + ); + + const pricerContractAfter = await zns.subRegistrar.distrConfigs(domainHash); + expect(pricerContractAfter.pricerContract).to.eq(await zns.curvePricer.getAddress()); + + // reset it back + await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( + domainHash, + domainConfigs[2].distrConfig.priceConfig, + domainConfigs[2].distrConfig.pricerContract, + ); + }); + + it("should NOT allow setting for non-authorized account", async () => { + const domainHash = registeredDomainHashes[2]; + + await expect( + zns.subRegistrar.connect(lvl2SubOwner).setPricerDataForDomain( + domainHash, + DEFAULT_CURVE_PRICE_CONFIG_BYTES, + await zns.curvePricer.getAddress() + ) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + NOT_AUTHORIZED_ERR + ); + }); + + it("should NOT set pricerContract to 0x0 address", async () => { + const domainHash = registeredDomainHashes[2]; + + await expect( + zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( + domainHash, + DEFAULT_FIXED_PRICER_CONFIG_BYTES, + ethers.ZeroAddress + ) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + ZERO_ADDRESS_ERR + ); + }); + }); + + describe("#setPaymentTypeForDomain()", () => { + it("should re-set payment type for an existing subdomain", async () => { + const domainHash = registeredDomainHashes[2]; + + const { paymentType: paymentTypeBefore } = await zns.subRegistrar.distrConfigs(domainHash); + expect(paymentTypeBefore).to.eq(domainConfigs[2].distrConfig.paymentType); + + await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( + domainHash, + PaymentType.STAKE, + ); + + const { paymentType: paymentTypeAfter } = await zns.subRegistrar.distrConfigs(domainHash); + expect(paymentTypeAfter).to.eq(PaymentType.STAKE); + + // reset it back + await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( + domainHash, + domainConfigs[2].distrConfig.paymentType, + ); + }); + + it("should NOT allow setting for non-authorized account", async () => { + const domainHash = registeredDomainHashes[2]; + + await expect( + zns.subRegistrar.connect(lvl2SubOwner).setPaymentTypeForDomain(domainHash, PaymentType.STAKE) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + NOT_AUTHORIZED_ERR + ); + }); + + it("should emit #PaymentTypeSet event with correct params", async () => { + const domainHash = registeredDomainHashes[2]; + + await expect( + zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( + domainHash, + PaymentType.STAKE, + ) + ).to.emit(zns.subRegistrar, "PaymentTypeSet").withArgs( + domainHash, + PaymentType.STAKE, + ); + + // reset back + await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( + domainHash, + domainConfigs[2].distrConfig.paymentType, + ); + }); + }); + + describe("#setAccessController", () => { + it("should allow ADMIN to set a valid AccessController", async () => { + await zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target); + + const currentAccessController = await zns.subRegistrar.getAccessController(); + + expect(currentAccessController).to.equal(zns.accessController.target); + }); + + it("should allow re-setting the AccessController to another valid contract", async () => { + expect( + await zns.subRegistrar.getAccessController() + ).to.equal( + zns.accessController.target + ); + + const ZNSAccessControllerFactory = await ethers.getContractFactory("ZNSAccessController", deployer); + const newAccessController = await ZNSAccessControllerFactory.deploy( + [deployer.address], + [deployer.address] + ); + + // then change the AccessController + await zns.subRegistrar.connect(deployer).setAccessController(newAccessController.target); + + expect( + await zns.subRegistrar.getAccessController() + ).to.equal( + newAccessController.target + ); + }); + + it("should emit AccessControllerSet event when setting a valid AccessController", async () => { + await expect( + zns.subRegistrar.connect(deployer).setAccessController(zns.accessController.target) + ).to.emit( + zns.subRegistrar, + "AccessControllerSet" + ).withArgs(zns.accessController.target); + }); + + it("should revert when a non-ADMIN tries to set AccessController", async () => { + await expect( + zns.subRegistrar.connect(lvl2SubOwner).setAccessController(zns.accessController.target) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_UNAUTHORIZED_ERR + ).withArgs(lvl2SubOwner.address, GOVERNOR_ROLE); + }); + + it("should revert when setting an AccessController as EOA address", async () => { + await expect( + zns.subRegistrar.connect(deployer).setAccessController(lvl2SubOwner.address) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(lvl2SubOwner.address); + }); + + it("should revert when setting an AccessController as another non-AC contract address", async () => { + await expect( + zns.subRegistrar.connect(deployer).setAccessController(zns.subRegistrar.target) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(zns.subRegistrar.target); + }); + + it("should revert when setting a zero address as AccessController", async () => { + // deployer is the governor + await expect( + zns.subRegistrar.connect(deployer).setAccessController(ethers.ZeroAddress) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + AC_WRONGADDRESS_ERR + ).withArgs(ethers.ZeroAddress); + }); + }); + + describe("#setRootRegistrar()", () => { + it("should set the new root registrar correctly and emit #RootRegistrarSet event", async () => { + const tx = await zns.subRegistrar.connect(admin).setRootRegistrar(random.address); + + await expect(tx).to.emit(zns.subRegistrar, "RootRegistrarSet").withArgs(random.address); + + expect(await zns.subRegistrar.rootRegistrar()).to.equal(random.address); + }); + + it("should NOT be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).setRootRegistrar(random.address)) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("should NOT set registrar as 0x0 address", async () => { + await expect( + zns.subRegistrar.connect(admin).setRootRegistrar(ethers.ZeroAddress) + ).to.be.revertedWithCustomError( + zns.subRegistrar, + ZERO_ADDRESS_ERR + ); + }); + }); + + describe("#setRegistry()", () => { + it("should set the new registry correctly and emit #RegistrySet event", async () => { + const tx = await zns.subRegistrar.connect(admin).setRegistry(random.address); + + await expect(tx).to.emit(zns.subRegistrar, "RegistrySet").withArgs(random.address); + + expect(await zns.subRegistrar.registry()).to.equal(random.address); + }); + + it("should not be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).setRegistry(random.address)) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + }); + + describe("#pauseRegistration()", () => { + it("should pause the registration process and emit #RegistrationPauseSet event", async () => { + const tx = await zns.subRegistrar.connect(admin).pauseRegistration(); + + await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(true); + + expect(await zns.subRegistrar.registrationPaused()).to.equal(true); + }); + + it("should not be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).pauseRegistration()) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("should not allow to pause if already paused", async () => { + await expect(zns.subRegistrar.connect(admin).pauseRegistration()) + .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); + }); + }); + + describe("#unpauseRegistration()", () => { + it("should unpause the registration process and emit #RegistrationPauseSet event", async () => { + const tx = await zns.subRegistrar.connect(admin).unpauseRegistration(); + + await expect(tx).to.emit(zns.subRegistrar, "RegistrationPauseSet").withArgs(false); + + expect(await zns.subRegistrar.registrationPaused()).to.equal(false); + }); + + it("should not be callable by anyone other than ADMIN_ROLE", async () => { + await expect(zns.subRegistrar.connect(random).unpauseRegistration()) + .to.be.revertedWithCustomError(zns.accessController, AC_UNAUTHORIZED_ERR) + .withArgs(random.address, ADMIN_ROLE); + }); + + it("should not allow to unpause if already unpaused", async () => { + await expect(zns.subRegistrar.connect(admin).unpauseRegistration()) + .to.be.revertedWithCustomError(zns.subRegistrar, PAUSE_SAME_VALUE_ERR); + }); + }); + }); }); \ No newline at end of file diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index aebabdf17..c8e49849b 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -240,11 +240,12 @@ export default class Domain { } async setDistributionConfigForDomain ( - executor ?: SignerWithAddress - ) : Promise { - return this.zns.subRegistrar.connect(executor ? executor : this.owner).setDistributionConfigForDomain( + distrConfig ?: IDistributionConfig, + executor ?: SignerWithAddress, + ) { + await this.zns.subRegistrar.connect(executor ? executor : this.owner).setDistributionConfigForDomain( this.hash, - this.distrConfig, + distrConfig ? distrConfig : this.distrConfig, ); } From 1b138e8213b3bbb7af2613b8ae08b3d74c799c76 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Mon, 29 Sep 2025 18:43:11 -0700 Subject: [PATCH 17/26] Minor test fix --- test/ZNSSubRegistrar.unit.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 2c1d56a1d..86a82d38f 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -99,6 +99,8 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { ].map(async ({ address }) => zns.meowToken.mint(address, ethers.parseEther("1000000000000000000000000"))) ); + + await zns.meowToken.connect(specificSubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); }); it("Should NOT let initialize the implementation contract", async () => { From c03901eddee718f1a5884de9ff060782a5ea8d8a Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Mon, 29 Sep 2025 18:48:59 -0700 Subject: [PATCH 18/26] Tests type fixes --- test/ZNSSubRegistrar.unit.test.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 86a82d38f..1fdf51d62 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -28,6 +28,7 @@ import Domain from "./helpers/domain/domain"; import { getDomainRegisteredEvents } from "./helpers/events"; import { registrationWithSetup } from "./helpers/register-setup"; import { IFullDomainConfig } from "./helpers/domain/types"; +import { Addressable } from "ethers"; describe.only("ZNSSubRegistrar Unit Tests", () => { @@ -580,15 +581,15 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { // reset it back await zns.subRegistrar.connect(operator).setDistributionConfigForDomain( domainHash, - domainConfigs[2].distrConfig, + domainConfigs[2].distrConfig as IDistributionConfig, ); const origConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); - expect(origConfigAfter.accessType).to.eq(domainConfigs[2].distrConfig.accessType); - expect(origConfigAfter.pricerContract).to.eq(domainConfigs[2].distrConfig.pricerContract); + expect(origConfigAfter.accessType).to.eq(domainConfigs[2].distrConfig?.accessType); + expect(origConfigAfter.pricerContract).to.eq(domainConfigs[2].distrConfig?.pricerContract); expect( origConfigAfter.paymentType ).to.eq( - domainConfigs[2].distrConfig.paymentType + domainConfigs[2].distrConfig?.paymentType ); // remove operator @@ -646,7 +647,7 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { const domainHash = registeredDomainHashes[2]; const pricerContractBefore = await zns.subRegistrar.distrConfigs(domainHash); - expect(pricerContractBefore.pricerContract).to.eq(domainConfigs[2].distrConfig.pricerContract); + expect(pricerContractBefore.pricerContract).to.eq(domainConfigs[2].distrConfig?.pricerContract); await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( domainHash, @@ -660,8 +661,8 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { // reset it back await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( domainHash, - domainConfigs[2].distrConfig.priceConfig, - domainConfigs[2].distrConfig.pricerContract, + domainConfigs[2].distrConfig?.priceConfig as string, + domainConfigs[2].distrConfig?.pricerContract as string | Addressable, ); }); @@ -701,7 +702,7 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { const domainHash = registeredDomainHashes[2]; const { paymentType: paymentTypeBefore } = await zns.subRegistrar.distrConfigs(domainHash); - expect(paymentTypeBefore).to.eq(domainConfigs[2].distrConfig.paymentType); + expect(paymentTypeBefore).to.eq(domainConfigs[2].distrConfig?.paymentType); await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( domainHash, @@ -714,7 +715,7 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { // reset it back await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( domainHash, - domainConfigs[2].distrConfig.paymentType, + domainConfigs[2].distrConfig?.paymentType as bigint, ); }); @@ -745,7 +746,7 @@ describe.only("ZNSSubRegistrar Unit Tests", () => { // reset back await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( domainHash, - domainConfigs[2].distrConfig.paymentType, + domainConfigs[2].distrConfig?.paymentType as bigint, ); }); }); From 05a04102ad57f54edf7b8c8d09ae0439b1aead9a Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 30 Sep 2025 14:51:51 -0700 Subject: [PATCH 19/26] After merge fixes --- test/ZNSAddressResolver.test.ts | 8 ++++---- test/ZNSSubRegistrar.test.ts | 19 +++++++++---------- test/ZNSSubRegistrar.unit.test.ts | 2 +- test/helpers/domain/domain.ts | 4 ++++ 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/test/ZNSAddressResolver.test.ts b/test/ZNSAddressResolver.test.ts index c9e327ace..516156d04 100644 --- a/test/ZNSAddressResolver.test.ts +++ b/test/ZNSAddressResolver.test.ts @@ -142,10 +142,10 @@ describe("ZNSAddressResolver", () => { }); it("Should allow operator to setAddress and emit event", async () => { - await domain.setOwnersOperator({ - operator: operator.address, - allowed: true, - }); + await domain.setOwnersOperator( + operator.address, + true, + ); await expect( zns.addressResolver.connect(operator) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 12357709a..9bc6bb3e5 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -165,7 +165,7 @@ describe("ZNSSubRegistrar", () => { }); await subdomain.register(lvl2SubOwner); - const config = await subdomain.getPaymentConfig(); + const config = await subdomain.paymentConfig; expect(config.token).to.eq(await zns.meowToken.getAddress()); expect(config.beneficiary).to.eq(lvl2SubOwner.address); }); @@ -204,7 +204,7 @@ describe("ZNSSubRegistrar", () => { }); await subdomain.register(); - const config = await subdomain.getPaymentConfig(); + const config = await zns.treasury.paymentConfigs(subdomain.hash); expect(config.token).to.eq(ethers.ZeroAddress); expect(config.beneficiary).to.eq(ethers.ZeroAddress); }); @@ -857,10 +857,10 @@ describe("ZNSSubRegistrar", () => { decodedConfig.feePercentage = BigInt(0); - await domain2.setPricerDataForDomain({ - priceConfig: decodedConfig, - pricerContract: currDistrConfig.pricerContract, - }); + await domain2.setPricerDataForDomain( + decodedConfig, + currDistrConfig.pricerContract, + ); // try register a subdomain again await subdomain2.register(); @@ -908,7 +908,7 @@ describe("ZNSSubRegistrar", () => { // the first domain is root if (!config.parentHash) { if (i !== 0) { - config.parentHash = domObj?.domainHash; + config.parentHash = domObj?.domainHash as string; // parent is the previous domain } else { config.parentHash = ethers.ZeroHash; } @@ -1489,7 +1489,7 @@ describe("ZNSSubRegistrar", () => { // check a couple of fields from price config const distrConfig = await zns.subRegistrar.distrConfigs(lvl2Hash); const priceConfig = decodePriceConfig(distrConfig.priceConfig); - const priceConfigFromDomain = decodePriceConfig(domainConfigs[1].distrConfig.priceConfig); + const priceConfigFromDomain = decodePriceConfig(domainConfigs[1].distrConfig?.priceConfig as string); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if ("maxPrice" in priceConfigFromDomain) { @@ -1726,8 +1726,7 @@ describe("ZNSSubRegistrar", () => { allowed: [ true ], }); - const parentOwnerFromReg = await subdomain.getDomainOwner(); - expect(parentOwnerFromReg).to.eq(branchLvl1Owner.address); + expect(await subdomain.ownerOfHash).to.eq(branchLvl1Owner.address); const childBalBefore = await zns.meowToken.balanceOf(branchLvl2Owner.address); diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 1fdf51d62..ec15ca288 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -31,7 +31,7 @@ import { IFullDomainConfig } from "./helpers/domain/types"; import { Addressable } from "ethers"; -describe.only("ZNSSubRegistrar Unit Tests", () => { +describe("ZNSSubRegistrar Unit Tests", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress; let specificRootOwner : SignerWithAddress; diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 60d49b510..c57ed306e 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -101,6 +101,10 @@ export default class Domain { return this.zns.domainToken.ownerOf(this.tokenId); } + async getPaymentConfig () : Promise { + return this.zns.treasury.getPaymentConfig(this.hash); + } + async isOwnerOrOperator (candidate : SignerWithAddress) : Promise { return this.zns.registry.isOwnerOrOperator(this.hash, candidate.address); } From 07349e7c24651e0d28f1977f3acd19e194bff5a9 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 30 Sep 2025 15:59:25 -0700 Subject: [PATCH 20/26] Updated Domain class functions to work with object params. Updated tests --- test/ZNSAddressResolver.test.ts | 8 +- test/ZNSRootRegistrar.test.ts | 36 ++++----- test/ZNSSubRegistrar.test.ts | 26 +++--- test/ZNSSubRegistrar.unit.test.ts | 47 ++++++----- test/helpers/domain/domain.ts | 127 +++++++++++++++++++----------- 5 files changed, 141 insertions(+), 103 deletions(-) diff --git a/test/ZNSAddressResolver.test.ts b/test/ZNSAddressResolver.test.ts index 516156d04..c9e327ace 100644 --- a/test/ZNSAddressResolver.test.ts +++ b/test/ZNSAddressResolver.test.ts @@ -142,10 +142,10 @@ describe("ZNSAddressResolver", () => { }); it("Should allow operator to setAddress and emit event", async () => { - await domain.setOwnersOperator( - operator.address, - true, - ); + await domain.setOwnersOperator({ + operator: operator.address, + allowed: true, + }); await expect( zns.addressResolver.connect(operator) diff --git a/test/ZNSRootRegistrar.test.ts b/test/ZNSRootRegistrar.test.ts index 39d3a2439..cc8a9b855 100644 --- a/test/ZNSRootRegistrar.test.ts +++ b/test/ZNSRootRegistrar.test.ts @@ -422,7 +422,7 @@ describe("ZNSRootRegistrar", () => { }; const domain = new Domain(args); - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain({}); } }); @@ -477,7 +477,7 @@ describe("ZNSRootRegistrar", () => { label: defaultDomain, }, }); - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain({}); await zns.rootRegistrar.connect(admin).unpauseRegistration(); }); @@ -493,7 +493,7 @@ describe("ZNSRootRegistrar", () => { }, }); - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain({}); }); it("Successfully registers a domain with distrConfig and adds it to state properly", async () => { @@ -514,13 +514,13 @@ describe("ZNSRootRegistrar", () => { }, }); - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain({}); const { pricerContract, accessType, paymentType, - } = await zns.subRegistrar.distrConfigs(domain.hash); + } = await domain.getDistributionConfig(); expect(pricerContract).to.eq(distrConfig.pricerContract); expect(paymentType).to.eq(distrConfig.paymentType); @@ -537,7 +537,7 @@ describe("ZNSRootRegistrar", () => { tokenURI, }, }); - await domain.registerAndValidateDomain(randomUser); + await domain.registerAndValidateDomain({ executor: randomUser }); expect(await domain.ownerOfToken).to.eq(randomUser.address); }); @@ -718,7 +718,7 @@ describe("ZNSRootRegistrar", () => { }, }); // validates in Registry and events - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain({}); const namehashRef = hashDomainLabel(defaultDomain); @@ -1236,10 +1236,10 @@ describe("ZNSRootRegistrar", () => { const asBytes = encodePriceConfig(newConfig); - await domain.setPricerDataForDomain( - newConfig, - zns.fixedPricer.target, - ); + await domain.setPricerDataForDomain({ + priceConfig: newConfig, + pricerContract: zns.fixedPricer.target, + }); expect(await zns.fixedPricer.getPrice(asBytes, defaultDomain, false)).to.eq(ogPrice); @@ -1259,12 +1259,12 @@ describe("ZNSRootRegistrar", () => { expect(exists).to.be.false; // validate access type has been set to LOCKED - const { accessType } = await zns.subRegistrar.distrConfigs(domain.hash); + const { accessType } = await domain.getDistributionConfig(); expect(accessType).to.eq(AccessType.LOCKED); // validate mintlist has been removed - expect(await zns.subRegistrar.isMintlistedForDomain(domain.hash, user.address)).to.be.false; - expect(await zns.subRegistrar.isMintlistedForDomain(domain.hash, zeroVault.address)).to.be.false; + expect(await domain.isMintlistedForDomain(user)).to.be.false; + expect(await domain.isMintlistedForDomain(zeroVault)).to.be.false; }); it("Cannot revoke a domain that doesnt exist", async () => { @@ -1392,10 +1392,10 @@ describe("ZNSRootRegistrar", () => { await domain.register(); // assign an operator - await domain.setOwnersOperator( - operator.address, - true, - ); + await domain.setOwnersOperator({ + operator: operator.address, + allowed: true, + }); // Revoke the domain await domain.revoke(); diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 9bc6bb3e5..b8e6eeb41 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -204,7 +204,7 @@ describe("ZNSSubRegistrar", () => { }); await subdomain.register(); - const config = await zns.treasury.paymentConfigs(subdomain.hash); + const config = await subdomain.getPaymentConfig(); expect(config.token).to.eq(ethers.ZeroAddress); expect(config.beneficiary).to.eq(ethers.ZeroAddress); }); @@ -470,7 +470,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await subdomain.registerAndValidateDomain(); + await subdomain.registerAndValidateDomain({}); }); it("should register a subdomain with token assigned to a different address if provided", async () => { @@ -642,7 +642,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await subdomain.registerAndValidateDomain(); + await subdomain.registerAndValidateDomain({}); }); // ! this value can change based on the block gas limit ! @@ -676,7 +676,7 @@ describe("ZNSSubRegistrar", () => { paymentConfig: FULL_DISTR_CONFIG_EMPTY.paymentConfig, }, }); - await subdomain.registerAndValidateDomain(); + await subdomain.registerAndValidateDomain({}); }); it("should revert when user has insufficient funds", async () => { @@ -857,10 +857,10 @@ describe("ZNSSubRegistrar", () => { decodedConfig.feePercentage = BigInt(0); - await domain2.setPricerDataForDomain( - decodedConfig, - currDistrConfig.pricerContract, - ); + await domain2.setPricerDataForDomain({ + priceConfig: decodedConfig, + pricerContract: currDistrConfig.pricerContract, + }); // try register a subdomain again await subdomain2.register(); @@ -919,7 +919,7 @@ describe("ZNSSubRegistrar", () => { zns, domainConfig: config, }); - await domain.registerAndValidateDomain(executor ? executor : config.owner); + await domain.registerAndValidateDomain({ executor: executor ? executor : config.owner }); domObj = { domainHash: domain.hash, @@ -1603,7 +1603,7 @@ describe("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, }, }); - await subdomain.registerAndValidateDomain(); + await subdomain.registerAndValidateDomain({}); }); it("should NOT register a child (subdomain) under a parent (root domain) that has been revoked", async () => { @@ -1642,7 +1642,7 @@ describe("ZNSSubRegistrar", () => { zns, domainConfig: domainConfigs[0], }); - await domain.registerAndValidateDomain(); + await domain.registerAndValidateDomain({}); }); it("should NOT register a child (subdomain) under a parent (subdomain) that has been revoked", async () => { @@ -1716,7 +1716,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await subdomain.registerAndValidateDomain(); + await subdomain.registerAndValidateDomain({}); expect(subdomain.hash).to.eq(regResults[1].domainHash); @@ -1750,7 +1750,7 @@ describe("ZNSSubRegistrar", () => { }, }, }); - await newChildHash.registerAndValidateDomain(branchLvl2Owner); + await newChildHash.registerAndValidateDomain({ executor: branchLvl2Owner }); const childBalAfter = await zns.meowToken.balanceOf(branchLvl2Owner.address); diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index ec15ca288..10d7f9cdc 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -6,7 +6,7 @@ import { AC_UNAUTHORIZED_ERR, AC_WRONGADDRESS_ERR, AccessType, - ADMIN_ROLE, DEFAULT_CURVE_PRICE_CONFIG_BYTES, DEFAULT_FIXED_PRICER_CONFIG_BYTES, DEFAULT_TOKEN_URI, deployZNS, + ADMIN_ROLE, decodePriceConfig, DEFAULT_CURVE_PRICE_CONFIG, DEFAULT_CURVE_PRICE_CONFIG_BYTES, DEFAULT_FIXED_PRICER_CONFIG_BYTES, DEFAULT_TOKEN_URI, deployZNS, distrConfigEmpty, encodePriceConfig, getProxyImplAddress, @@ -28,7 +28,6 @@ import Domain from "./helpers/domain/domain"; import { getDomainRegisteredEvents } from "./helpers/events"; import { registrationWithSetup } from "./helpers/register-setup"; import { IFullDomainConfig } from "./helpers/domain/types"; -import { Addressable } from "ethers"; describe("ZNSSubRegistrar Unit Tests", () => { @@ -547,9 +546,9 @@ describe("ZNSSubRegistrar Unit Tests", () => { describe("#setDistributionConfigForDomain()", () => { it("should re-set distribution config for an existing subdomain", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; - const distrConfigBefore = await zns.subRegistrar.distrConfigs(domainHash); + const distrConfigBefore = await domain.getDistributionConfig(); expect(distrConfigBefore.accessType).to.not.eq(AccessType.MINTLIST); expect(distrConfigBefore.pricerContract).to.not.eq(await zns.fixedPricer.getAddress()); expect( @@ -565,9 +564,9 @@ describe("ZNSSubRegistrar Unit Tests", () => { priceConfig: DEFAULT_FIXED_PRICER_CONFIG_BYTES, }; - await domains[2].setDistributionConfigForDomain(newConfig); + await domains[2].setDistributionConfigForDomain({ distrConfig: newConfig }); - const distrConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); + const distrConfigAfter = await domain.getDistributionConfig(); expect(distrConfigAfter.accessType).to.eq(newConfig.accessType); expect(distrConfigAfter.pricerContract).to.eq(newConfig.pricerContract); expect(distrConfigAfter.paymentType).to.eq(newConfig.paymentType); @@ -579,11 +578,11 @@ describe("ZNSSubRegistrar Unit Tests", () => { ); // reset it back - await zns.subRegistrar.connect(operator).setDistributionConfigForDomain( - domainHash, - domainConfigs[2].distrConfig as IDistributionConfig, - ); - const origConfigAfter = await zns.subRegistrar.distrConfigs(domainHash); + await domain.setDistributionConfigForDomain({ + distrConfig: domainConfigs[2].distrConfig as IDistributionConfig, + executor: operator, + }); + const origConfigAfter = await domain.getDistributionConfig(); expect(origConfigAfter.accessType).to.eq(domainConfigs[2].distrConfig?.accessType); expect(origConfigAfter.pricerContract).to.eq(domainConfigs[2].distrConfig?.pricerContract); expect( @@ -644,26 +643,26 @@ describe("ZNSSubRegistrar Unit Tests", () => { describe("#setPricerDataForDomain()", () => { it("should re-set pricer contract for an existing subdomain", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; - const pricerContractBefore = await zns.subRegistrar.distrConfigs(domainHash); + const pricerContractBefore = await domain.getDistributionConfig(); expect(pricerContractBefore.pricerContract).to.eq(domainConfigs[2].distrConfig?.pricerContract); - await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( - domainHash, - DEFAULT_CURVE_PRICE_CONFIG_BYTES, - await zns.curvePricer.getAddress(), - ); + await domain.setPricerDataForDomain({ + priceConfig: DEFAULT_CURVE_PRICE_CONFIG, + pricerContract: await zns.curvePricer.getAddress(), + executor: lvl3SubOwner, + }); - const pricerContractAfter = await zns.subRegistrar.distrConfigs(domainHash); + const pricerContractAfter = await domain.getDistributionConfig(); expect(pricerContractAfter.pricerContract).to.eq(await zns.curvePricer.getAddress()); // reset it back - await zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( - domainHash, - domainConfigs[2].distrConfig?.priceConfig as string, - domainConfigs[2].distrConfig?.pricerContract as string | Addressable, - ); + await domain.setPricerDataForDomain({ + priceConfig: decodePriceConfig(domainConfigs[2].distrConfig?.priceConfig as string), + pricerContract: domainConfigs[2].distrConfig?.pricerContract, + executor: lvl3SubOwner, + }); }); it("should NOT allow setting for non-authorized account", async () => { diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index c57ed306e..707885b80 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -25,7 +25,7 @@ import { ContractTransactionResponse, } from "ethers"; import { expect } from "chai"; -import { encodePriceConfig } from "../pricing"; +import { decodePriceConfig, encodePriceConfig } from "../pricing"; export default class Domain { @@ -102,13 +102,21 @@ export default class Domain { } async getPaymentConfig () : Promise { - return this.zns.treasury.getPaymentConfig(this.hash); + return this.zns.treasury.paymentConfigs(this.hash); + } + + async getDistributionConfig () : Promise { + return this.zns.subRegistrar.distrConfigs(this.hash); } async isOwnerOrOperator (candidate : SignerWithAddress) : Promise { return this.zns.registry.isOwnerOrOperator(this.hash, candidate.address); } + async isMintlistedForDomain (candidate : SignerWithAddress) : Promise { + return this.zns.subRegistrar.isMintlistedForDomain(this.hash, candidate.address); + } + private async getDomainHashFromEvent (domainOwner ?: SignerWithAddress) : Promise { const latestBlock = await time.latestBlock(); const filter = this.zns.rootRegistrar.filters.DomainRegistered( @@ -200,11 +208,15 @@ export default class Domain { ); } - async updateDomainRecord ( - resolverType ?: string, - newOwner ?: string, - executor ?: SignerWithAddress - ) : Promise { + async updateDomainRecord ({ + resolverType, + newOwner, + executor, + } : { + resolverType ?: string; + newOwner ?: string; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.registry.connect(executor ? executor : this.owner).updateDomainRecord( this.hash, newOwner ? newOwner : this.owner, @@ -231,18 +243,25 @@ export default class Domain { ); } - async setOwnersOperator ( - operator : string, - allowed : boolean, - executor ?: SignerWithAddress - ) : Promise { + async setOwnersOperator ({ + operator, + allowed, + executor, + } : { + operator : string; + allowed : boolean; + executor ?: SignerWithAddress; + }) : Promise { return this.zns.registry.connect(executor ? executor : this.owner).setOwnersOperator(operator, allowed); } - async setDistributionConfigForDomain ( - distrConfig : IDistributionConfig, - executor ?: SignerWithAddress - ) { + async setDistributionConfigForDomain ({ + distrConfig, + executor, + } : { + distrConfig : IDistributionConfig; + executor ?: SignerWithAddress; + }) { const currentConfig = distrConfig ? distrConfig : this.distrConfig; await this.zns.subRegistrar.connect(executor ? executor : this.owner).setDistributionConfigForDomain( @@ -254,34 +273,47 @@ export default class Domain { this.distrConfig = currentConfig; } - async setPricerDataForDomain ( - priceConfig ?: ICurvePriceConfig | IFixedPriceConfig, - pricerContract ?: string | Addressable, - executor ?: SignerWithAddress - ) { + async setPricerDataForDomain ({ + priceConfig, + pricerContract, + executor, + } : { + priceConfig ?: ICurvePriceConfig | IFixedPriceConfig; + pricerContract ?: string | Addressable; + executor ?: SignerWithAddress; + }) { if (priceConfig || this.priceConfig !== undefined || Object.keys(this.priceConfig).length === 0 ) { - await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( - this.hash, - priceConfig ? encodePriceConfig(priceConfig) : encodePriceConfig(this.priceConfig), - pricerContract ? pricerContract : this.distrConfig.pricerContract - ); + if (typeof priceConfig === "string") { + await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( + this.hash, + priceConfig, + pricerContract ? pricerContract : this.distrConfig.pricerContract + ); + + this.priceConfig = decodePriceConfig(priceConfig); + + } else { + await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( + this.hash, + encodePriceConfig(priceConfig), + pricerContract ? pricerContract : this.distrConfig.pricerContract + ); + } } else { throw new Error("Domain Helper: priceConfig is not specified"); } - - // updating local var - if (priceConfig) { - this.priceConfig = priceConfig; - } } - async setPaymentTypeForDomain ( - paymentType : bigint, - executor ?: SignerWithAddress - ) : Promise { + async setPaymentTypeForDomain ({ + paymentType, + executor, + } : { + paymentType : bigint; + executor ?: SignerWithAddress; + }) : Promise { if (Object.values(PaymentType).includes(paymentType)) { return this.zns.subRegistrar.connect(executor ? executor : this.owner).setPaymentTypeForDomain( this.hash, @@ -293,10 +325,13 @@ export default class Domain { this.distrConfig.paymentType = paymentType; } - async setAccessTypeForDomain ( - accessType : bigint, - executor ?: SignerWithAddress - ) : Promise { + async setAccessTypeForDomain ({ + accessType, + executor, + } : { + accessType : bigint; + executor ?: SignerWithAddress; + }) : Promise { if (!Object.values(AccessType).includes(accessType)) { return this.zns.subRegistrar.connect(executor ? executor : this.owner).setAccessTypeForDomain( this.hash, @@ -328,11 +363,15 @@ export default class Domain { // ------------------------------------------------------ // VALIDATION // ------------------------------------------------------ - async registerAndValidateDomain ( - executor ?: SignerWithAddress, - domainOwner ?: string, - tokenOwner ?: string, - ) : Promise { + async registerAndValidateDomain ({ + executor, + domainOwner, + tokenOwner, + } : { + executor ?: SignerWithAddress; + domainOwner ?: string; + tokenOwner ?: string; + }) : Promise { const caller = executor ? executor : this.owner; const txPromise = await this.register(caller); From 5eb6ebce2387f6e0585cc327d4c6b586ea2cd375 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Wed, 1 Oct 2025 15:12:20 -0700 Subject: [PATCH 21/26] Test fixes in accordance with new domain methods. --- test/ZNSSubRegistrar.unit.test.ts | 95 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 10d7f9cdc..7be1c372b 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -599,7 +599,7 @@ describe("ZNSSubRegistrar Unit Tests", () => { }); it("should NOT allow to set distribution config for a non-authorized account", async () => { - const domainHash = registeredDomainHashes[1]; + const domain = domains[1]; const newConfig = { pricerContract: await zns.curvePricer.getAddress(), @@ -609,10 +609,10 @@ describe("ZNSSubRegistrar Unit Tests", () => { }; await expect( - zns.subRegistrar.connect(deployer).setDistributionConfigForDomain( - domainHash, - newConfig - ) + domain.setDistributionConfigForDomain({ + distrConfig: newConfig, + executor: deployer, + }) ).to.be.revertedWithCustomError( zns.subRegistrar, NOT_AUTHORIZED_ERR @@ -620,7 +620,7 @@ describe("ZNSSubRegistrar Unit Tests", () => { }); it("should revert if pricerContract is passed as 0x0 address", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; const newConfig = { pricerContract: ethers.ZeroAddress, @@ -630,10 +630,10 @@ describe("ZNSSubRegistrar Unit Tests", () => { }; await expect( - zns.subRegistrar.connect(lvl3SubOwner).setDistributionConfigForDomain( - domainHash, - newConfig - ) + domain.setDistributionConfigForDomain({ + distrConfig: newConfig, + executor: lvl3SubOwner, + }) ).to.be.revertedWithCustomError( zns.subRegistrar, ZERO_ADDRESS_ERR @@ -666,14 +666,14 @@ describe("ZNSSubRegistrar Unit Tests", () => { }); it("should NOT allow setting for non-authorized account", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; await expect( - zns.subRegistrar.connect(lvl2SubOwner).setPricerDataForDomain( - domainHash, - DEFAULT_CURVE_PRICE_CONFIG_BYTES, - await zns.curvePricer.getAddress() - ) + domain.setPricerDataForDomain({ + priceConfig: DEFAULT_CURVE_PRICE_CONFIG, + pricerContract: await zns.curvePricer.getAddress(), + executor: lvl2SubOwner, + }) ).to.be.revertedWithCustomError( zns.subRegistrar, NOT_AUTHORIZED_ERR @@ -681,14 +681,14 @@ describe("ZNSSubRegistrar Unit Tests", () => { }); it("should NOT set pricerContract to 0x0 address", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; await expect( - zns.subRegistrar.connect(lvl3SubOwner).setPricerDataForDomain( - domainHash, - DEFAULT_FIXED_PRICER_CONFIG_BYTES, - ethers.ZeroAddress - ) + domain.setPricerDataForDomain({ + priceConfig: DEFAULT_CURVE_PRICE_CONFIG, + pricerContract: ethers.ZeroAddress, + executor: lvl3SubOwner, + }) ).to.be.revertedWithCustomError( zns.subRegistrar, ZERO_ADDRESS_ERR @@ -698,31 +698,34 @@ describe("ZNSSubRegistrar Unit Tests", () => { describe("#setPaymentTypeForDomain()", () => { it("should re-set payment type for an existing subdomain", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; - const { paymentType: paymentTypeBefore } = await zns.subRegistrar.distrConfigs(domainHash); + const { paymentType: paymentTypeBefore } = await domain.getDistributionConfig(); expect(paymentTypeBefore).to.eq(domainConfigs[2].distrConfig?.paymentType); - await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - PaymentType.STAKE, - ); + await domain.setPaymentTypeForDomain({ + paymentType: PaymentType.STAKE, + executor: lvl3SubOwner, + }); - const { paymentType: paymentTypeAfter } = await zns.subRegistrar.distrConfigs(domainHash); + const { paymentType: paymentTypeAfter } = await domain.getDistributionConfig(); expect(paymentTypeAfter).to.eq(PaymentType.STAKE); // reset it back - await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - domainConfigs[2].distrConfig?.paymentType as bigint, - ); + await domain.setPaymentTypeForDomain({ + paymentType: domainConfigs[2].distrConfig?.paymentType as bigint, + executor: lvl3SubOwner, + }); }); it("should NOT allow setting for non-authorized account", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; await expect( - zns.subRegistrar.connect(lvl2SubOwner).setPaymentTypeForDomain(domainHash, PaymentType.STAKE) + domain.setPaymentTypeForDomain({ + paymentType: PaymentType.STAKE, + executor: lvl2SubOwner, + }) ).to.be.revertedWithCustomError( zns.subRegistrar, NOT_AUTHORIZED_ERR @@ -730,23 +733,23 @@ describe("ZNSSubRegistrar Unit Tests", () => { }); it("should emit #PaymentTypeSet event with correct params", async () => { - const domainHash = registeredDomainHashes[2]; + const domain = domains[2]; await expect( - zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - PaymentType.STAKE, - ) + domain.setPaymentTypeForDomain({ + paymentType: PaymentType.STAKE, + executor: lvl3SubOwner, + }) ).to.emit(zns.subRegistrar, "PaymentTypeSet").withArgs( - domainHash, + domain.hash, PaymentType.STAKE, ); // reset back - await zns.subRegistrar.connect(lvl3SubOwner).setPaymentTypeForDomain( - domainHash, - domainConfigs[2].distrConfig?.paymentType as bigint, - ); + await domain.setPaymentTypeForDomain({ + paymentType: domainConfigs[2].distrConfig?.paymentType as bigint, + executor: lvl3SubOwner, + }); }); }); @@ -912,4 +915,4 @@ describe("ZNSSubRegistrar Unit Tests", () => { }); }); }); -}); \ No newline at end of file +}); From 4724d7ef76e8b24e968bd9bfdf78f20d57577cbc Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Wed, 1 Oct 2025 18:38:53 -0700 Subject: [PATCH 22/26] More tests updated in accordance of Domain class changes. --- test/ZNSSubRegistrar.test.ts | 224 +++++++++++++++++---------------- test/helpers/domain/domain.ts | 27 +++- test/helpers/register-setup.ts | 1 - 3 files changed, 135 insertions(+), 117 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index b8e6eeb41..080c65628 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -706,8 +706,10 @@ describe("ZNSSubRegistrar", () => { // add allowance await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), ethers.MaxUint256); - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, parentHash: domain.hash, label: "subfunds", domainAddress: lvl2SubOwner.address, @@ -715,7 +717,11 @@ describe("ZNSSubRegistrar", () => { tokenURI: subTokenURI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + sub.register(lvl2SubOwner, false) ).to.be.revertedWithCustomError( zns.meowToken, INSUFFICIENT_BALANCE_ERC_ERR @@ -749,8 +755,10 @@ describe("ZNSSubRegistrar", () => { // add allowance await zns.meowToken.connect(lvl2SubOwner).approve(await zns.treasury.getAddress(), expectedPrice - 1n); - await expect( - zns.subRegistrar.connect(lvl2SubOwner).registerSubdomain({ + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl2SubOwner, parentHash: domain.hash, label: "suballowance", domainAddress: lvl2SubOwner.address, @@ -758,7 +766,11 @@ describe("ZNSSubRegistrar", () => { tokenURI: subTokenURI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + sub.register(lvl2SubOwner, false) ).to.be.revertedWithCustomError( zns.meowToken, INSUFFICIENT_ALLOWANCE_ERC_ERR @@ -852,20 +864,18 @@ describe("ZNSSubRegistrar", () => { ).to.be.revertedWithCustomError(zns.treasury, NO_BENEFICIARY_ERR); // change stakeFee to 0 - const currDistrConfig = await zns.subRegistrar.distrConfigs(domain2.hash); - const decodedConfig = decodePriceConfig(currDistrConfig.priceConfig); + const { priceConfig, pricerContract } = await domain2.getDistributionConfig(); + const decodedConfig = decodePriceConfig(priceConfig); decodedConfig.feePercentage = BigInt(0); await domain2.setPricerDataForDomain({ priceConfig: decodedConfig, - pricerContract: currDistrConfig.pricerContract, + pricerContract, }); // try register a subdomain again - await subdomain2.register(); - - await zns.registry.exists(subdomain2.hash); + await subdomain2.registerAndValidateDomain({}); }); }); @@ -2846,15 +2856,15 @@ describe("ZNSSubRegistrar", () => { decodePriceConfig(rootPriceConfig).feePercentage ); - const distrConfig = await zns.subRegistrar.distrConfigs(subdomainParent.hash); + const { priceConfig } = await subdomainParent.getDistributionConfig(); - expect(distrConfig.priceConfig).to.eq(encodePriceConfig(priceConfigIncorrect)); + expect(priceConfig).to.eq(encodePriceConfig(priceConfigIncorrect)); const { price: priceFromSC, stakeFee: feeFromSC, } = await zns.curvePricer.getPriceAndFee( - distrConfig.priceConfig, + priceConfig, label, true ); @@ -2890,8 +2900,10 @@ describe("ZNSSubRegistrar", () => { ); // using direct contract call cause domain.register() prepares and - await expect( - zns.subRegistrar.connect(lvl3SubOwner).registerSubdomain({ + const subdomain = new Domain({ + zns, + domainConfig: { + owner: lvl3SubOwner, parentHash: subdomainParent.hash, label, domainAddress: lvl3SubOwner.address, @@ -2899,7 +2911,10 @@ describe("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + await expect( + subdomain.register(lvl3SubOwner, false) ).to.be.revertedWithCustomError( zns.meowToken, INSUFFICIENT_ALLOWANCE_ERC_ERR @@ -3141,16 +3156,22 @@ describe("ZNSSubRegistrar", () => { }); // try to register child - await expect( - zns.subRegistrar.connect(lvl5SubOwner).registerSubdomain({ + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl5SubOwner, parentHash: res[0].domainHash, label: "tobedenied", domainAddress: ethers.ZeroAddress, tokenOwner: ethers.ZeroAddress, tokenURI: DEFAULT_TOKEN_URI, - distrConfig: distrConfigEmpty, + distrConfig: defaultDistrConfig, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + sub.register(undefined, false) ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -3161,41 +3182,17 @@ describe("ZNSSubRegistrar", () => { const { domainHash: parentHash } = regResults[1]; const domainLabel = "alloweded"; - const { - expectedPrice, - } = getPriceObject( - domainLabel, - decodePriceConfig(domainConfigs[1].fullConfig.distrConfig.priceConfig) - ); - - const protocolFee = getStakingOrProtocolFee(expectedPrice); - // approve direct payment - await zns.meowToken.connect(lvl5SubOwner).approve( - await zns.treasury.getAddress(), - expectedPrice + protocolFee - ); - - await defaultSubdomainRegistration({ - user: lvl5SubOwner, - zns, - parentHash, - subdomainLabel: domainLabel, - }); - - const hash = await getDomainHashFromEvent({ + const sub = new Domain({ zns, - user: lvl5SubOwner, + domainConfig: { + owner: lvl5SubOwner, + parentHash, + label: domainLabel, + }, }); + await sub.registerAndValidateDomain({}); - // check registry - const dataFromReg = await zns.registry.getDomainRecord(hash); - expect(dataFromReg.owner).to.eq(lvl5SubOwner.address); - expect(dataFromReg.resolver).to.eq(zns.addressResolver.target); - - // check domain token - const tokenId = BigInt(hash).toString(); - const tokenOwner = await zns.domainToken.ownerOf(tokenId); - expect(tokenOwner).to.eq(lvl5SubOwner.address); + expect(sub.tokenOwner).to.eq(lvl5SubOwner.address); }); // eslint-disable-next-line max-len @@ -3203,13 +3200,13 @@ describe("ZNSSubRegistrar", () => { // approve direct payment await zns.meowToken.connect(lvl3SubOwner).approve(await zns.treasury.getAddress(), fixedPrice); // register parent with mintlisted access - const parentHash = await registrationWithSetup({ + const parent = new Domain({ zns, - user: lvl3SubOwner, - tokenOwner: lvl3SubOwner.address, - parentHash: regResults[1].domainHash, - domainLabel: "mintlistparent", - fullConfig: { + domainConfig: { + owner: lvl3SubOwner, + tokenOwner: lvl3SubOwner.address, + parentHash: regResults[1].domainHash, + label: "mintlistparent", distrConfig: { pricerContract: await zns.fixedPricer.getAddress(), priceConfig: encodePriceConfig({ @@ -3225,67 +3222,66 @@ describe("ZNSSubRegistrar", () => { }, }, }); + await parent.register(); // mintlist potential child user - await zns.subRegistrar.connect(lvl3SubOwner).updateMintlistForDomain( - parentHash, - [lvl4SubOwner.address], - [true], - ); + await parent.updateMintlistForDomain({ + candidates: [lvl4SubOwner.address], + allowed: [true], + }); // register child - const hash = await registrationWithSetup({ + const child = new Domain({ zns, - user: lvl4SubOwner, - tokenOwner: lvl4SubOwner.address, - parentHash, - domainLabel: "mintlisted", + domainConfig: { + owner: lvl4SubOwner, + parentHash: parent.hash, + label: "mintlisted", + }, }); + await child.register(); // check registry - const dataFromReg = await zns.registry.getDomainRecord(hash); + const dataFromReg = await zns.registry.getDomainRecord(child.hash); expect(dataFromReg.owner).to.eq(lvl4SubOwner.address); expect(dataFromReg.resolver).to.eq(await zns.addressResolver.getAddress()); // check domain token - const tokenId = BigInt(hash).toString(); + const tokenId = BigInt(child.hash).toString(); const tokenOwner = await zns.domainToken.ownerOf(tokenId); expect(tokenOwner).to.eq(lvl4SubOwner.address); // try to register child with non-mintlisted user - await expect( - zns.subRegistrar.connect(lvl5SubOwner).registerSubdomain({ - parentHash, + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl4SubOwner, + parentHash: parent.hash, label: "notmintlisted", domainAddress: ethers.ZeroAddress, tokenOwner: ethers.ZeroAddress, tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + sub.register(lvl5SubOwner, false) ).to.be.revertedWithCustomError( zns.subRegistrar, SENDER_NOT_APPROVED_ERR ); // remove user from mintlist - await zns.subRegistrar.connect(lvl3SubOwner).updateMintlistForDomain( - parentHash, - [lvl4SubOwner.address], - [false], - ); + await parent.updateMintlistForDomain({ + candidates: [lvl4SubOwner.address], + allowed: [false], + }); // try to register again await expect( - zns.subRegistrar.connect(lvl4SubOwner).registerSubdomain({ - parentHash, - label: "notmintlisted", - domainAddress: ethers.ZeroAddress, - tokenOwner: ethers.ZeroAddress, - tokenURI: DEFAULT_TOKEN_URI, - distrConfig: distrConfigEmpty, - paymentConfig: paymentConfigEmpty, - }) + sub.register() ).to.be.revertedWithCustomError( zns.subRegistrar, SENDER_NOT_APPROVED_ERR @@ -3318,7 +3314,9 @@ describe("ZNSSubRegistrar", () => { // try with non-authorized await expect( - zns.subRegistrar.connect(lvl5SubOwner).updateMintlistForDomain(domainHash, [lvl5SubOwner.address], [true]) + zns.subRegistrar.connect(lvl5SubOwner).updateMintlistForDomain( + domainHash, [lvl5SubOwner.address], [true] + ) ).to.be.revertedWithCustomError( zns.subRegistrar, NOT_AUTHORIZED_ERR @@ -3371,8 +3369,10 @@ describe("ZNSSubRegistrar", () => { AccessType.LOCKED ); - await expect( - zns.subRegistrar.connect(lvl5SubOwner).registerSubdomain({ + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl5SubOwner, parentHash: regResults[1].domainHash, label: "notallowed", domainAddress: ethers.ZeroAddress, @@ -3380,7 +3380,11 @@ describe("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + sub.register(lvl5SubOwner) ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR @@ -3421,21 +3425,15 @@ describe("ZNSSubRegistrar", () => { ); // register - await defaultSubdomainRegistration({ - zns, - user: lvl5SubOwner, - parentHash: regResults[1].domainHash, - subdomainLabel: "alloweddddd", - }); - - const hash = await getDomainHashFromEvent({ + const subdomain = new Domain({ zns, - user: lvl5SubOwner, + domainConfig: { + owner: lvl5SubOwner, + parentHash: regResults[1].domainHash, + label: "alloweddddd", + }, }); - - // check registry - const dataFromReg = await zns.registry.getDomainRecord(hash); - expect(dataFromReg.owner).to.eq(lvl5SubOwner.address); + await subdomain.registerAndValidateDomain({}); // switch back to open await zns.subRegistrar.connect(lvl2SubOwner).setAccessTypeForDomain( @@ -3455,8 +3453,10 @@ describe("ZNSSubRegistrar", () => { fullConfig: FULL_DISTR_CONFIG_EMPTY, // accessType is 0 when supplying empty config }); - await expect( - zns.subRegistrar.connect(lvl4SubOwner).registerSubdomain({ + const sub = new Domain({ + zns, + domainConfig: { + owner: lvl4SubOwner, parentHash, label: "notallowed", domainAddress: ethers.ZeroAddress, @@ -3464,7 +3464,11 @@ describe("ZNSSubRegistrar", () => { tokenURI: DEFAULT_TOKEN_URI, distrConfig: distrConfigEmpty, paymentConfig: paymentConfigEmpty, - }) + }, + }); + + await expect( + sub.register(lvl4SubOwner, false) ).to.be.revertedWithCustomError( zns.subRegistrar, DISTRIBUTION_LOCKED_NOT_EXIST_ERR diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 707885b80..1a2c9c47b 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -145,7 +145,10 @@ export default class Domain { })); } - async register (executor ?: SignerWithAddress) : Promise { + async register ( + executor ?: SignerWithAddress, + shouldMintAndApprove = true, + ) : Promise { const { zns, owner, @@ -163,7 +166,9 @@ export default class Domain { const caller = executor ? executor : owner; // mint and approve strict amount of tokens for domain registration - await this.mintAndApproveForDomain(caller); + if (shouldMintAndApprove) { + await this.mintAndApproveForDomain(caller); + } if (isRoot) { txPromise = await zns.rootRegistrar.connect(caller).registerRootDomain({ @@ -298,9 +303,11 @@ export default class Domain { } else { await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( this.hash, - encodePriceConfig(priceConfig), + encodePriceConfig(priceConfig as ICurvePriceConfig | IFixedPriceConfig), pricerContract ? pricerContract : this.distrConfig.pricerContract ); + + this.priceConfig = priceConfig as ICurvePriceConfig | IFixedPriceConfig; } } else { throw new Error("Domain Helper: priceConfig is not specified"); @@ -313,16 +320,22 @@ export default class Domain { } : { paymentType : bigint; executor ?: SignerWithAddress; - }) : Promise { + }) { + let tx : ContractTransactionResponse | undefined; + if (Object.values(PaymentType).includes(paymentType)) { - return this.zns.subRegistrar.connect(executor ? executor : this.owner).setPaymentTypeForDomain( + tx = await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPaymentTypeForDomain( this.hash, paymentType, ); + } else { + throw new Error("Domain Helper: Invalid payment type provided"); } // updating local var this.distrConfig.paymentType = paymentType; + + return tx; } async setAccessTypeForDomain ({ @@ -367,13 +380,15 @@ export default class Domain { executor, domainOwner, tokenOwner, + shouldMintAndApprove = true, } : { executor ?: SignerWithAddress; domainOwner ?: string; tokenOwner ?: string; + shouldMintAndApprove ?: boolean; }) : Promise { const caller = executor ? executor : this.owner; - const txPromise = await this.register(caller); + const txPromise = await this.register(caller, shouldMintAndApprove); if (!domainOwner) { domainOwner = caller.address; diff --git a/test/helpers/register-setup.ts b/test/helpers/register-setup.ts index 46a2f9810..fca8ab4e7 100644 --- a/test/helpers/register-setup.ts +++ b/test/helpers/register-setup.ts @@ -76,7 +76,6 @@ export const fundApprove = async ({ const { token: tokenAddress } = await zns.treasury.paymentConfigs(parentHash); const tokenContract = getTokenContract(tokenAddress, user); - const rootPriceConfig = await zns.rootRegistrar.rootPriceConfig(); const protocolFee = await zns.curvePricer.getFeeForPrice(rootPriceConfig, price + parentFee); const totalPrice = price + parentFee + protocolFee; From 2511f149bb67fb051cb135c74171b9c8cf7c7647 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Thu, 2 Oct 2025 19:00:09 -0700 Subject: [PATCH 23/26] Minor Domain class fixes --- test/helpers/domain/domain.ts | 24 ++++++++++++------------ test/helpers/types.ts | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index 1a2c9c47b..c2e35d074 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -283,32 +283,32 @@ export default class Domain { pricerContract, executor, } : { - priceConfig ?: ICurvePriceConfig | IFixedPriceConfig; - pricerContract ?: string | Addressable; + priceConfig ?: ICurvePriceConfig | IFixedPriceConfig | string; + pricerContract ?: string; executor ?: SignerWithAddress; }) { if (priceConfig || this.priceConfig !== undefined || Object.keys(this.priceConfig).length === 0 ) { + const args = [this.hash]; + if (typeof priceConfig === "string") { - await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( - this.hash, - priceConfig, - pricerContract ? pricerContract : this.distrConfig.pricerContract - ); + args.push(priceConfig); this.priceConfig = decodePriceConfig(priceConfig); } else { - await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( - this.hash, - encodePriceConfig(priceConfig as ICurvePriceConfig | IFixedPriceConfig), - pricerContract ? pricerContract : this.distrConfig.pricerContract - ); + args.push(encodePriceConfig(priceConfig as ICurvePriceConfig | IFixedPriceConfig)); this.priceConfig = priceConfig as ICurvePriceConfig | IFixedPriceConfig; } + + args.push(pricerContract ? pricerContract : this.distrConfig.pricerContract); + + await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( + ...args + ); } else { throw new Error("Domain Helper: priceConfig is not specified"); } diff --git a/test/helpers/types.ts b/test/helpers/types.ts index 0fe922bec..a359b8575 100644 --- a/test/helpers/types.ts +++ b/test/helpers/types.ts @@ -81,7 +81,7 @@ export interface DeployZNSParams { } export interface IDistributionConfig { - pricerContract : string | Addressable; + pricerContract : string; priceConfig : string; paymentType : bigint; accessType : bigint; From e467e0661f3b555eac61c9873e054dc847387b35 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Fri, 3 Oct 2025 15:22:18 -0700 Subject: [PATCH 24/26] Linter fixes. --- test/DeployCampaignInt.test.ts | 1 - test/ZNSSubRegistrar.test.ts | 3 +- test/ZNSSubRegistrar.unit.test.ts | 12 ++- test/helpers/ac.ts | 174 +++++++++++++++--------------- test/helpers/domain/domain.ts | 1 - test/helpers/types.ts | 1 - 6 files changed, 97 insertions(+), 95 deletions(-) diff --git a/test/DeployCampaignInt.test.ts b/test/DeployCampaignInt.test.ts index 0f69cd543..d343ae4a4 100644 --- a/test/DeployCampaignInt.test.ts +++ b/test/DeployCampaignInt.test.ts @@ -42,7 +42,6 @@ import { getConfig } from "../src/deploy/campaign/get-config"; import { ethers } from "ethers"; import { promisify } from "util"; import { exec } from "child_process"; -import { saveTag } from "../src/utils/git-tag/save-tag"; import { IZNSCampaignConfig, IZNSContracts } from "../src/deploy/campaign/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { getZnsMongoAdapter } from "../src/deploy/mongo"; diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index 080c65628..b5a7e5813 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -27,7 +27,6 @@ import { AC_UNAUTHORIZED_ERR, INSUFFICIENT_BALANCE_ERC_ERR, INSUFFICIENT_ALLOWANCE_ERC_ERR, - ZERO_ADDRESS_ERR, DOMAIN_EXISTS_ERR, SENDER_NOT_APPROVED_ERR, encodePriceConfig, @@ -123,7 +122,7 @@ describe("ZNSSubRegistrar", () => { }; defaultDistrConfig = { - pricerContract: zns.fixedPricer.target, + pricerContract: zns.fixedPricer.target as string, paymentType: PaymentType.DIRECT, accessType: AccessType.OPEN, priceConfig: encodePriceConfig(rootPriceConfig), diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 7be1c372b..1722263f4 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -6,13 +6,18 @@ import { AC_UNAUTHORIZED_ERR, AC_WRONGADDRESS_ERR, AccessType, - ADMIN_ROLE, decodePriceConfig, DEFAULT_CURVE_PRICE_CONFIG, DEFAULT_CURVE_PRICE_CONFIG_BYTES, DEFAULT_FIXED_PRICER_CONFIG_BYTES, DEFAULT_TOKEN_URI, deployZNS, + ADMIN_ROLE, + decodePriceConfig, + DEFAULT_CURVE_PRICE_CONFIG, + DEFAULT_CURVE_PRICE_CONFIG_BYTES, + DEFAULT_FIXED_PRICER_CONFIG_BYTES, + DEFAULT_TOKEN_URI, + deployZNS, distrConfigEmpty, encodePriceConfig, getProxyImplAddress, GOVERNOR_ROLE, IDistributionConfig, - IFixedPriceConfig, INITIALIZED_ERR, ISubRegistrarConfig, NOT_AUTHORIZED_ERR, @@ -28,6 +33,7 @@ import Domain from "./helpers/domain/domain"; import { getDomainRegisteredEvents } from "./helpers/events"; import { registrationWithSetup } from "./helpers/register-setup"; import { IFullDomainConfig } from "./helpers/domain/types"; +import { IFixedPriceConfig } from "../src/deploy/missions/types"; describe("ZNSSubRegistrar Unit Tests", () => { @@ -80,7 +86,7 @@ describe("ZNSSubRegistrar Unit Tests", () => { }; defaultDistrConfig = { - pricerContract: zns.fixedPricer.target, + pricerContract: zns.fixedPricer.target as string, paymentType: PaymentType.DIRECT, accessType: AccessType.OPEN, priceConfig: encodePriceConfig(rootPriceConfig), diff --git a/test/helpers/ac.ts b/test/helpers/ac.ts index 4af55fc49..c94f8d9bc 100644 --- a/test/helpers/ac.ts +++ b/test/helpers/ac.ts @@ -1,102 +1,102 @@ -import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; -import { expect } from "chai"; -import { ethers } from "hardhat"; -import { - IZNSContracts, - ZNSContract, -} from "../../src/deploy/campaign/types"; +// import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; +// import { expect } from "chai"; +// import { ethers } from "hardhat"; +// import { +// IZNSContracts, +// ZNSContract, +// } from "../../src/deploy/campaign/types"; -export const setACTests = ({ - zns, - contract, -} : { - zns : IZNSContracts; - contract : ZNSContract; -}) => { - let deployer : SignerWithAddress; - let user : SignerWithAddress; - let admin : SignerWithAddress; +// export const setACTests = ({ +// zns, +// contract, +// } : { +// zns : IZNSContracts; +// contract : ZNSContract; +// }) => { +// let deployer : SignerWithAddress; +// let user : SignerWithAddress; +// let admin : SignerWithAddress; - describe("#setAccessController", () => { - beforeEach(async () => { - [deployer, user, admin] = await ethers.getSigners(); - }); +// describe("#setAccessController", () => { +// beforeEach(async () => { +// [deployer, user, admin] = await ethers.getSigners(); +// }); - it("should allow ADMIN to set a valid AccessController", async () => { - await zns.rootRegistrar.connect(deployer).setAccessController(zns.accessController.target); +// it("should allow ADMIN to set a valid AccessController", async () => { +// await zns.rootRegistrar.connect(deployer).setAccessController(zns.accessController.target); - const currentAccessController = await zns.rootRegistrar.getAccessController(); +// const currentAccessController = await zns.rootRegistrar.getAccessController(); - expect(currentAccessController).to.equal(zns.accessController.target); - }); +// expect(currentAccessController).to.equal(zns.accessController.target); +// }); - it("should allow re-setting the AccessController to another valid contract", async () => { - expect( - await zns.rootRegistrar.getAccessController() - ).to.equal( - zns.accessController.target - ); +// it("should allow re-setting the AccessController to another valid contract", async () => { +// expect( +// await zns.rootRegistrar.getAccessController() +// ).to.equal( +// zns.accessController.target +// ); - const ZNSAccessControllerFactory = await hre.ethers.getContractFactory("ZNSAccessController", deployer); - const newAccessController = await ZNSAccessControllerFactory.deploy( - [deployer.address], - [deployer.address] - ); +// const ZNSAccessControllerFactory = await hre.ethers.getContractFactory("ZNSAccessController", deployer); +// const newAccessController = await ZNSAccessControllerFactory.deploy( +// [deployer.address], +// [deployer.address] +// ); - // then change the AccessController - await zns.rootRegistrar.connect(deployer).setAccessController(newAccessController.target); +// // then change the AccessController +// await zns.rootRegistrar.connect(deployer).setAccessController(newAccessController.target); - expect( - await zns.rootRegistrar.getAccessController() - ).to.equal( - newAccessController.target - ); - }); +// expect( +// await zns.rootRegistrar.getAccessController() +// ).to.equal( +// newAccessController.target +// ); +// }); - it("should emit AccessControllerSet event when setting a valid AccessController", async () => { - await expect( - zns.rootRegistrar.connect(deployer).setAccessController(zns.accessController.target) - ).to.emit( - zns.rootRegistrar, - "AccessControllerSet" - ).withArgs(zns.accessController.target); - }); +// it("should emit AccessControllerSet event when setting a valid AccessController", async () => { +// await expect( +// zns.rootRegistrar.connect(deployer).setAccessController(zns.accessController.target) +// ).to.emit( +// zns.rootRegistrar, +// "AccessControllerSet" +// ).withArgs(zns.accessController.target); +// }); - it("should revert when a non-ADMIN tries to set AccessController", async () => { - await expect( - zns.rootRegistrar.connect(user).setAccessController(zns.accessController.target) - ).to.be.revertedWithCustomError( - zns.rootRegistrar, - AC_UNAUTHORIZED_ERR - ).withArgs(user.address, ADMIN_ROLE); - }); +// it("should revert when a non-ADMIN tries to set AccessController", async () => { +// await expect( +// zns.rootRegistrar.connect(user).setAccessController(zns.accessController.target) +// ).to.be.revertedWithCustomError( +// zns.rootRegistrar, +// AC_UNAUTHORIZED_ERR +// ).withArgs(user.address, ADMIN_ROLE); +// }); - it("should revert when setting an AccessController as EOA address", async () => { - await expect( - zns.rootRegistrar.connect(deployer).setAccessController(user.address) - ).to.be.revertedWithCustomError( - zns.rootRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(user.address); - }); +// it("should revert when setting an AccessController as EOA address", async () => { +// await expect( +// zns.rootRegistrar.connect(deployer).setAccessController(user.address) +// ).to.be.revertedWithCustomError( +// zns.rootRegistrar, +// AC_WRONGADDRESS_ERR +// ).withArgs(user.address); +// }); - it("should revert when setting an AccessController as another non-AC contract address", async () => { - await expect( - zns.rootRegistrar.connect(deployer).setAccessController(zns.rootRegistrar.target) - ).to.be.revertedWithCustomError( - zns.rootRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(zns.rootRegistrar.target); - }); +// it("should revert when setting an AccessController as another non-AC contract address", async () => { +// await expect( +// zns.rootRegistrar.connect(deployer).setAccessController(zns.rootRegistrar.target) +// ).to.be.revertedWithCustomError( +// zns.rootRegistrar, +// AC_WRONGADDRESS_ERR +// ).withArgs(zns.rootRegistrar.target); +// }); - it("should revert when setting a zero address as AccessController", async () => { - await expect( - zns.rootRegistrar.connect(admin).setAccessController(ethers.ZeroAddress) - ).to.be.revertedWithCustomError( - zns.rootRegistrar, - AC_WRONGADDRESS_ERR - ).withArgs(ethers.ZeroAddress); - }); - }); -}; \ No newline at end of file +// it("should revert when setting a zero address as AccessController", async () => { +// await expect( +// zns.rootRegistrar.connect(admin).setAccessController(ethers.ZeroAddress) +// ).to.be.revertedWithCustomError( +// zns.rootRegistrar, +// AC_WRONGADDRESS_ERR +// ).withArgs(ethers.ZeroAddress); +// }); +// }); +// }; \ No newline at end of file diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index c2e35d074..cbb299294 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -21,7 +21,6 @@ import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { time } from "@nomicfoundation/hardhat-network-helpers"; import { fundApprove } from "../register-setup"; import { - Addressable, ContractTransactionResponse, } from "ethers"; import { expect } from "chai"; diff --git a/test/helpers/types.ts b/test/helpers/types.ts index a359b8575..3a1fa52c5 100644 --- a/test/helpers/types.ts +++ b/test/helpers/types.ts @@ -21,7 +21,6 @@ import { } from "../../typechain"; import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { ICurvePriceConfig, IFixedPriceConfig } from "../../src/deploy/missions/types"; -import { Addressable } from "ethers"; import { IZNSContracts } from "../../src/deploy/campaign/types"; From fbc4468fc615f34f25fa2807fd83a501560771e6 Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Mon, 6 Oct 2025 19:24:29 -0700 Subject: [PATCH 25/26] Fixes based on Copilot's review --- test/ZNSSubRegistrar.test.ts | 1 - test/helpers/deploy/deploy-zns.ts | 1 + test/helpers/domain/domain.ts | 49 ++++++++++++++++--------------- test/helpers/register-setup.ts | 9 +++++- test/helpers/types.ts | 3 +- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/test/ZNSSubRegistrar.test.ts b/test/ZNSSubRegistrar.test.ts index b5a7e5813..5dbb06c1d 100644 --- a/test/ZNSSubRegistrar.test.ts +++ b/test/ZNSSubRegistrar.test.ts @@ -905,7 +905,6 @@ describe("ZNSSubRegistrar", () => { configs : Array; extrArray ?: Array; executor ?: SignerWithAddress; - // TODO dom: idk, am I right here? }) : Promise> => { const resultArray = []; let domObj; diff --git a/test/helpers/deploy/deploy-zns.ts b/test/helpers/deploy/deploy-zns.ts index 955d53e3f..fce69180f 100644 --- a/test/helpers/deploy/deploy-zns.ts +++ b/test/helpers/deploy/deploy-zns.ts @@ -48,6 +48,7 @@ import { import { DOMAIN_TOKEN_ROLE, REGISTRAR_ROLE } from "../../../src/deploy/constants"; import { getProxyImplAddress } from "../utils"; import { meowTokenName, meowTokenSymbol } from "../../../src/deploy/missions/contracts"; +import { IZNSContracts } from "../../../src/deploy/campaign/types"; export const deployAccessController = async ({ diff --git a/test/helpers/domain/domain.ts b/test/helpers/domain/domain.ts index cbb299294..72aed5880 100644 --- a/test/helpers/domain/domain.ts +++ b/test/helpers/domain/domain.ts @@ -21,6 +21,7 @@ import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { time } from "@nomicfoundation/hardhat-network-helpers"; import { fundApprove } from "../register-setup"; import { + Addressable, ContractTransactionResponse, } from "ethers"; import { expect } from "chai"; @@ -28,7 +29,6 @@ import { decodePriceConfig, encodePriceConfig } from "../pricing"; export default class Domain { - // TODO dom: need to make a class with a method for every possible feature of ZNS contracts zns : IZNSContracts; hash : string; @@ -283,34 +283,35 @@ export default class Domain { executor, } : { priceConfig ?: ICurvePriceConfig | IFixedPriceConfig | string; - pricerContract ?: string; + pricerContract ?: string | Addressable; executor ?: SignerWithAddress; }) { - if (priceConfig || - this.priceConfig !== undefined || - Object.keys(this.priceConfig).length === 0 - ) { - const args = [this.hash]; - - if (typeof priceConfig === "string") { - args.push(priceConfig); - - this.priceConfig = decodePriceConfig(priceConfig); + if (!priceConfig && !this.priceConfig) { + throw new Error("Domain Helper: priceConfig is not specified"); + } - } else { - args.push(encodePriceConfig(priceConfig as ICurvePriceConfig | IFixedPriceConfig)); + const config = + typeof priceConfig === "string" + ? priceConfig + : encodePriceConfig(priceConfig ?? this.priceConfig); - this.priceConfig = priceConfig as ICurvePriceConfig | IFixedPriceConfig; - } + this.priceConfig = + typeof priceConfig === "string" + ? decodePriceConfig(priceConfig) + : priceConfig ?? this.priceConfig; - args.push(pricerContract ? pricerContract : this.distrConfig.pricerContract); + const pricerAddr = pricerContract ?? this.distrConfig.pricerContract; - await this.zns.subRegistrar.connect(executor ? executor : this.owner).setPricerDataForDomain( - ...args - ); - } else { - throw new Error("Domain Helper: priceConfig is not specified"); + if (!this.hash || !config || !pricerAddr) { + throw new Error("Domain Helper: pricerData is not fully specified"); } + + await this.zns.subRegistrar.connect(executor ?? this.owner).setPricerDataForDomain( + this.hash, + config, + pricerAddr, + {} + ); } async setPaymentTypeForDomain ({ @@ -344,11 +345,13 @@ export default class Domain { accessType : bigint; executor ?: SignerWithAddress; }) : Promise { - if (!Object.values(AccessType).includes(accessType)) { + if (Object.values(AccessType).includes(accessType)) { return this.zns.subRegistrar.connect(executor ? executor : this.owner).setAccessTypeForDomain( this.hash, accessType, ); + } else { + throw new Error("Domain Helper: Invalid access type provided"); } // updating local var diff --git a/test/helpers/register-setup.ts b/test/helpers/register-setup.ts index fca8ab4e7..29d4f836d 100644 --- a/test/helpers/register-setup.ts +++ b/test/helpers/register-setup.ts @@ -86,7 +86,14 @@ export const fundApprove = async ({ await tokenContract.connect(user).mint(user.address, toMint); } - return tokenContract.connect(user).approve(await zns.treasury.getAddress(), totalPrice); + // return tokenContract.connect(user).approve(await zns.treasury.getAddress(), totalPrice); + const treasuryAddress = await zns.treasury.getAddress(); + const allowance = await tokenContract.allowance(user.address, treasuryAddress); + if (allowance < totalPrice) { + return tokenContract.connect(user).approve(treasuryAddress, totalPrice); + } + // Allowance is sufficient, no need to approve + return undefined; }; /** diff --git a/test/helpers/types.ts b/test/helpers/types.ts index 3a1fa52c5..6770a3f36 100644 --- a/test/helpers/types.ts +++ b/test/helpers/types.ts @@ -22,6 +22,7 @@ import { import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; import { ICurvePriceConfig, IFixedPriceConfig } from "../../src/deploy/missions/types"; import { IZNSContracts } from "../../src/deploy/campaign/types"; +import { Addressable } from "ethers"; export type GeneralContractGetter = Promise< @@ -80,7 +81,7 @@ export interface DeployZNSParams { } export interface IDistributionConfig { - pricerContract : string; + pricerContract : string | Addressable; priceConfig : string; paymentType : bigint; accessType : bigint; From 47c8a50ba2724aa5e9079620c403a06ec7daa95b Mon Sep 17 00:00:00 2001 From: MichaelKorchagin Date: Tue, 14 Oct 2025 15:29:02 -0700 Subject: [PATCH 26/26] CI check --- test/ZNSSubRegistrar.unit.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/ZNSSubRegistrar.unit.test.ts b/test/ZNSSubRegistrar.unit.test.ts index 1722263f4..8f3324775 100644 --- a/test/ZNSSubRegistrar.unit.test.ts +++ b/test/ZNSSubRegistrar.unit.test.ts @@ -36,6 +36,7 @@ import { IFullDomainConfig } from "./helpers/domain/types"; import { IFixedPriceConfig } from "../src/deploy/missions/types"; +// Separated SubRegistrar tests describe("ZNSSubRegistrar Unit Tests", () => { let deployer : SignerWithAddress; let rootOwner : SignerWithAddress;