Skip to content

Adapt ensjs for Electroneum ENS#1

Merged
andrepatta merged 8 commits into
mainfrom
feature/electroneum-testnet-support
Jul 20, 2026
Merged

Adapt ensjs for Electroneum ENS#1
andrepatta merged 8 commits into
mainfrom
feature/electroneum-testnet-support

Conversation

@andrepatta

Copy link
Copy Markdown
Member

Ports ensjs to Electroneum ENS: registrar TLD .etn, Electroneum testnet (chain 5201420), publishable as @etn-sc/ensjs. Contracts come from @etn-sc/ens-contracts (ABI-identical to upstream; only TLD constants differ).

Library

  • The registrar TLD is defined once (REGISTRAR_TLD = 'etn') and drives both runtime comparisons and the `${string}.etn` template-literal types. The 'eth-2ld' specifier strings are kept as opaque tags to avoid churning the public API.
  • contracts/consts.ts supports electroneumTestnet only, with addresses sourced from the testnet deployment records — including canonical multicall3, which viem's Electroneum chain definitions don't ship. Legacy/wrapped contract entries are removed (they don't exist on Electroneum and were never consumed). Mainnet (52014) gets added once deployed; pnpm verify:addresses checks consts.ts against the package's deployment records.
  • No ENS subgraph exists for Electroneum yet: addEnsContracts takes a subgraphUrl override, and /subgraph functions are unusable until one is deployed.

Test environment (docker-free)

  • pnpm tenv start now runs a local foundry anvil, executes the @etn-sc/ens-contracts rocketh deploy pipeline in-process (no legacy/wrapped contracts, matching the real chain), registers all ~95 .etn fixtures via plain viem, and runs vitest. All hardhat machinery and the docker-based ens-test-env are removed.
  • Suite fully green: 382 tests / 62 files, plus a read-path smoke test against the live testnet (pnpm smoke:testnet).
  • Works on both old (--odyssey) and current anvil releases; CI installs foundry.

Packaging

  • Renamed to @etn-sc/ensjs (@etn-sc/ensjs-react for the hooks package), repository/README updated for the fork. npm publishing is manual only — both CI auto-publish workflows are guarded off.

Known caveat

@etn-sc/ens-contracts' DNSSEC algorithm-13 contract (P256SHA256Algorithm) relies on the EIP-7951 P256VERIFY precompile, which the live Electroneum chains don't have — P256-signed DNSSEC verification silently fails on-chain (probed testnet + mainnet directly). The local test env enables the precompile in anvil, so DNS tests pass; the real fix belongs in ens-contracts (restore the pure-Solidity P256 implementation) or etn-sc (adopt the precompile). Low severity while DNSSEC is inert on Electroneum.

Port the library to work against the Electroneum ENS deployment from
electroneum/ens-contracts (ABI-identical to upstream; only TLD constants
differ):

- Define the registrar TLD once as REGISTRAR_TLD = 'etn' in utils/consts
  and use it at the seven ground-truth 'eth' comparisons (getNameType,
  validation, getOwner, createSubname, getSubnames, filters). All
  'eth-2ld'-gated functions adapt automatically; the specifier strings
  are kept as opaque tags to avoid public API churn. Template-literal
  name types now derive from typeof REGISTRAR_TLD.
- Replace mainnet/sepolia in contracts/consts with electroneumTestnet
  (5201420), addresses sourced from ens-contracts deployment records,
  including canonical multicall3 (viem's Electroneum chain definitions
  ship no contracts). Drop the legacy/wrapped contract entries, which
  don't exist on Electroneum and were never consumed by function code.
- Replace the subgraphApiKey option of addEnsContracts with a direct
  subgraphUrl override; no ENS subgraph exists for Electroneum yet, so
  the default is a localhost placeholder.
- Add scripts/smokeElectroneumTestnet.mjs, a read-only smoke test that
  passes against the live testnet (availability, pricing, ownership,
  expiry, records via UniversalResolver, multicall3 batching, reverse).

Electroneum mainnet (52014) addresses will be added once its contracts
are deployed. The vitest suite still targets the upstream .eth local
test env and is adapted separately.
Add the published Electroneum ens-contracts package as a devDependency
and a verification script that checks the addresses in
src/contracts/consts.ts against the package's shipped deployment
records (pnpm verify:addresses, after pnpm build). Multicall3 is
compared against a deployment record when one exists, falling back to
the canonical singleton address, matching the deploy pipeline's
semantics.

When Electroneum mainnet is deployed, its addresses arrive via a
version bump of the package and its records are the source for the
mainnet entry in consts.ts.

Also add pnpm script entries for the two .mjs scripts (smoke:testnet,
verify:addresses) and apply Biome formatting to the smoke script,
which was committed unformatted.

@ensdomains/ens-contracts stays as a devDependency for now because
hardhat.config.cts still points the local test environment at it; that
machinery is replaced when the test env is adapted to the Electroneum
contracts.
…flow

The local test environment now deploys the real Electroneum ENS stack
(from @etn-sc/ens-contracts) instead of the upstream .eth contracts:

- scripts/testEnv.mjs replaces the @ensdomains/ens-test-env CLI:
  it starts a local foundry anvil (chain 1337, same timestamp/snapshot
  choreography as before), runs the deploy, then vitest. Docker is no
  longer needed. Anvil runs with --odyssey to enable the EIP-7951
  P256VERIFY precompile that the fork's DNSSEC algorithm-13 contract
  calls — note the real Electroneum chains do NOT have that precompile
  (verified by probing 0x100 on testnet and mainnet with a valid P-256
  signature), so P256-signed DNSSEC verification works locally but is
  silently broken on the live chains; fixing that belongs in
  ens-contracts (restore the pure-Solidity P256 implementation) or in
  etn-sc (adopt the precompile).
- scripts/deployTestEnv.mjs runs the package's precompiled rocketh
  deploy pipeline in-process with electroneumTestnet-like tags (no
  legacy/wrapped contracts), registers the test fixtures, and writes
  DEPLOYMENT_ADDRESSES to .env.local. scripts/rockethAliasHook.mjs
  makes the precompiled scripts runnable under plain node (resolves
  the '@rocketh' alias, retries bare imports across pnpm's isolated
  layout, injects JSON import attributes, shims tsx and hardhat).
- scripts/fixtures.mjs ports all the old hardhat-deploy fixture
  scripts to plain viem, registering the same ~95 names under .etn.
  Legacy/wrapped fixture states are recreated the way they arise on
  the real chain: modern-controller registration plus
  NameWrapper.wrapETH2LD (the retired legacy/wrapped controllers do
  not exist on Electroneum). ABI records encode through the library's
  own encodeAbi (the standalone cbor package miscompiles under
  node >= 26). Accounts are topped up because OwnedUsdOracle pricing
  makes multi-century durations unaffordable at default balances.
- All hardhat machinery is removed: deploy/, utils/ name generators,
  hardhat.config.cts, the wrapped-controller artifacts, the hh script,
  and the hardhat/hardhat-deploy/@ensdomains/ens-contracts/
  @ensdomains/ens-test-env devDependencies with their pnpm patches.
  NoMulticallResolver/OldResolver artifacts stay (deployed by the
  fixtures for resolver edge-case tests).
- CI installs foundry instead of relying on docker anvil.
- Sweep every .eth fixture/test name to .etn and update namehash,
  labelhash, and DNS-encoded-name constants and inline snapshots to
  their .etn values (including namehash('etn') as the registrar node).
- Remove the live-Ethereum-network tests (CCIP against mainnet/sepolia
  ENS, getDnsOffchainData, ENSv2 forward-compat, jessesum.eth/
  taytems.xyz records): they target Ethereum ENS infrastructure that
  this fork intentionally no longer supports. Local CCIP coverage via
  ccipRequest/ccipBatchRequest utils remains; ccipRequest unit tests
  now build their chain from electroneumTestnet.
- addTestContracts.ts: read Multicall3 (rocketh deployment name) and
  drop the legacy/wrapped contract entries, which don't exist in the
  Electroneum deployment; tests that asserted the legacy resolver
  address now assert the PublicResolver.
- vitest: switch environment from happy-dom to node (nothing under
  test touches DOM APIs, and happy-dom's AbortController breaks
  node >= 26's fetch); a localStorage stub for the labels cache lives
  in setup.ts. Subgraph tests are excluded until an Electroneum ENS
  subgraph exists.
- getPrice expectations updated for OwnedUsdOracle pricing ($5/yr at
  the default $0.00086/ETN test value).

Full suite: 62 files, 382 tests, all passing via
pnpm tenv start --extra-time 11368000.
CI installs the latest foundry, whose anvil (1.7.x) broke the test
environment in two ways, both reproduced locally against the 1.7.1
binary:

- anvil 1.7.x dropped the --odyssey flag (exit code 2 at startup); its
  default hardfork already includes the Osaka P256VERIFY precompile
  that the flag was providing. testEnv.mjs now retries without the
  flag when anvil rejects it (older anvils still need it), and prints
  anvil's stderr when startup genuinely fails instead of swallowing it.
- anvil 1.7.x slightly underestimates gas for the timestamp-sensitive
  controller registrations, so fixture transactions died out-of-gas
  (gasUsed == gasLimit). The fixture writer now pads the node's
  estimate by 1.5x.

Verified: full run (382/382) against anvil 1.7.1 via the fallback
path, and the deploy against anvil 1.2.3 via --odyssey.
The pkg-pr-new GitHub App (upstream's continuous preview-release
service) is not installed on this fork, so the step failed on every
push after the tests had already passed. Preview builds of upstream's
package from an Electroneum fork aren't wanted anyway.
- @ensdomains/ensjs -> @etn-sc/ensjs and @ensdomains/ensjs-react ->
  @etn-sc/ensjs-react across package manifests, source doc-comments,
  the error version string (getVersion), tests, examples, workflows,
  and the changesets changelog repo. repository fields now point at
  electroneum/ensjs, and both packages carry
  publishConfig.access=public (scoped packages default to restricted).
- README rewritten for the fork: @etn-sc/ensjs install, Electroneum
  testnet example, .etn TLD, links to electroneum/ens-contracts, and a
  note that /subgraph functions need a not-yet-existing subgraph.
- The release workflow's repository_owner guard now matches
  electroneum, so the changesets flow can run on this repo. Publishing
  uses npm OIDC trusted publishing (id-token: write, no NPM_TOKEN):
  the @etn-sc npm org must have trusted publishing configured for the
  electroneum/ensjs repo's publish.yml workflow before the first
  release.

Verified: pnpm publish --dry-run resolves @etn-sc/ensjs@4.3.1 to
registry.npmjs.org with a clean tarball (dist/ + src/, no tests), both
packages build, and the full test suite passes (382/382).
Both automated publish paths (the changesets flow on main pushes and
the prerelease flow on GitHub releases) are guarded off. Publishing to
npm is done manually with pnpm publish from packages/ensjs.
@andrepatta
andrepatta merged commit 523016a into main Jul 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant