Development of ENS-Based Profile System
ENS stores not just addresses — resolver supports arbitrary text records, IPFS contenthash, multi-chain addresses. This is ready infrastructure for decentralized identity: user manages their profile through ENS, applications read data without centralized storage.
ENS Profile Structure
Standard fields according to EIP-634:
interface ENSProfile {
// Core identity
name: string; // display name
description: string; // bio
avatar: string; // URL or IPFS hash of image
// Contact
email: string;
url: string; // website
// Social
"com.twitter": string;
"com.github": string;
"com.discord": string;
"org.telegram": string;
"com.reddit": string;
// Professional
keywords: string; // comma-separated tags
notice: string; // public announcement
}
Reading Profile
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
import { normalize } from "viem/ens";
const client = createPublicClient({ chain: mainnet, transport: http(RPC_URL) });
async function getENSProfile(nameOrAddress: string) {
let ensName: string | null = null;
// Determine: is it a name or address?
if (nameOrAddress.endsWith(".eth")) {
ensName = normalize(nameOrAddress);
} else {
ensName = await client.getEnsName({ address: nameOrAddress as `0x${string}` });
}
if (!ensName) return null;
const [avatar, textRecords] = await Promise.all([
client.getEnsAvatar({ name: ensName }),
Promise.all([
client.getEnsText({ name: ensName, key: "description" }),
client.getEnsText({ name: ensName, key: "com.twitter" }),
client.getEnsText({ name: ensName, key: "com.github" }),
client.getEnsText({ name: ensName, key: "url" }),
]),
]);
return {
name: ensName,
avatar,
description: textRecords[0],
twitter: textRecords[1],
github: textRecords[2],
website: textRecords[3],
};
}
Avatar Resolution
ENS supports several avatar formats:
- HTTP/HTTPS URL:
https://example.com/avatar.png - IPFS:
ipfs://QmHash... - NFT reference:
eip155:1/erc721:0xContractAddr/tokenId— automatically reads tokenURI
// viem getEnsAvatar automatically handles all formats
// and returns the final image URL
const avatarUrl = await client.getEnsAvatar({ name: "vitalik.eth" });
For NFT avatars: library requests tokenURI → parses metadata → returns image URL. Important: NFT must be owned by the ENS name owner — otherwise avatar is not displayed.
Writing Profile
import { createWalletClient, custom } from "viem";
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum),
});
// ENS Public Resolver address (mainnet)
const RESOLVER = "0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63";
const ENS_ABI = [...] // ABI resolver
const { request } = await client.simulateContract({
address: RESOLVER,
abi: ENS_ABI,
functionName: "setText",
args: [namehash("alice.eth"), "description", "DeFi developer"],
account: walletClient.account,
});
await walletClient.writeContract(request);
Caching and Performance
ENS data changes rarely. Aggressive caching is justified:
| Field | Cache TTL |
|---|---|
| Address (forward resolution) | 10 minutes |
| Reverse resolution | 10 minutes |
| Avatar | 1 hour |
| Text records | 30 minutes |
For high-load applications — Redis cache before RPC calls. Cache size is minimal (few KB per profile), can store thousands of profiles.
Linked Accounts Verification
Twitter/GitHub verification in ENS — user specifies handle, but anyone can write any handle. For verification, an additional step is needed:
Verification via Keybase / Lens Protocol: user publishes cryptographic proof (wallet signature) in Twitter/GitHub. Verifiers (Keybase, Lens) check ownership.
EAS attestation: trusted verifier issues attestation "address X owns Twitter @Y" via EAS. Profile reads attestation, not just text record.
Development of ENS-profile system with data reading, caching, avatar resolution, and linked account verification — 1-3 weeks depending on feature depth.







