Skip to main content
ensforge wordmark and anvil logo on a black and gold metallic background

ensforge

About

Type-safe ENS tools that route name lookups, record updates, and registration through the right contracts, with standalone actions, an SDK, and React hooks.

Status
Maintained
Built with
TypeScriptEffectViemReactWagmi

ensforge gives applications one API for working with Ethereum Name Service (ENS). A caller asks for a name's owner, updates a record, or starts a registration. The library works out which contracts need to handle that request.

The same actions are available as standalone functions, a configured SDK client, and React hooks.

An ENS name does not always follow the same contract path. It can use ENSv1, be reserved for migration, or already use ENSv2. That state affects where an application reads ownership, sends a renewal, or updates records.

Putting those branches in application code means carrying protocol details into every feature. A profile view needs an owner and resolver records. A renewal form needs a price and a transaction. Both still need to reach the right contracts.

ensforge keeps that routing in the library while exposing the name's state when the application needs it.

Each action normalizes the name, discovers the relevant registry state, and selects the supported route. A renewal can go through the ENSv1 controller, the ENSv2 registrar, or a compatibility path.

Small actions such as getOwner and isMigrated answer a specific question. getNameState returns a fuller picture, including whether the name is native to ENSv2, migrated, or still reserved. Applications can use that distinction to explain what a user can do next.

ensforge protocol routing guide showing network profiles and ENS name states

Name state determines which registry and contract path an action uses.

The project is split into four packages:

  • @ensforge/contracts contains contract ABIs, deployment addresses, and shared interfaces.
  • @ensforge/core exposes framework-independent actions and utilities.
  • @ensforge/sdk binds configuration once and groups actions by capability.
  • @ensforge/react adds reactive queries, mutations, Suspense, and caching through Effect Atom.

Ethereum clients come from Viem, with support for an existing Wagmi configuration. The library adds ENS-specific behavior around those clients.

ENS operations combine validation, contract discovery, and RPC calls. Effect keeps those steps composable, with typed failures, timeouts, interruption, and tracing. A temporary RPC failure can be retried separately from invalid input or a rejected wallet request.

Every action has one Effect implementation. The Promise API runs it for ordinary async code; .effect exposes it for composition inside an Effect application. Both use the same routing and return the same success value.

The SDK binds the network and clients once, then groups methods by ENS capability.

Install the SDK with its Effect and Viem peers:

pnpm add @ensforge/sdk effect@rc viem

Create a shared client.ts module:

client.ts
import { Ensforge } from "@ensforge/sdk";
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

export const sdk = new Ensforge({
  network: "mainnet",
  publicClient: createPublicClient({
    chain: mainnet,
    transport: http(),
  }),
});
ensforge SDK getting-started guide showing installation and Viem client setup

The SDK binds a network and public client once for subsequent ENS reads.

Read an ENS profile with the shared client:

index.ts
import { sdk } from "./client";

const name = "ens.eth";

export const profile = await sdk.batch.readBatch({
  owner: sdk.name.getOwner({ name }),
  address: sdk.records.getAddress({ name }),
  avatar: sdk.records.getAvatar({ name }),
});

The same reads through .effect, with bounded concurrency and a shared timeout:

import { Effect } from "effect";
import { sdk } from "./client";

const name = "ens.eth";

const program = Effect.all(
  {
    owner: sdk.name.getOwner.effect({ name }),
    address: sdk.records.getAddress.effect({ name }),
    avatar: sdk.records.getAvatar.effect({ name }),
  },
  { concurrency: 3 },
).pipe(Effect.timeout("5 seconds"));

export const profile = await Effect.runPromise(program);

Core exposes the same APIs as standalone functions: getOwner(config, parameters) and getOwner.effect(config, parameters).

ensforge Effect guide composing name state and record lookups with Effect.gen

Name state and record lookups compose into one Effect operation.

EnsforgeProvider accepts the same SDK instance or client configuration. Hooks such as useOwner and useAvatar share cached reads through Effect Atom and expose loading, failure, and success states. Mutation hooks resolve the connected wallet when they execute.

ensforge React getting-started guide showing installation and EnsforgeProvider setup

The React provider shares the client configuration used by ENS hooks.

Concurrent reads are separate from RPC batching. ensforge can combine compatible onchain reads through Multicall3 while keeping other requests on their required execution path. A settled batch can return partial results when one lookup fails.

Writes have more steps. ensforge resolves the wallet account, checks authorization, and simulates by default before execution. Direct write intents can also be prepared for simulation, estimation, or batching before reaching the wallet.

Wallet batching depends on what the connected wallet supports. Automatic mode falls back to sequential transactions. If an operation must succeed as a whole, the caller needs to require atomic execution explicitly.

Registration and migration can span several stages. Treating them as one pending transaction would hide the state an application needs to show and recover.

ensforge returns progress that the application can persist and pass back when resuming. It checks that the inputs still describe the same plan and skips stages already recorded as complete. The application remains responsible for saving that progress.

ensforge writes guide configuring a wallet with simulation and confirmation settings

Write configuration makes simulation and confirmation requirements explicit.

ensforge is open source under Apache-2.0. It covers name state, resolver records, registration, renewals, migration, wrapping, DNS, and reverse resolution.

The documented network profiles use the supported ENS deployment on mainnet and the current ENSv2 deployment with ENSv1 compatibility contracts on Sepolia. Available operations depend on the network and the name's state.

Start with the SDK guide (opens in a new tab) for installation, reads, and wallet setup. The Effect guide (opens in a new tab) covers execution control, and the React guide (opens in a new tab) covers providers and hooks.

The repository (opens in a new tab) includes the implementation and integration tests. For missing workflows or unexpected behavior, open an issue with the network, action, and a reproducible example.