Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
422480a
Add comprehensive ENSv2 documentation
wentelteefje Apr 27, 2026
f3b5a22
ENSv2 docs: structural improvements, widgets, and FrenCallout
wentelteefje Apr 27, 2026
6ef27db
Remove working files and clean up .gitignore
wentelteefje Apr 27, 2026
16f979b
Change overview title, add what's new in v2 to PermReg page
wentelteefje Apr 28, 2026
69150c9
ERC1155Singleton fixes, reverse resolution page, widget subsections
wentelteefje Apr 29, 2026
cb63ffb
- Add ContractReference expandable component for contract reference s…
wentelteefje Apr 30, 2026
fcccad3
Move widgets to H3 sections, add title for frencallout
wentelteefje Apr 30, 2026
b71f987
Add new migration page template (WIP)
wentelteefje Apr 30, 2026
c156303
Fix migration page: correct BONUS_PERIOD (62 days, not 90), add time …
wentelteefje May 1, 2026
1adec41
Update migration page for case study revisions
wentelteefje May 5, 2026
91503fd
Add self-hosted ABC fonts and Tailwind font families
ali-rasheed Apr 29, 2026
9a730bb
Use bunx for all Vocs script invocations.
ali-rasheed May 1, 2026
2cad38f
Apply ENS typography defaults and font tuning.
ali-rasheed May 1, 2026
78848c4
Update src/pages/contracts/ensv2/mutable-token-ids.mdx
wentelteefje May 7, 2026
80f217a
Revert "Use bunx for all Vocs script invocations."
ali-rasheed May 7, 2026
9b1f084
Align docs design tokens with ENS Core palette and document UI patterns.
ali-rasheed May 7, 2026
693ee7c
Adjust profile and button shape/ring styling to match updated UI lang…
ali-rasheed May 7, 2026
31859f4
Ignore local Netlify metadata in the repository.
ali-rasheed May 7, 2026
e21f001
Fix resolver scope to per-account, restore 28-day grace period, add n…
wentelteefje May 8, 2026
380ab0e
Remove misleading from overview, clarify v1 registrations and renewa…
wentelteefje May 9, 2026
f0567e9
Add on-chain DNSSEC note to DNS resolvers page, add RegistryCreated e…
wentelteefje May 12, 2026
18e8100
Merge remote-tracking branch 'upstream/master' into feature/ensv2-docs
wentelteefje May 12, 2026
9371ade
Add verifiable-factory repo link, clarify BatchRegistrar for ENSv1 mi…
wentelteefje May 12, 2026
ab9af22
Fix reverse resolution intro to credit v1 for multi-chain support, fi…
wentelteefje May 12, 2026
e11efbb
restructure overview page, clarify factory is default not but not req…
wentelteefje May 13, 2026
835cdf5
style(docs): refresh global styles and design tokens
ali-rasheed May 13, 2026
9588c49
chore(vocs): tune theme and normalize config formatting
ali-rasheed May 13, 2026
3d888b2
style(components): use semi-mono for ENS name labels
ali-rasheed May 13, 2026
521d84b
style(docs): refresh global styles and design tokens
ali-rasheed May 13, 2026
d9da958
chore(vocs): tune theme and normalize config formatting
ali-rasheed May 13, 2026
9adffed
style(components): use semi-mono for ENS name labels
ali-rasheed May 13, 2026
afec27a
Merge branch 'ensdomains:ens-brand-refresh' into ens-brand-refresh
ali-rasheed May 13, 2026
09d1977
Apply fixes to migration page based on post-audit branch
wentelteefje May 14, 2026
acf81a8
Merge pull request #1 from ali-rasheed/ens-brand-refresh
wentelteefje May 14, 2026
b9c1d19
adjust eth registrar, perm resolver, migration and registry temp page…
wentelteefje May 18, 2026
7998689
more registrar fixes
wentelteefje May 18, 2026
af66267
overhaul permissioned registry prose, refactor metadata for post-audi…
wentelteefje May 20, 2026
266e87f
overhaul universal resolver v2 page, verify and fix dns-resolvers pag…
wentelteefje May 20, 2026
22e633b
Overhaul registry-template page, fix verifiable-factory technical ina…
wentelteefje May 27, 2026
559342c
Address Ram's comments on EAC, PermReg pages
wentelteefje May 27, 2026
b4462d2
pull scripts/ensips.ts from upstream master
wentelteefje May 27, 2026
de678fd
Fix technical inaccuracies across ENSv2 docs (dns-resolvers, emancipa…
wentelteefje Jun 3, 2026
0251d20
Add MonoDiagram component for box-drawing diagrams, replace code bloc…
wentelteefje Jun 3, 2026
5b878fb
Fix cross-page consistency issues, broken links, and factual inaccura…
wentelteefje Jun 4, 2026
67e22d9
Align EAC, PermReg, and PermResolver docs with post-audit PRs #333 an…
wentelteefje Jun 8, 2026
778d004
Add proxy deployment code example to Verifiable Factory
wentelteefje Jun 8, 2026
86c2fd8
Fix code example accuracy and add missing examples across ENSv2 docs …
wentelteefje Jun 8, 2026
4da9572
Add contract developers tutorial (subname registrar guide); add resol…
wentelteefje Jun 11, 2026
8d7e352
Refactor subregistry deployment on Subregistrar guide page, add some …
wentelteefje Jun 11, 2026
de1055b
Fix indexing page: event order, TokenResource at registration only, P…
wentelteefje Jul 2, 2026
6240b74
Add ENS Explorer (Sepolia) link to ENSv2 overview
wentelteefje Jul 2, 2026
0b3e708
Add sepolia-official-v1-20260525-r2 ENSv2 deployments table to overv…
wentelteefje Jul 9, 2026
25fe646
Expand indexing page with subgraph research findings; fix migration p…
wentelteefje Jul 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ src/data/generated/*
!src/data/generated/.keep

.wrangler
.claude
.claude
# Local Netlify folder
.netlify
45 changes: 45 additions & 0 deletions design-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Design Patterns

This document captures high-signal UI conventions for the docs site so brand and implementation choices stay consistent.

## Core Tokens

- Use CSS custom properties in `src/styles.css` for global tokens.
- Prefer semantic token names (`--ens-*`) over hardcoded values in component styles.

## Buttons

- All button controls use a 4px corner radius.
- Source of truth: `--ens-radius-button` in `src/styles.css`.
- Applied to: `button`, `input[type='button']`, `input[type='submit']`, and `input[type='reset']`.

## Tables

- All documentation tables use `rounded-md` corners (6px).
- Source of truth: `--ens-radius-table` in `src/styles.css`.
- Applied to Vocs table wrappers/content to keep corners visibly clipped.

## Typography

- Primary sans serif: `ABCMonumentGrotesk`.
- Serif: `ABCMarist`.
- Monospace: `ABCMonumentGroteskMono` and `ABCMonumentGroteskSemiMono`.
- Keep `font-display: swap` for self-hosted font loading behavior.

## Color System

- Use `--ens-*` palette tokens and semantic aliases (`--ens-background`, `--ens-text`, etc.).
- Define both light (`:root`) and dark (`.dark`) token values in `src/styles.css`.
- Figma source of truth: [`ENS Core` color tokens](https://www.figma.com/design/2sH9SoYCbfma5clol8dFP4/%F0%9F%93%93--ENS-Core?node-id=514-12&p=f&t=TTwQnH0qKnppCExL-0) (node `514:12`).

### Figma Palette Extract (current)

- **Lapis**: `100 #DBF0F8`, `300 #80C4E0`, `400 #39B4EA`, `500 #0082BB`, `900 #02293B`
- **Quartz**: `100 #EEEDED`, `300 #C7C6C4`, `400 #737373`, `500 #595755`, `900 #191919`
- **Peridot**: `100 #D1EEDF`, `300 #65D388`, `400 #1CBF46`, `500 #007C20`, `900 #033010`
- **Garnet**: `100 #FEEAF0`, `300 #FFB0D0`, `400 #F569AB`, `500 #E72A96`, `900 #5A0024`
- **Citrine**: `100 #F8F7E2`, `300 #E1B77E`, `400 #E7A259`, `500 #984D1B`, `900 #441B03`

### Current Mapping Rule

- `--ens-blue-primary` maps to **Lapis 500** (`#0082BB`) and is the default accent blue used by Vocs theme variables.
16 changes: 9 additions & 7 deletions scripts/ensips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ export async function ensips() {
'https://api.github.com/repos/ensdomains/ensips/contents/ensips',
{ headers: githubHeaders }
)
if (!ensipsRepoRes.ok) throw new Error('Failed to fetch ENSIPs')
if (!ensipsRepoRes.ok) {
const body = await ensipsRepoRes.text()
throw new Error(
`Failed to fetch ENSIPs: ${ensipsRepoRes.status} ${ensipsRepoRes.statusText} — ${body}`
)
}
const files = ((await ensipsRepoRes.json()) as DirectoryContents).filter(
(f) => f.name.endsWith('.md')
)
Expand Down Expand Up @@ -173,15 +178,12 @@ async function inlineSubdirectoryFiles(
markdown: string,
ensipNumber: number
): Promise<string> {
// Replace lines containing links to subdirectory .md files
// (e.g. "- [text](./19/supported.md)") with the actual file content.
// Matches the entire line to avoid leftover list markers.
const subfileLink =
/^[^\S\n]*(?:[-*]|\d+\.)\s*\[([^\]]*)\]\(\.\/\d+\/([^)]+\.md)\)\s*$/gm
// Matches [](./NUMBER/file.md) — content inclusion directives
const subfileLink = /\[\]\(\.\/\d+\/([^)]+\.md)\)/gm
let result = markdown

for (const match of markdown.matchAll(subfileLink)) {
const [fullMatch, , filename] = match
const [fullMatch, filename] = match
const url = `https://raw.githubusercontent.com/ensdomains/ensips/master/ensips/${ensipNumber}/${filename}`
const res = await fetchWithRetry(url)

Expand Down
233 changes: 233 additions & 0 deletions scripts/ensv2-deployments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import fs from 'fs/promises'
import path from 'path'
import { Hex } from 'viem'

// ENSv2 deployment addresses, sourced from what ENSjs v2 tracks.
//
// Pinned to a commit on the `feature/fet-1885-ensjs-refactor` branch so the
// build cannot break if the branch is force-pushed or deleted. To pick up new
// deployments, bump the SHA:
// git ls-remote https://github.com/ensdomains/ensjs refs/heads/feature/fet-1885-ensjs-refactor
// and delete src/data/generated/ensv2-deployments.json to re-fetch.
//
// TODO: switch to ingesting a proper deployments file once ensjs/ens-contracts
// publish one for ENSv2 (only the fetch + parse below should need to change).
const ENSJS_COMMIT = 'd946c1fb520fe1989d9e50687b545f341d366e62'
const ENSJS_L1_URL = `https://raw.githubusercontent.com/ensdomains/ensjs/${ENSJS_COMMIT}/packages/ensjs/src/clients/l1.ts`

const CONTRACTS_V2_BLOB =
'https://github.com/ensdomains/contracts-v2/blob/main/contracts'

// Deployment artifact snapshot in contracts-v2 that corresponds to the
// deployment set ensjs tracks (verified address-by-address; the generate step
// below re-checks this and fails on any mismatch). The newer `deployments/sepolia`
// set on main is NOT the one ensjs uses yet.
const ABI_SNAPSHOT = 'sepolia-official-v1-20260525-r2'
const ABI_BLOB = `https://github.com/ensdomains/contracts-v2/blob/main/contracts/deployments/${ABI_SNAPSHOT}`
const ABI_RAW = `https://raw.githubusercontent.com/ensdomains/contracts-v2/main/contracts/deployments/${ABI_SNAPSHOT}`

type ENSv2Deployment = {
name: string
ensjsKey: string
abiFilename?: string // artifact name in the contracts-v2 snapshot
address?: Hex
sourceUrl?: string
abiUrl?: string
}

export type ENSv2DeploymentsByChain = {
name: string // Sepolia, etc.
slug: string // sepolia, etc.
contracts: ENSv2Deployment[]
}

// Exactly the `// v2` section of `supportedL1Contracts` in ensjs l1.ts,
// mapped to display names and contracts-v2 source files.
const ENSV2_CONTRACTS: ENSv2Deployment[] = [
{
name: 'ETHRegistry',
ensjsKey: 'ensRegistry',
abiFilename: 'ETHRegistry',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/registry/PermissionedRegistry.sol`,
},
{
name: 'ETHRegistrar',
ensjsKey: 'ensEthRegistrar',
abiFilename: 'ETHRegistrar',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/registrar/ETHRegistrar.sol`,
},
{
name: 'StandardRentPriceOracle',
ensjsKey: 'ensStandardRentPriceOracle',
abiFilename: 'StandardRentPriceOracle',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/registrar/StandardRentPriceOracle.sol`,
},
{
name: 'VerifiableFactory',
ensjsKey: 'ensVerifiableFactory',
abiFilename: 'VerifiableFactory',
sourceUrl:
'https://github.com/ensdomains/verifiable-factory/blob/main/src/VerifiableFactory.sol',
},
{
name: 'UserRegistryImpl',
ensjsKey: 'ensUserRegistryImpl',
abiFilename: 'UserRegistryImpl',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/registry/UserRegistry.sol`,
},
{
name: 'PermissionedResolverImpl',
ensjsKey: 'ensPermissionedResolverImpl',
abiFilename: 'PermissionedResolverImpl',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/resolver/PermissionedResolver.sol`,
},
{
name: 'HCAFactory',
ensjsKey: 'ensHcaFactory',
abiFilename: 'HCAFactory',
},
{
name: 'LockedMigrationController',
ensjsKey: 'ensLockedMigrationController',
abiFilename: 'LockedMigrationController',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/migration/LockedMigrationController.sol`,
},
{
name: 'UnlockedMigrationController',
ensjsKey: 'ensUnlockedMigrationController',
abiFilename: 'UnlockedMigrationController',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/migration/UnlockedMigrationController.sol`,
},
{
name: 'MigrationHelper',
ensjsKey: 'ensMigrationHelper',
abiFilename: 'MigrationHelper',
sourceUrl: `${CONTRACTS_V2_BLOB}/src/migration/MigrationHelper.sol`,
},
{
name: 'USDC (payment token)',
ensjsKey: 'usdc',
abiFilename: 'MockUSDC',
},
{
name: 'DAI (payment token)',
ensjsKey: 'dai',
abiFilename: 'MockDAI',
},
]

const CHAINS = [{ name: 'Sepolia', slug: 'sepolia', ensjsChainKey: 'sepolia' }]

// Extract `key: { address: '0x...' }` pairs from one chain block of the
// `ensL1Contracts` object in ensjs l1.ts. `zeroAddress` means not deployed.
function parseChainBlock(
source: string,
chainKey: string
): Map<string, Hex | undefined> {
const exportStart = source.indexOf('export const ensL1Contracts')
if (exportStart === -1)
throw new Error('ensv2-deployments: ensL1Contracts not found in l1.ts')
const exportEnd = source.indexOf('export ', exportStart + 1)
const block = source.slice(
exportStart,
exportEnd === -1 ? undefined : exportEnd
)

const chainStart = block.indexOf(`[supportedL1Chains.${chainKey}]`)
if (chainStart === -1)
throw new Error(
`ensv2-deployments: chain block ${chainKey} not found in ensL1Contracts`
)
const nextChain = block.indexOf('[supportedL1Chains.', chainStart + 1)
const chainBlock = block.slice(
chainStart,
nextChain === -1 ? undefined : nextChain
)

const addresses = new Map<string, Hex | undefined>()
const entry =
/(\w+):\s*\{\s*address:\s*(?:'(0x[0-9a-fA-F]{40})'|zeroAddress)\s*,?\s*\}/g
for (const match of chainBlock.matchAll(entry)) {
addresses.set(match[1], match[2] as Hex | undefined)
}
if (addresses.size === 0)
throw new Error(
`ensv2-deployments: no addresses parsed for ${chainKey}, format changed?`
)
return addresses
}

// Generate a JSON file with ENSv2 contract deployment info from ensjs.
// Only runs once; delete the generated file to re-fetch.
export async function ensv2Deployments() {
const outFile = path.join(
__dirname,
'..',
'src/data/generated/ensv2-deployments.json'
)

const alreadyExists = await fs
.access(outFile)
.then(() => true)
.catch(() => false)
if (alreadyExists) {
return
}

console.log('Fetching ENSv2 deployments (ensjs)')

const source = await fetch(ENSJS_L1_URL).then((res) => {
if (!res.ok)
throw new Error(`ensv2-deployments: fetch failed (${res.status})`)
return res.text()
})

const result: ENSv2DeploymentsByChain[] = CHAINS.map((chain) => {
const addresses = parseChainBlock(source, chain.ensjsChainKey)
const contracts = ENSV2_CONTRACTS.map((contract) => {
if (!addresses.has(contract.ensjsKey))
throw new Error(
`ensv2-deployments: key ${contract.ensjsKey} missing for ${chain.slug}`
)
const address = addresses.get(contract.ensjsKey)
if (!address) {
console.warn(
`ensv2-deployments: ${contract.ensjsKey} is zeroAddress on ${chain.slug}, skipping`
)
return undefined
}
return { ...contract, address }
}).filter((c): c is ENSv2Deployment => c !== undefined)
return { name: chain.name, slug: chain.slug, contracts }
})

// Guard: the ABI snapshot in contracts-v2 must describe the same deployment
// set as ensjs. If a future ENSJS_COMMIT bump moves to a newer deployment,
// this fails the build until ABI_SNAPSHOT is updated to match.
await Promise.all(
result.flatMap((chain) =>
chain.contracts
.filter((c) => c.abiFilename)
.map(async (contract) => {
const artifact = (await fetch(
`${ABI_RAW}/${contract.abiFilename}.json`
).then((res) => {
if (!res.ok)
throw new Error(
`ensv2-deployments: artifact fetch failed for ${contract.abiFilename} (${res.status})`
)
return res.json()
})) as { address: string }
if (
artifact.address.toLowerCase() !== contract.address!.toLowerCase()
)
throw new Error(
`ensv2-deployments: address mismatch for ${contract.name}: ensjs ${contract.address} vs snapshot ${artifact.address}. Update ABI_SNAPSHOT to the deployment set ensjs tracks.`
)
contract.abiUrl = `${ABI_BLOB}/${contract.abiFilename}.json`
})
)
)

await fs.writeFile(outFile, JSON.stringify(result, null, 2))
}
3 changes: 2 additions & 1 deletion scripts/run-plugins.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { daoProposalsSidebar } from './dao-proposals'
import { deployments } from './deployments'
import { ensips } from './ensips'
import { ensv2Deployments } from './ensv2-deployments'

const plugins = [ensips, deployments, daoProposalsSidebar]
const plugins = [ensips, deployments, ensv2Deployments, daoProposalsSidebar]

for (const plugin of plugins) {
await plugin()
Expand Down
2 changes: 1 addition & 1 deletion src/components/AddressRecords.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const AddressRecords = ({ name, coinTypes }: UseEnsAddressesProps) => {
src={avatar || '/img/fallback-avatar.svg'}
className="h-8 w-8 rounded"
/>
<span className="font-semibold">{name}</span>
<span className="font-semibold font-semi-mono">{name}</span>
</div>

<Table
Expand Down
6 changes: 3 additions & 3 deletions src/components/EnsProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ function Profile({
const { data: avatar } = useEnsAvatar({ name: name || undefined, chainId: 1 })

return (
<div className="border-grey-light flex w-fit min-w-fit items-center justify-center rounded-full border bg-white p-1 pr-6 shadow-sm dark:bg-black">
<div className="border-grey-light flex w-fit min-w-fit items-center justify-center rounded-lg border bg-white p-1 pr-6 dark:bg-black">
<div className="flex items-center gap-2">
<img
src={avatar || '/img/fallback-avatar.svg'}
className="border-grey-light h-10 w-10 rounded-full border"
className="border-grey-light h-10 w-10 rounded-sm border-0.5"
/>
<div className="flex flex-col gap-0.5 leading-none">
<span className="font-semibold">{name || 'No name'}</span>
<span className="font-semibold font-semi-mono">{name || 'No name'}</span>

{!hideAddress && (
<span className={cn('text-grey text-xs')}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/TextRecords.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const TextRecords = ({ name, keys }: UseEnsTextsProps) => {
src={avatar || '/img/fallback-avatar.svg'}
className="h-8 w-8 rounded"
/>
<span className="font-semibold">{name}</span>
<span className="font-semibold font-semi-mono">{name}</span>
</div>

<Table
Expand Down
Loading