Resolve Basenames on Base — forward (
name → address), reverse (address → name), and text records. A tiny TypeScript SDK + CLI built on viem.
Basenames are Base's human-readable names for wallets — like tomiin.base.eth instead of 0xaA0a…8DD5. They're built on ENS and follow ENSIP-19, which means resolving them correctly (especially reverse — address → name) takes a few non-obvious steps.
I built basenames-js so you don't have to think about any of that: it wraps the ENS + ENSIP-19 machinery behind three calls, on both an SDK and a CLI.
npm install basenames-js viemviem is a peer dependency.
import { Basenames } from "basenames-js";
const bn = new Basenames({ rpcUrl: process.env.MAINNET_RPC_URL });
// name -> address
await bn.resolve("tomiin.base.eth"); // "0xaA0a…8DD5"
// address -> Base primary name (ENSIP-19 reverse)
await bn.reverse("0xaA0a5596278E2518AB357A6E20f813AfDeeE8DD5"); // "tomiin.base.eth"
// text records
await bn.getText("tomiin.base.eth", "avatar");
// address + common profile records in one call
await bn.profile("tomiin.base.eth");
// { name, address, avatar, url, description, twitter }# name -> address
npx basename resolve tomiin.base.eth --rpc https://your-mainnet-rpc
# address -> name
npx basename lookup 0xaA0a5596278E2518AB357A6E20f813AfDeeE8DD5 --rpc https://your-mainnet-rpc
# a text record
npx basename record tomiin.base.eth avatar --rpc https://your-mainnet-rpc
# full profile
npx basename profile tomiin.base.eth --rpc https://your-mainnet-rpcYou can also set BASENAMES_RPC_URL instead of passing --rpc every time.
Basenames resolve through Ethereum mainnet (L1) ENS with CCIP-read into Base — so you point this at an Ethereum mainnet RPC, not a Base RPC. Per Base's own guidance, reverse resolution (ENSIP-19) is computationally heavy, so a private/dedicated mainnet RPC (Alchemy, QuickNode, etc.) is strongly recommended — public endpoints often rate-limit or fail the reverse path.
There can also be a short delay between a Basename's registration and when it resolves via ENSIP-19, due to state-proof production.
new Basenames({ rpcUrl? })
bn.resolve(name) // -> Address | null (forward)
bn.reverse(address) // -> string | null (reverse, ENSIP-19)
bn.getText(name, key) // -> string | null (text record)
bn.profile(name) // -> { name, address, avatar, url, description, twitter }Every wallet UI, "send to a name" flow, and profile card needs to turn names into addresses and back. On Base that means ENS + ENSIP-19 + CCIP-read — correct, but fiddly. basenames-js is the small, typed helper I wanted: three calls, no contract addresses to look up, works from Node or the command line.
npm install
npm run typecheck
npm run buildMIT © tomiin
- Base docs — Basenames with viem: https://docs.base.org/identity/basenames/basenames-wagmi-tutorial
- ENSIP-19 (L2 reverse resolution): https://docs.ens.domains/ensip/19/
- Basenames contracts: https://github.com/base/basenames
