
Ens
- 12 installs
- 610 repo stars
- Updated June 26, 2026
- alsk1992/cloddsbot
ENS is a Claude Code skill that sets your primary ENS name (reverse resolution) on Base and other L2 chains via the ENS Reverse Registrar.
About
ENS is a skill that sets your primary ENS name on Base and other L2 chains through the ENS Reverse Registrar. A developer uses /ens set to configure reverse resolution so an address maps back to name.eth, and /ens verify or /ens resolve to check names. It requires owning a registered ENS name, existing forward resolution, a wallet PRIVATE_KEY, and gas on the target chain.
- Sets your primary (reverse) ENS name on Base, Arbitrum, Optimism, and Ethereum
- Creates the bi-directional link so an address resolves back to name.eth
- Verifies and resolves ENS names via the ENS Reverse Registrar contracts
Ens by the numbers
- 12 all-time installs (skills.sh)
- Ranked #306 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
ens capabilities & compatibility
Requires a wallet PRIVATE_KEY and native tokens for gas on the target chain; no service fee stated.
- Capabilities
- ens primary name · reverse resolution · ens resolve
- Pricing
- Bring your own API key
What ens says it does
Set your primary ENS name on Base and other L2 chains via the ENS Reverse Registrar.
**Reverse:** `0x1234...` → `name.eth` (set via this skill)
npx skills add https://github.com/alsk1992/cloddsbot --skill ensAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 12 |
|---|---|
| repo stars | ★ 610 |
| Last updated | June 26, 2026 |
| Repository | alsk1992/cloddsbot ↗ |
What it does
Set your primary (reverse) ENS name on Base and other L2 chains and verify or resolve ENS names on-chain.
Who is it for?
Configuring reverse ENS resolution across L2 chains for a wallet you control.
Skip if: Registering a new ENS name or setting forward resolution.
When should I use this skill?
You want to set or verify a primary ENS name (reverse resolution) on Base, Arbitrum, Optimism, or Ethereum.
What you get
A bi-directional ENS link so an address resolves back to name.eth on the chosen chain.
By the numbers
- 4 supported chains: Base, Arbitrum, Optimism, Ethereum
Files
ENS Primary Name
Set your primary ENS name on Base and other L2 chains via the ENS Reverse Registrar.
What It Does
Creates a bi-directional link:
- Forward:
name.eth→0x1234...(set in ENS resolver) - Reverse:
0x1234...→name.eth(set via this skill)
Supported Chains
| Chain | Reverse Registrar |
|---|---|
| Base | 0x0000000000D8e504002cC26E3Ec46D81971C1664 |
| Arbitrum | 0x0000000000D8e504002cC26E3Ec46D81971C1664 |
| Optimism | 0x0000000000D8e504002cC26E3Ec46D81971C1664 |
| Ethereum | 0x283F227c4Bd38ecE252C4Ae7ECE650B0e913f1f9 |
Commands
Set Primary Name
/ens set <name.eth> Set primary name on Base
/ens set <name.eth> --chain arb Set on Arbitrum
/ens set <name.eth> --chain eth Set on EthereumVerify
/ens verify <address> Check if primary name is set
/ens resolve <name.eth> Resolve ENS name to addressExamples
/ens set myname.eth
/ens set myname.eth --chain arbitrum
/ens verify 0x1234...Prerequisites
1. Own an ENS name (registered) 2. Forward resolution configured (name → your address) 3. Native tokens for gas (ETH on target chain)
Setup
export PRIVATE_KEY="0x..." # Your wallet key/**
* ENS Skill - Primary Name on L2s
*
* Set primary ENS name on Base and other L2 chains via Reverse Registrar.
*
* Commands:
* /ens set <name.eth> Set primary name
* /ens verify <address> Verify primary name
* /ens resolve <name.eth> Resolve name to address
*/
import { createPublicClient, createWalletClient, http, namehash, type Address, encodeFunctionData } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base, mainnet, arbitrum, optimism } from 'viem/chains';
import { normalize } from 'viem/ens';
// Reverse Registrar addresses
const REVERSE_REGISTRAR: Record<string, Address> = {
base: '0x0000000000D8e504002cC26E3Ec46D81971C1664',
arbitrum: '0x0000000000D8e504002cC26E3Ec46D81971C1664',
optimism: '0x0000000000D8e504002cC26E3Ec46D81971C1664',
ethereum: '0xa58E81fe9b61B5c3fE2AFD33CF304c454AbFc7Cb',
};
const CHAINS = {
base,
arbitrum,
optimism,
ethereum: mainnet,
eth: mainnet,
arb: arbitrum,
op: optimism,
};
const RPC_URLS: Record<string, string> = {
base: process.env.BASE_RPC_URL || 'https://mainnet.base.org',
arbitrum: process.env.ARB_RPC_URL || 'https://arb1.arbitrum.io/rpc',
optimism: process.env.OP_RPC_URL || 'https://mainnet.optimism.io',
ethereum: process.env.ETH_RPC_URL || 'https://eth.llamarpc.com',
};
const REVERSE_ABI = [
{
inputs: [{ name: 'name', type: 'string' }],
name: 'setName',
outputs: [{ type: 'bytes32' }],
stateMutability: 'nonpayable',
type: 'function',
},
] as const;
function getChainKey(chain: string): string {
const aliases: Record<string, string> = {
eth: 'ethereum',
arb: 'arbitrum',
op: 'optimism',
};
return aliases[chain.toLowerCase()] || chain.toLowerCase();
}
function getPublicClient(chainKey: string) {
const chain = CHAINS[chainKey as keyof typeof CHAINS] || base;
const rpcUrl = RPC_URLS[chainKey] || RPC_URLS.base;
return createPublicClient({
chain,
transport: http(rpcUrl),
});
}
function getWalletClient(chainKey: string) {
const privateKey = process.env.PRIVATE_KEY;
if (!privateKey) throw new Error('PRIVATE_KEY not set');
const account = privateKeyToAccount(privateKey.startsWith('0x') ? privateKey as `0x${string}` : `0x${privateKey}`);
const chain = CHAINS[chainKey as keyof typeof CHAINS] || base;
const rpcUrl = RPC_URLS[chainKey] || RPC_URLS.base;
return createWalletClient({
account,
chain,
transport: http(rpcUrl),
});
}
async function handleSet(name: string, chainArg: string = 'base'): Promise<string> {
if (!name) {
return `Usage: /ens set <name.eth> [--chain base|eth|arb|op]
Example:
/ens set myname.eth
/ens set myname.eth --chain arbitrum`;
}
const chainKey = getChainKey(chainArg);
const reverseRegistrar = REVERSE_REGISTRAR[chainKey];
if (!reverseRegistrar) {
return `Chain "${chainArg}" not supported. Use: base, ethereum, arbitrum, optimism`;
}
try {
const walletClient = getWalletClient(chainKey);
const publicClient = getPublicClient(chainKey);
// Normalize ENS name
const normalizedName = normalize(name);
// Set primary name
const hash = await walletClient.writeContract({
address: reverseRegistrar,
abi: REVERSE_ABI,
functionName: 'setName',
args: [normalizedName],
});
const receipt = await publicClient.waitForTransactionReceipt({ hash });
const chainDisplay = chainKey.charAt(0).toUpperCase() + chainKey.slice(1);
return `**Primary Name Set!**
Name: ${normalizedName}
Chain: ${chainDisplay}
Address: \`${walletClient.account.address}\`
TX: \`${hash}\`
Status: ${receipt.status === 'success' ? 'Success' : 'Failed'}
Your address now resolves to ${normalizedName} on ${chainDisplay}!`;
} catch (error) {
const msg = error instanceof Error ? error.message : String(error);
if (msg.includes('revert')) {
return `Transaction reverted. Make sure:\n1. You own the ENS name\n2. Forward resolution is set (name → your address)\n3. You have ETH for gas on ${chainArg}`;
}
return `Error: ${msg}`;
}
}
async function handleVerify(address: string, chainArg: string = 'base'): Promise<string> {
if (!address) {
return 'Usage: /ens verify <address> [--chain base|eth|arb|op]';
}
const chainKey = getChainKey(chainArg);
try {
const client = getPublicClient(chainKey);
// Get ENS name for address (reverse resolution)
const ensName = await client.getEnsName({
address: address as Address,
}).catch(() => null);
if (!ensName) {
return `No primary name set for \`${address}\` on ${chainKey}.`;
}
// Verify forward resolution
const resolvedAddress = await client.getEnsAddress({
name: normalize(ensName),
}).catch(() => null);
const chainDisplay = chainKey.charAt(0).toUpperCase() + chainKey.slice(1);
if (resolvedAddress?.toLowerCase() === address.toLowerCase()) {
return `**Primary Name Verified!**
Address: \`${address}\`
Name: ${ensName}
Chain: ${chainDisplay}
Reverse: ${address} → ${ensName}
Forward: ${ensName} → ${resolvedAddress}
Bi-directional resolution confirmed!`;
}
return `**Partial Configuration**
Address: \`${address}\`
Reverse Name: ${ensName}
Forward Resolution: ${resolvedAddress || 'Not set'}
The forward resolution doesn't match. Update it at app.ens.domains`;
} catch (error) {
return `Error: ${error instanceof Error ? error.message : String(error)}`;
}
}
async function handleResolve(name: string): Promise<string> {
if (!name) {
return 'Usage: /ens resolve <name.eth>';
}
try {
// Use Ethereum mainnet for ENS resolution
const client = getPublicClient('ethereum');
const normalizedName = normalize(name);
const address = await client.getEnsAddress({
name: normalizedName,
});
if (!address) {
return `No address found for ${normalizedName}`;
}
return `**ENS Resolution**
Name: ${normalizedName}
Address: \`${address}\``;
} catch (error) {
return `Error: ${error instanceof Error ? error.message : String(error)}`;
}
}
export async function execute(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
const command = parts[0]?.toLowerCase() || 'help';
// Parse --chain flag
const chainIdx = parts.indexOf('--chain');
const chainArg = chainIdx !== -1 ? parts[chainIdx + 1] : 'base';
const filteredParts = parts.filter((_, i) => i !== chainIdx && i !== chainIdx + 1);
switch (command) {
case 'set':
return handleSet(filteredParts[1], chainArg);
case 'verify':
return handleVerify(filteredParts[1], chainArg);
case 'resolve':
return handleResolve(filteredParts[1]);
case 'help':
default:
return getHelp();
}
}
function getHelp(): string {
return `**ENS - Primary Name on L2**
/ens set <name.eth> Set primary name on Base
/ens set <name.eth> --chain arb Set on Arbitrum
/ens verify <address> Check if primary name is set
/ens resolve <name.eth> Resolve name to address
**Supported Chains:**
- base (default)
- ethereum / eth
- arbitrum / arb
- optimism / op
**Prerequisites:**
1. Own an ENS name
2. Forward resolution set (name → address)
3. Native token for gas
**Example:**
/ens set myname.eth
/ens verify 0x1234...`;
}
export const tools = [
{
name: 'ens_set_primary',
description: 'Set primary ENS name on Base or other L2',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'ENS name (e.g., myname.eth)' },
chain: { type: 'string', enum: ['base', 'ethereum', 'arbitrum', 'optimism'], description: 'Target chain' },
},
required: ['name'],
},
execute: async ({ name, chain }: { name: string; chain?: string }) => handleSet(name, chain || 'base'),
},
{
name: 'ens_verify',
description: 'Verify if an address has a primary ENS name set',
parameters: {
type: 'object',
properties: {
address: { type: 'string', description: 'Wallet address' },
chain: { type: 'string', description: 'Chain to check' },
},
required: ['address'],
},
execute: async ({ address, chain }: { address: string; chain?: string }) => handleVerify(address, chain || 'base'),
},
{
name: 'ens_resolve',
description: 'Resolve an ENS name to its address',
parameters: {
type: 'object',
properties: { name: { type: 'string', description: 'ENS name to resolve' } },
required: ['name'],
},
execute: async ({ name }: { name: string }) => handleResolve(name),
},
];
export default {
name: 'ens',
description: 'ENS - Set and verify primary ENS names on Base and other L2 chains',
commands: ['/ens'],
handle: execute,
tools,
};