ENS (Ethereum Name Service)
Resolve ENS names (.eth) to Ethereum addresses and vice versa. Use when a user provides an .eth name (e.g. "send to vitalik.eth"), when displaying addresses (show ENS names), looking up ENS profiles,
Description
name: ens description: Resolve ENS names (.eth) to Ethereum addresses and vice versa. Use when a user provides an .eth name (e.g. "send to vitalik.eth"), when displaying addresses (show ENS names), looking up ENS profiles, or helping users register, renew, or manage .eth names. homepage: https://docs.ens.domains/ metadata: openclaw: emoji: "🏷️" requires: { env: [] }
ENS (Ethereum Name Service) — Skill
What this skill does
Enables Gundwane to:
- Resolve ENS names to Ethereum addresses (forward resolution)
- Resolve addresses to ENS names (reverse resolution)
- Look up ENS profiles (avatar, social records, text records)
- Help users register, renew, and manage .eth names on Ethereum mainnet
When to use
- User mentions any
.ethname: "send to vitalik.eth", "look up nick.eth", "who is luc.eth" - Displaying wallet addresses to the user — show the ENS primary name alongside the address
- User asks "what's my ENS?", "do I have an ENS name?", "set my ENS"
- User asks to register a new .eth name, renew an existing one, or update records
- User sends to or receives from an
.ethaddress
ENS Name Detection
Any token matching *.eth in user input is likely an ENS name. Examples:
- "send 0.1 ETH to vitalik.eth" → resolve
vitalik.eth - "what's the address for nick.eth?" → resolve
nick.eth - "register myname.eth" → check availability for
myname
Always resolve before using. Never pass a .eth name directly to LI.FI or transaction tools — resolve to a 0x address first.
Resolution
Forward Resolution (Name → Address)
Use curl to resolve an ENS name to its Ethereum address. Try in priority order.
Approach 1: ENS Subgraph (The Graph)
Best for detailed data (expiry, registrant, resolver). Requires GRAPH_API_KEY env var.
curl -s -X POST \
--url "https://gateway.thegraph.com/api/$GRAPH_API_KEY/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH" \
--header 'Content-Type: application/json' \
--data '{"query":"{ domains(where: { name: \"vitalik.eth\" }) { name resolvedAddress { id } expiryDate registration { registrant { id } expiryDate } } }"}'
Response: data.domains[0].resolvedAddress.id = the 0x address.
Approach 2: web3.bio API (free, no key needed)
Good for quick resolution + profile data in one call.
curl -s "https://api.web3.bio/profile/vitalik.eth"
Returns JSON with address, identity, displayName, avatar, description, and linked social profiles. Use the address field for the resolved 0x address.
Approach 3: Node.js with viem (fallback)
If APIs are down and node is available (viem is in the project deps):
node --input-type=module -e "
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
import { normalize } from 'viem/ens';
const c = createPublicClient({ chain: mainnet, transport: http('https://eth.llamarpc.com') });
const addr = await c.getEnsAddress({ name: normalize('REPLACE_NAME') });
console.log(JSON.stringify({ address: addr }));
"
Replace REPLACE_NAME with the actual ENS name.
Priority: Approach 1 → 2 → 3. Use whichever is available and fastest.
Reverse Resolution (Address → Name)
Given a 0x address, find the primary ENS name.
Via ENS Subgraph
curl -s -X POST \
--url "https://gateway.thegraph.com/api/$GRAPH_API_KEY/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH" \
--header 'Content-Type: application/json' \
--data '{"query":"{ domains(where: { resolvedAddress: \"0xd8da6bf26964af9d7eed9e03e53415d37aa96045\" }) { name } }"}'
Note: address must be lowercase in the query.
Via web3.bio
curl -s "https://api.web3.bio/profile/0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
Returns ENS name and profile if a primary name is set.
Via viem (fallback)
node --input-type=module -e "
import { createPublicClient, http } from 'viem';
import { mainnet } from 'viem/chains';
const c = createPublicClient({ chain: mainnet, transport: http('https://eth.llamarpc.com') });
const name = await c.getEnsName({ address: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045' });
console.log(JSON.stringify({ name }));
"
Profile Lookup
Get ENS profile details: avatar, description, social links, text records.
curl -s "https://api.web3.bio/profile/nick.eth"
Common text record keys (for reference):
com.twitter— Twitter/X handlecom.github— GitHub usernameurl— Websiteemail— Email addressavatar— Avatar URL or NFT referencedescription— Bio/descriptioncom.discord— Discord handle
ENS Avatar URL
Direct avatar image:
https://metadata.ens.domains/mainnet/avatar/{name}
Example: https://metadata.ens.domains/mainnet/avatar/nick.eth
Use this URL when displaying a user's ENS avatar in messages.
Display Rules
When showing addresses
- After getting a user's wallet via
defi_get_wallet, optionally check for a reverse ENS name. - If user has a primary ENS name, display it:
fabri.eth (0xabc...def) - In portfolio views, prefer the ENS name when available.
- Don't resolve on every message — cache the result for the session.
When resolving for transactions
- Always confirm the resolved address before executing:
vitalik.eth → 0xd8dA...6045 Send 0.1 ETH to this address? - Never blindly trust resolution — ENS records can change. Always show the
0xaddress.
In transaction summaries
- Use both:
0.1 ETH → vitalik.eth (0xd8d...6045) on Base
Registration
.eth Name Registration
Registration happens on Ethereum mainnet only. Requires ETH for the name price + gas. If the user's ETH is on L2, flag that they need to bridge first.
Pricing:
- 5+ characters: $5/year in ETH
- 4 characters: $160/year in ETH
- 3 characters: $640/year in ETH
Contracts (Mainnet):
| Contract | Address |
|---|---|
| ENS Registry | 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e |
| ETH Registrar Controller | 0x253553366Da8546fC250F225fe3d25d0C782303b |
| Public Resolver | 0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63 |
| Reverse Registrar | 0xa58E81fe9b61B5c3fE2AFD33CF304c454AbFc7Cb |
| Name Wrapper | 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401 |
| Universal Resolver | 0xce01f8eee7E479C928F8919abD53E553a36CeF67 |
Check Availability
Via the ENS subgraph:
curl -s -X POST \
--url "https://gateway.thegraph.com/api/$GRAPH_API_KEY/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH" \
--header 'Content-Type: application/json' \
--data '{"query":"{ registrations(where: { labelName: \"myname\" }) { labelName expiryDate } }"}'
If no result or expiryDate is in the past (+ 90 day grace period), the name is available.
Or link the user to check directly: https://ens.app/myname.eth
Registration Flow
Registration uses a 2-step commit/reveal process (prevents front-running):
- Check availability (subgraph query above).
- Check price: ~$5/year for 5+ char names. Current ETH price determines the exact cost.
- Present summary:
Register myname.eth: • Cost: ~0.002 ETH ($5) for 1 year • Chain: Ethereum mainnet • 2-step process (~2 min total) Register? - Step 1 — Commit: Call
commit(bytes32)on the ETH Registrar Controller viadefi_send_transaction(chainId: 1). The commitment hash must be computed from the name, owner address, duration, and a random secret. - Wait 60 seconds (tell the user: "Commitment submitted. Registration completes in ~1 minute.").
- Step 2 — Register: Call
register(name, owner, duration, secret, resolver, data, reverseRecord, fuses)with the name price asvalue. - Confirm:
myname.eth registered! Yours for 1 year (expires Feb 2027). [View tx](...) - Store in strategy and suggest setting a primary name.
Simpler alternative: Direct the user to the ENS Manager App for registration: https://ens.app/myname.eth — this handles the full flow with a nice UI. Recommend this for first-time registrations.
Renewal
Simpler than registration — single transaction, no commit step.
When user says "renew myname.eth":
- Look up current expiry via subgraph or strategy.
- Get renewal price (same as registration pricing).
- Present summary:
Renew myname.eth: • Current expiry: Feb 8, 2027 • Cost: ~0.002 ETH ($5) for 1 year • New expiry: Feb 8, 2028 - On approval: Call
renew(string name, uint256 duration)on the ETH Registrar Controller viadefi_send_transaction(chainId: 1) with the renewal price asvalue. Duration in seconds (1 year = 31536000). - Update expiry in strategy.
Grace period: Names have a 90-day grace period after expiry. Only the original owner can renew during this window. After grace period, name goes to public auction with a temporary premium that decreases over 21 days.
Setting Records
Set Primary Name (Reverse Record)
When user says "set my ENS primary name" or "make myname.eth my primary":
- Call
setName(string name)on the Reverse Registrar (0xa58E81fe9b61B5c3fE2AFD33CF304c454AbFc7Cb) viadefi_send_transactionon mainnet (chainId: 1). - This makes the user's address resolve to
myname.ethin reverse lookups. - The user must own the name and it must point to their address.
Set Text Records
Update social/text records via the Public Resolver (0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63):
- Function:
setText(bytes32 node, string key, string value) - The
nodeis the namehash of the full name. - Common keys:
com.twitter,com.github,url,email,avatar,description
For complex record updates, recommend the ENS Manager App: https://ens.app/myname.eth
Expiry Monitoring
Store registered ENS names in the user's strategy for heartbeat monitoring:
{
"ensNames": [
{
"name": "fabri.eth",
"expiry": "2027-02-08T00:00:00Z",
"isPrimary": true
}
]
}
During heartbeats, check ensNames from each user's strategy:
- 30 days before expiry: "Your name fabri.eth expires in 30 days. Want to renew?"
- 7 days before expiry: "fabri.eth expires in 7 days. Renew now to keep it."
- Expired (in grace period): "fabri.eth expired! You have 90 days to renew before it's released."
Data Storage — Strategy JSON
ENS data is stored per-user in strategy JSON (via defi_set_strategy):
{
"ensNames": [
{
"name": "fabri.eth",
"expiry": "2027-02-08T00:00:00Z",
"isPrimary": true
}
],
"ensPreferences": {
"showEnsInPortfolio": true,
"expiryAlertDays": 30
}
}
Read via defi_get_strategy, write via defi_set_strategy. Automatically per-user.
Narrative data (e.g., "resolved vitalik.eth for a 0.1 ETH transfer") goes to per-user daily memory.
Rules
- Always resolve before transacting. Never pass
.ethnames to LI.FI or transaction tools. Resolve to a0xaddress first. - Confirm resolved address. Always show the user the resolved
0xaddress before sending funds. ENS records can change. - Mainnet only for registration/renewal. .eth names live on Ethereum mainnet. Flag if user needs to bridge ETH for gas + fees.
- No permission for lookups. ENS resolution and profile lookups are read operations — do them silently.
- Cache within session. If you resolve a name in a conversation, reuse the result. Don't re-resolve every message.
- Handle failures gracefully. If resolution fails (name doesn't exist, API down), tell the user clearly. Never guess an address.
- Monitor expiry during heartbeats. Check
ensNamesin user strategies. Alert before names expire. - Per-user isolation. ENS data lives in the user's strategy JSON. Never cross-read.
- Suggest ENS once. If user doesn't have an ENS name and frequently uses their raw address, mention ENS once. Don't push it.
- ENSv2 awareness. ENS is migrating to a new L2-based system (ENSv2). Current mainnet registration still works. Be aware this may change.
Reviews (0)
No reviews yet. Be the first to review!
Comments (0)
No comments yet. Be the first to share your thoughts!