Skip to content

Commit

Permalink
Merge pull request #3 from ensdomains/immutable-tokens-test
Browse files Browse the repository at this point in the history
fixed tests
  • Loading branch information
Arachnid authored Aug 13, 2024
2 parents 8782cc9 + 5613f19 commit e25cde4
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 121 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
name: Contract tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: "recursive"

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Use Bun 1.1.16
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.1.16

- run: bun install --frozen-lockfile

- name: Run tests
run: bun --filter contracts test:hardhat
Binary file modified bun.lockb
Binary file not shown.
19 changes: 19 additions & 0 deletions contracts/hardhat.config.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { HardhatUserConfig } from "hardhat/config";

import "@nomicfoundation/hardhat-foundry";
import "@nomicfoundation/hardhat-verify";
import "@nomicfoundation/hardhat-viem";
import "./tasks/esm_fix.cjs";

import("@ensdomains/hardhat-chai-matchers-viem");

const config = {
solidity: {
version: "0.8.25",
settings: {
evmVersion: "cancun",
},
},
} satisfies HardhatUserConfig;

export default config;
15 changes: 0 additions & 15 deletions contracts/hardhat.config.ts

This file was deleted.

11 changes: 8 additions & 3 deletions contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
{
"name": "contracts",
"module": "index.ts",
"type": "module",
"scripts": {
"test:hardhat": "hardhat test",
"compile:hardhat": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat compile",
"test:hardhat": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat test",
"test:forge": "echo \"Skipping forge test for now since there are no tests...\"",
"test": "bun run test:forge && bun run test:hardhat"
},
"devDependencies": {
"@ensdomains/hardhat-chai-matchers-viem": "^0.0.7",
"@nomicfoundation/hardhat-foundry": "^1.1.1",
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomicfoundation/hardhat-toolbox-viem": "^3.0.0",
"@nomicfoundation/hardhat-viem": "^2.0.0",
"@types/bun": "latest",
"@vitest/expect": "^1.6.0",
"chai": "^5.1.1",
"hardhat": "^2.22.2",
"ts-node": "^10.9.2",
"viem": "^2.9.12"
},
"peerDependencies": {
Expand Down
21 changes: 21 additions & 0 deletions contracts/tasks/esm_fix.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import fs = require("fs/promises");
import task_names = require("hardhat/builtin-tasks/task-names");
import config = require("hardhat/config");
import path = require("path");

config
.subtask(task_names.TASK_COMPILE_SOLIDITY)
.setAction(async (_, { config }, runSuper) => {
const superRes = await runSuper();

try {
await fs.writeFile(
path.join(config.paths.artifacts, "package.json"),
'{ "type": "commonjs" }'
);
} catch (error) {
console.error("Error writing package.json: ", error);
}

return superRes;
});
112 changes: 112 additions & 0 deletions contracts/test/ETHRegistry.t.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox-viem/network-helpers.js";
import { expect } from "chai";
import { fromHex, getAddress, labelhash, zeroAddress } from "viem";
import { deployEnsFixture, registerName } from "./fixtures/deployEnsFixture.js";

describe("ETHRegistry", function () {
it("registers names", async () => {
const { accounts, ethRegistry } = await loadFixture(deployEnsFixture);

const tx = await registerName({ ethRegistry, label: "test2" });
const expectedId =
fromHex(labelhash("test2"), "bigint") &
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n;

await expect(ethRegistry)
.transaction(tx)
.toEmitEvent("TransferSingle")
.withArgs(
getAddress(accounts[0].address),
zeroAddress,
accounts[0].address,
expectedId,
1n
);
await expect(
ethRegistry.read.ownerOf([expectedId])
).resolves.toEqualAddress(accounts[0].address);
});

it("registers locked names", async () => {
const { accounts, ethRegistry } = await loadFixture(deployEnsFixture);

const tx = await registerName({
ethRegistry,
label: "test2",
subregistryLocked: true,
resolverLocked: true,
});
const expectedId =
(fromHex(labelhash("test2"), "bigint") &
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n) |
3n;

await expect(ethRegistry)
.transaction(tx)
.toEmitEvent("TransferSingle")
.withArgs(
getAddress(accounts[0].address),
zeroAddress,
accounts[0].address,
expectedId,
1n
);
await expect(
ethRegistry.read.ownerOf([expectedId])
).resolves.toEqualAddress(accounts[0].address);
});

it("supports locking names", async () => {
const { accounts, ethRegistry } = await loadFixture(deployEnsFixture);

await registerName({ ethRegistry, label: "test2" });
const expectedId =
fromHex(labelhash("test2"), "bigint") &
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n;

await expect(
ethRegistry.read.ownerOf([expectedId])
).resolves.toEqualAddress(accounts[0].address);
await expect(
ethRegistry.read.ownerOf([expectedId | 3n])
).resolves.toEqualAddress(zeroAddress);
await ethRegistry.write.lock([expectedId, 0x3]);
await expect(
ethRegistry.read.ownerOf([expectedId | 3n])
).resolves.toEqualAddress(accounts[0].address);
await expect(
ethRegistry.read.ownerOf([expectedId])
).resolves.toEqualAddress(zeroAddress);
});

it("cannot unlock names", async () => {
const { accounts, ethRegistry } = await loadFixture(deployEnsFixture);

await registerName({
ethRegistry,
label: "test2",
subregistryLocked: true,
resolverLocked: true,
});
const expectedId =
(fromHex(labelhash("test2"), "bigint") &
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n) |
3n;

await expect(
ethRegistry.read.ownerOf([expectedId])
).resolves.toEqualAddress(accounts[0].address);
await expect(
ethRegistry.read.ownerOf([expectedId ^ 3n])
).resolves.toEqualAddress(zeroAddress);

await ethRegistry.write.lock([expectedId, 0x0]);

await expect(
ethRegistry.read.ownerOf([expectedId])
).resolves.toEqualAddress(accounts[0].address);
await expect(
ethRegistry.read.ownerOf([expectedId ^ 3n])
).resolves.toEqualAddress(zeroAddress);
});
});
77 changes: 7 additions & 70 deletions contracts/test/Ens.t.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,7 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox-viem/network-helpers.js";
import { expect } from "chai";
import { getAddress, keccak256, parseEventLogs, fromHex } from "viem";
import { deployEnsFixture, registerName } from "./fixtures/deployEnsFixture";
import { dnsEncodeName } from "./utils/utils";

describe("ETHRegistry", function () {
it("registers names", async () => {
const client = await hre.viem.getPublicClient();
const walletClients = await hre.viem.getWalletClients();
const { universalResolver, ethRegistry } = await loadFixture(
deployEnsFixture
);
const tx = await registerName({ ethRegistry, label: "test2" });
const receipt = await client.waitForTransactionReceipt({hash: tx});
const logs = parseEventLogs({abi: ethRegistry.abi, logs: receipt.logs })
const id = logs[0].args.id;
const expectedId = fromHex(keccak256("test2"), "bigint") & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n;
expect(id).to.equal(expectedId);
expect((await ethRegistry.read.ownerOf([id])).toLowerCase()).to.equal(walletClients[0].account.address);
});

it("registers locked names", async () => {
const client = await hre.viem.getPublicClient();
const walletClients = await hre.viem.getWalletClients();
const { universalResolver, ethRegistry } = await loadFixture(
deployEnsFixture
);
const tx = await registerName({ ethRegistry, label: "test", subregistryLocked: true, resolverLocked: true });
const receipt = await client.waitForTransactionReceipt({hash: tx});
const logs = parseEventLogs({abi: ethRegistry.abi, logs: receipt.logs })
const id = logs[0].args.id;
const expectedId = (fromHex(keccak256("test"), "bigint") & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n) | 3n;
expect(id).to.equal(expectedId);
expect((await ethRegistry.read.ownerOf([id])).toLowerCase()).to.equal(walletClients[0].account.address);
});

it("supports locking names", async () => {
const client = await hre.viem.getPublicClient();
const walletClients = await hre.viem.getWalletClients();
const { universalResolver, ethRegistry } = await loadFixture(
deployEnsFixture
);
const id = fromHex(keccak256("test2"), "bigint") & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n;
await registerName({ ethRegistry, label: "test2" });
expect((await ethRegistry.read.ownerOf([id])).toLowerCase()).to.equal(walletClients[0].account.address);
expect((await ethRegistry.read.ownerOf([id | 3n])).toLowerCase()).to.equal("0x0000000000000000000000000000000000000000");
await ethRegistry.write.lock([id, 0x3]);
expect((await ethRegistry.read.ownerOf([id | 3n])).toLowerCase()).to.equal(walletClients[0].account.address);
expect((await ethRegistry.read.ownerOf([id])).toLowerCase()).to.equal("0x0000000000000000000000000000000000000000");
});

it("cannot unlock names", async () => {
const client = await hre.viem.getPublicClient();
const walletClients = await hre.viem.getWalletClients();
const { universalResolver, ethRegistry } = await loadFixture(
deployEnsFixture
);
const id = fromHex(keccak256("test2"), "bigint") & 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8n | 3n;
await registerName({ ethRegistry, label: "test2", subregistryLocked: true, resolverLocked: true });
expect((await ethRegistry.read.ownerOf([id])).toLowerCase()).to.equal(walletClients[0].account.address);
expect((await ethRegistry.read.ownerOf([id ^ 3n])).toLowerCase()).to.equal("0x0000000000000000000000000000000000000000");
await ethRegistry.write.lock([id, 0x0]);
expect((await ethRegistry.read.ownerOf([id])).toLowerCase()).to.equal(walletClients[0].account.address);
expect((await ethRegistry.read.ownerOf([id ^ 3n])).toLowerCase()).to.equal("0x0000000000000000000000000000000000000000");
});
});
import { deployEnsFixture, registerName } from "./fixtures/deployEnsFixture.js";
import { dnsEncodeName } from "./utils/utils.js";

describe("Ens", function () {
it("returns eth registry for eth", async () => {
Expand All @@ -73,8 +10,8 @@ describe("Ens", function () {
);
const [fetchedEthRegistry, isExact] =
await universalResolver.read.getRegistry([dnsEncodeName("eth")]);
expect(isExact).to.be.true;
expect(fetchedEthRegistry).to.equal(getAddress(ethRegistry.address));
expect(isExact).toBe(true);
expect(fetchedEthRegistry).toEqualAddress(ethRegistry.address);
});

it("returns eth registry for test.eth without user registry", async () => {
Expand All @@ -85,7 +22,7 @@ describe("Ens", function () {
const [registry, isExact] = await universalResolver.read.getRegistry([
dnsEncodeName("test.eth"),
]);
expect(isExact).to.be.false;
expect(registry).to.equal(getAddress(ethRegistry.address));
expect(isExact).toBe(false);
expect(registry).toEqualAddress(ethRegistry.address);
});
});
40 changes: 28 additions & 12 deletions contracts/test/fixtures/deployEnsFixture.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,46 @@
import hre from "hardhat";
import { Address, bytesToHex, keccak256, stringToHex, zeroAddress } from "viem";
import { packetToBytes } from "../utils/utils";
import { Address, bytesToHex, keccak256, stringToHex } from "viem";
import { packetToBytes } from "../utils/utils.js";

export async function deployEnsFixture() {
const walletClients = await hre.viem.getWalletClients();
const publicClient = await hre.viem.getPublicClient();
const accounts = await hre.viem
.getWalletClients()
.then((clients) => clients.map((c) => c.account));

const datastore = await hre.viem.deployContract("RegistryDatastore", []);
const rootRegistry = await hre.viem.deployContract("RootRegistry", [datastore.address]);
const ethRegistry = await hre.viem.deployContract("ETHRegistry", [datastore.address]);
const rootRegistry = await hre.viem.deployContract("RootRegistry", [
datastore.address,
]);
const ethRegistry = await hre.viem.deployContract("ETHRegistry", [
datastore.address,
]);
const universalResolver = await hre.viem.deployContract("UniversalResolver", [
rootRegistry.address,
]);
await rootRegistry.write.grantRole([
keccak256(stringToHex("SUBDOMAIN_ISSUER_ROLE")),
walletClients[0].account.address,
accounts[0].address,
]);
await ethRegistry.write.grantRole([
keccak256(stringToHex("REGISTRAR_ROLE")),
walletClients[0].account.address,
accounts[0].address,
]);
await rootRegistry.write.mint([
"eth",
walletClients[0].account.address,
accounts[0].address,
ethRegistry.address,
true,
]);

return { datastore, rootRegistry, ethRegistry, universalResolver };
return {
publicClient,
accounts,
datastore,
rootRegistry,
ethRegistry,
universalResolver,
};
}

export type EnsFixture = Awaited<ReturnType<typeof deployEnsFixture>>;
Expand Down Expand Up @@ -64,10 +79,11 @@ export const registerName = async ({
expiry?: bigint;
owner?: Address;
subregistry?: Address;
locked?: boolean;
subregistryLocked?: boolean;
resolverLocked?: boolean;
}) => {
const owner =
owner_ ?? (await hre.viem.getWalletClients())[0].account.address;
const flags = (subregistryLocked ? 1n : 0n) | (resolverLocked ? 2n : 0n);
return await ethRegistry.write.register([label, owner, subregistry, flags, expiry]);
const flags = (subregistryLocked ? 1 : 0) | (resolverLocked ? 2 : 0);
return ethRegistry.write.register([label, owner, subregistry, flags, expiry]);
};
Loading

0 comments on commit e25cde4

Please sign in to comment.