← 返回 Skills 市场
zeugh-eth

ens-manager

作者 Zeugh · GitHub ↗ · v1.2.0 · MIT-0
cross-platform ⚠ suspicious
251
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install ens-manager
功能描述
Register ENS names, create subdomains, and publish IPFS sites without manual contract calls
使用说明 (SKILL.md)

ENS Manager

Complete ENS name management: register new .eth names, create subdomains, and publish IPFS content to decentralized gateways.

Quick Start

Register New ENS Name

# Check availability and price (dry run)
node scripts/register-ens-name.js mynewname --dry-run

# Register for 1 year
node scripts/register-ens-name.js mynewname \
  --years 1 \
  --keystore /path/to/keystore.enc \
  --password "your-password"

What happens:

  1. Phase 1: Makes commitment on-chain (anti-frontrunning)
  2. Phase 2: Waits 60 seconds (required minimum)
  3. Phase 3: Registers name with payment

Cost: ~$5-20 USD/year (varies by name length and demand)

Check ENS Name Status

node scripts/check-ens-name.js yourname.eth

Shows ownership, wrapped status, resolver, and content hash.

Create Subdomain with IPFS

node scripts/create-subdomain-ipfs.js yourname.eth subdomain QmIPFS123... \
  --keystore /path/to/keystore.enc \
  --password "your-password"

Creates subdomain.yourname.eth and sets its IPFS content hash in one command.


Complete Workflows

1. Register New ENS Name (Full Process)

Scenario: You want to own mynewname.eth

Step 1: Check Availability

node scripts/register-ens-name.js mynewname --dry-run

Output:

🦞 ENS Name Registration
========================
📛 Name: mynewname.eth
⏱️  Duration: 1 year

🔍 Checking availability...
✅ Name is available!

💰 Calculating price...
   Registration cost: 0.008 ETH
   (for 1 year)

✅ Dry run complete.

Step 2: Register

node scripts/register-ens-name.js mynewname \
  --years 1 \
  --keystore ~/.openclaw/workspace/wallet-keystore.enc \
  --password "keystore-password"

What happens (three phases):

Phase 1: Commitment (TX 1)

📝 Phase 1: Making commitment...
   Commitment: 0xabc123...
   Secret: 0xdef456...
   TX: 0x789...
   Waiting for confirmation...

The commitment hash prevents frontrunning (someone stealing your name by seeing your TX and submitting theirs first with higher gas).

Phase 2: Wait 60 Seconds

⏳ Phase 2: Waiting 60 seconds (anti-frontrunning protection)...
   60 seconds remaining...
   59 seconds remaining...
   ...
   ✅ Wait complete!

This mandatory wait ensures your commitment is on-chain before registration.

Phase 3: Registration (TX 2 with payment)

📝 Phase 3: Registering name...
   Sending 0.008 ETH...
   TX: 0xghi789...

🎉 Registration complete!

📛 Your ENS name: mynewname.eth
🔍 View on ENS: https://app.ens.domains/mynewname.eth
🔗 Registry TX: https://etherscan.io/tx/0xghi789...

Next steps:
  1. Set your address: ens.domains → Records → ETH Address
  2. Create subdomains: node create-subdomain-ipfs.js
  3. Set reverse record: ens.domains → My Account → Primary Name

Total time: ~2-3 minutes (60s wait + TX confirmations)
Total cost: Registration price + ~$2-4 gas (at 10 gwei)


2. Publishing a Website to ENS

Scenario: You have a static website and want to publish it at meetup.yourname.eth.limo

Prerequisites

  • You own yourname.eth (registered via Step 1 or app.ens.domains)
  • Website files ready
  • IPFS access (local node or Infura/Pinata)

Steps

1. Add website to IPFS:

ipfs add -r ./website
# Output: added QmABC123... website

2. Create ENS subdomain and set content hash:

node scripts/create-subdomain-ipfs.js yourname.eth meetup QmABC123... \
  --keystore ~/.openclaw/workspace/wallet-keystore.enc \
  --password "keystore-password"

3. Access your site:

Open https://meetup.yourname.eth.limo in any browser!

Cost: ~$0.05 (at 0.1 gwei base fee)


3. Updating IPFS Content

Scenario: You updated your website and have a new IPFS CID

Option A: Use viem directly

const { createWalletClient, http, namehash } = require('viem');
const { mainnet } = require('viem/chains');
const contentHash = require('content-hash');

const node = namehash('subdomain.yourname.eth');
const encodedHash = '0x' + contentHash.encode('ipfs-ns', newCid);

await walletClient.writeContract({
  address: PUBLIC_RESOLVER,
  abi: [{
    name: 'setContenthash',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'node', type: 'bytes32' },
      { name: 'hash', type: 'bytes' }
    ],
    outputs: []
  }],
  functionName: 'setContenthash',
  args: [node, encodedHash]
});

Option B: Use ENS App

  1. Go to https://app.ens.domains/subdomain.yourname.eth
  2. Click "Records"
  3. Edit "Content Hash"
  4. Paste new IPFS CID
  5. Save (sign TX)

4. Checking What's Published

node scripts/check-ens-name.js meetup.yourname.eth

Shows current IPFS CID and eth.limo URL.


Contract Addresses (Ethereum Mainnet)

All operations use these addresses:

// Core ENS contracts
const ENS_REGISTRY = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';

// Registration (.eth names)
const ETH_REGISTRAR_CONTROLLER = '0x253553366Da8546fC250F225fe3d25d0C782303b';

// Wrapped names (modern, with fuses)
const NAME_WRAPPER = '0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401';

// Default resolver (most common)
const PUBLIC_RESOLVER = '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63';

Where they're used:

  • ENS_REGISTRY: Base registry for all names (ownership, resolvers)
  • ETH_REGISTRAR_CONTROLLER: Register/renew .eth names (3-phase process)
  • NAME_WRAPPER: Create subdomains for wrapped names
  • PUBLIC_RESOLVER: Resolve names to addresses/content hashes

Three-Phase Registration Process

Why Three Phases?

Problem: If you submit a registration transaction, miners or bots can see it in the mempool and frontrun you (submit their own TX with higher gas to steal the name).

Solution: Commitment scheme prevents this:

  1. Commit: Submit a hash of (name + secret). No one knows what name you want.
  2. Wait: 60 seconds minimum. Your commitment is now on-chain and timestamped.
  3. Register: Reveal the name + secret. Since your commitment was earlier, you win.

Phase 1: Commitment

What happens:

const commitment = keccak256(
  encodePacked(
    ['string', 'address', 'uint256', 'bytes32', 'address', 'bytes[]', 'bool', 'uint16'],
    [
      name,              // 'mynewname' (without .eth)
      owner,             // Your wallet address
      duration,          // 31536000 (1 year in seconds)
      secret,            // Random bytes32 (generated)
      resolver,          // PUBLIC_RESOLVER
      [],                // data (empty for basic registration)
      true,              // reverseRecord (set primary name)
      0                  // ownerControlledFuses (0 = none)
    ]
  )
);

// Submit to ETHRegistrarController
await controller.commit(commitment);

Gas cost: 45,000 gas ($1-2 at 10 gwei)

Phase 2: Wait

Mandatory 60-second wait ensures:

  • Your commitment is confirmed on-chain
  • Timestamp is set
  • You can't be frontrun

Technical reason: The contract checks that block.timestamp >= commitmentTimestamp + 60 seconds when you register.

Phase 3: Registration

What happens:

await controller.register(
  name,              // 'mynewname'
  owner,             // Your address
  duration,          // 31536000 (1 year)
  secret,            // Same secret from commitment
  resolver,          // PUBLIC_RESOLVER
  [],                // data
  true,              // reverseRecord
  0,                 // fuses
  { value: price }   // Payment in ETH
);

Gas cost: 150,000 gas ($3-5 at 10 gwei) + registration price

Total registration: $4-7 gas + registration price ($5-20/year)


Wrapped vs Unwrapped Names

Check if wrapped:

node scripts/check-ens-name.js yourname.eth

Look for "🎁 Wrapped (NameWrapper)" or "📦 Unwrapped (Registry)".

Key differences:

Feature Wrapped Unwrapped
Subdomain creation NameWrapper.setSubnodeRecord Registry.setSubnodeOwner + Registry.setResolver
Label parameter String ("meetup") Bytes32 hash (keccak256)
Owner location NameWrapper ERC-1155 Registry mapping
Advanced features Fuses, expiry None

The create-subdomain-ipfs.js script handles both automatically.


Current vs Typical Gas Costs

Gas costs vary based on network congestion. The skill shows real-time costs during dry-run.

Registration (2 TXs)

Current conditions (0.22 gwei - very low):

  • Commitment: 45,000 gas = $0.02
  • Registration: 265,000 gas = $0.15
  • Total gas: $0.17

Typical conditions (10 gwei - normal):

  • Commitment: 45,000 gas = $1.13
  • Registration: 265,000 gas = $6.63
  • Total gas: $7.75

ENS Name Pricing Tiers (Annual Rental)

Name Length Cost/Year Example
3 characters ~$773 abc.eth
4 characters ~$193 cool.eth
5+ characters ~$6 hello.eth, example.eth

Complete Registration Examples

5-letter name (most common):

  • Current: Name ($6) + Gas ($0.17) = $6.17 total
  • Typical: Name ($6) + Gas ($7.75) = $13.75 total

4-letter name:

  • Current: Name ($193) + Gas ($0.17) = $193.17 total
  • Typical: Name ($193) + Gas ($7.75) = $200.75 total

Recommendation: Use --dry-run to check current costs before registering.

See COSTS.md for detailed cost breakdowns and optimization tips.


Troubleshooting

Registration: "Name not available"

The name is already registered. Try:

node scripts/check-ens-name.js \x3Cname>.eth

To see who owns it and when it expires.

Registration: "insufficient funds"

You need ETH for:

  1. Registration price (~$5-20 for most names)
  2. Gas fees (~$4-7)

Check balance:

# In script or cast
const balance = await publicClient.getBalance({ address });
console.log('Balance:', formatEther(balance), 'ETH');

Registration: "Commitment not found" or "Too soon"

If you see this during Phase 3:

  • Too soon: Wait the full 60 seconds
  • Commitment not found: Your Phase 1 TX didn't confirm yet. Wait longer or check TX status.

Transaction reverts

Common causes:

  1. Not the owner - You must own the parent name to create subdomains
  2. Name is wrapped - Use NameWrapper methods, not Registry
  3. Gas limit too low - Increase gas parameter
  4. Commitment too old - If you wait >24 hours between Phase 1 and 3, start over

Content not appearing on eth.limo

  1. Wait a few minutes (DNS propagation)
  2. Check content hash is set: node scripts/check-ens-name.js yourname.eth
  3. Verify IPFS CID is accessible: https://ipfs.io/ipfs/YOUR_CID
  4. Check resolver is PUBLIC_RESOLVER (most gateways only read from it)

Manual Operations (Advanced)

Unwrapped Name: Create Subdomain

const { keccak256, encodePacked } = require('viem');

// 1. Create subdomain
const parentNode = namehash('yourname.eth');
const labelHash = keccak256(encodePacked(['string'], ['subdomain']));

await walletClient.writeContract({
  address: ENS_REGISTRY,
  abi: [{
    name: 'setSubnodeOwner',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'node', type: 'bytes32' },
      { name: 'label', type: 'bytes32' },
      { name: 'owner', type: 'address' }
    ],
    outputs: [{ name: '', type: 'bytes32' }]
  }],
  functionName: 'setSubnodeOwner',
  args: [parentNode, labelHash, ownerAddress]
});

// 2. Set resolver
const subnode = namehash('subdomain.yourname.eth');

await walletClient.writeContract({
  address: ENS_REGISTRY,
  abi: [{
    name: 'setResolver',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'node', type: 'bytes32' },
      { name: 'resolver', type: 'address' }
    ],
    outputs: []
  }],
  functionName: 'setResolver',
  args: [subnode, PUBLIC_RESOLVER]
});

Wrapped Name: Create Subdomain

await walletClient.writeContract({
  address: NAME_WRAPPER,
  abi: [{
    name: 'setSubnodeRecord',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'parentNode', type: 'bytes32' },
      { name: 'label', type: 'string' },
      { name: 'owner', type: 'address' },
      { name: 'resolver', type: 'address' },
      { name: 'ttl', type: 'uint64' },
      { name: 'fuses', type: 'uint32' },
      { name: 'expiry', type: 'uint64' }
    ],
    outputs: [{ name: '', type: 'bytes32' }]
  }],
  functionName: 'setSubnodeRecord',
  args: [
    namehash('yourname.eth'),  // parent node
    'subdomain',                // label (string!)
    ownerAddress,               // owner
    PUBLIC_RESOLVER,            // resolver
    0n,                         // ttl (0 = default)
    0,                          // fuses (0 = none)
    0n                          // expiry (0 = inherit from parent)
  ]
});

IPFS Content Hash

Encoding CID

const contentHash = require('content-hash');
const ipfsCid = 'QmABC123...';
const encoded = '0x' + contentHash.encode('ipfs-ns', ipfsCid);

Setting Content Hash

await walletClient.writeContract({
  address: PUBLIC_RESOLVER,
  abi: [{
    name: 'setContenthash',
    type: 'function',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'node', type: 'bytes32' },
      { name: 'hash', type: 'bytes' }
    ],
    outputs: []
  }],
  functionName: 'setContenthash',
  args: [namehash('subdomain.yourname.eth'), encodedHash]
});

Reading Content Hash

const contenthash = await publicClient.readContract({
  address: resolverAddress,
  abi: [{
    name: 'contenthash',
    type: 'function',
    stateMutability: 'view',
    inputs: [{ name: 'node', type: 'bytes32' }],
    outputs: [{ name: '', type: 'bytes' }]
  }],
  functionName: 'contenthash',
  args: [namehash('subdomain.yourname.eth')]
});

if (contenthash && contenthash !== '0x') {
  const decoded = contentHash.decode(contenthash);
  console.log('IPFS CID:', decoded);
}

Gateway Access

After setting a content hash, the subdomain becomes accessible via:

  • eth.limo: https://subdomain.yourname.eth.limo
  • eth.link: https://subdomain.yourname.eth.link
  • IPFS directly: https://ipfs.io/ipfs/QmABC123...
  • dweb.link: https://QmABC123....ipfs.dweb.link/

Note: eth.limo/eth.link may take a few minutes to update after setting a new content hash.


Resources

For detailed ENS concepts, wrapped vs unwrapped differences, and content hash encoding, read references/ens-basics.md.

安全使用建议
This skill generally does what it claims (register ENS names and set IPFS content) and includes the scripts to do it, but there are a few red flags you should address before using it with real funds: - Review the scripts first. They handle your private key / keystore locally; verify the decrypt/write flows and ensure no code sends raw private keys to external servers. The repo is bundled so you can audit it locally. - Protect wallet material. Prefer using a secure signing provider or an offline key rather than passing --password on the command line (shell history) or storing an unencrypted private key. If you must use a keystore+password, pass the password via a file descriptor or secure agent, not a plain CLI argument. - Test on a testnet or with a throwaway wallet before using production ETH. Use dry-run modes first where available. - Use a trusted RPC provider (or your own node) rather than the skill's default public endpoints — public RPCs can log requests (including the addresses involved) and may impose rate limits. - Note the docs/code mismatches: SKILL.md and changelog mention --private-key-env and specific default RPCs, but the scripts are inconsistent. Confirm the exact command-line options in the JS files before running. - Manually remove or inspect any hidden/unicode control characters in SKILL.md and other docs to ensure the content hasn't been obfuscated. If you want, I can: (1) point out the exact lines of code that read/decrypt the keystore and how they handle the private key, (2) search the scripts for any network calls beyond the RPC endpoints, or (3) produce a safe checklist of commands to run this skill with minimal exposure (dry-run, test wallet, local RPC).
功能分析
Type: OpenClaw Skill Name: ens-manager Version: 1.2.0 The ens-manager skill bundle is a comprehensive and well-documented utility for managing Ethereum Name Service (ENS) operations, including name registration, subdomain creation, and IPFS content linking. The scripts (e.g., register-ens-name.js and create-subdomain-ipfs.js) handle sensitive data such as private keys and keystore passwords, but they do so locally to sign transactions using the standard viem library, with no evidence of data exfiltration or malicious intent. The documentation is exceptionally thorough, providing clear cost breakdowns, technical explanations of the ENS commitment scheme, and security warnings regarding private key handling.
能力评估
Purpose & Capability
Name/description match the provided scripts: registration, subdomain creation, and IPFS content setting. The JS scripts operate on ENS contracts and use viem/content-hash as expected. No unrelated cloud provider credentials or unrelated binaries are requested.
Instruction Scope
The SKILL.md and other docs instruct the agent and user to provide keystore files, passwords, and optionally environment-based private keys; the bundled scripts require sensitive wallet material and will send transactions. The docs suggest a --private-key-env option and a default RPC (mainnet.rpc.buidlguidl.com / ethereum-rpc.publicnode.com), but the actual scripts do not consistently implement all documented authentication options (inconsistency between docs and code). SKILL.md also contains unicode-control-chars (prompt-injection signal) that could indicate tampering of documentation text. The scripts read local keystore files and accept plaintext passwords on the command line (shell-history risk) which the docs acknowledge; they also send requests to public RPC endpoints (which can log requests).
Install Mechanism
No install spec downloads arbitrary code; this is an instruction+script bundle included in the skill. Dependencies are standard npm packages (viem, content-hash). There are no external archive downloads or obscure installers in the skill metadata.
Credentials
The skill requires wallet credentials (keystore or private key) which is proportional to its ability to send ENS transactions. However, documentation mentions environment-based private-key options that are not implemented in the provided scripts, and different files default to different RPC URLs. The only environment variable actually used in code is RPC_URL (optional). No unrelated secrets are requested, but the skill legitimately needs private key material — that is high-sensitivity and should only be provided after code review.
Persistence & Privilege
Skill is not always-enabled (always:false) and does not request elevated platform privileges. It does not modify other skills or system-wide settings. Autonomous invocation is allowed (platform default) but does not by itself increase concern given other findings.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install ens-manager
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /ens-manager 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.2.0
ens-manager 1.2.0 introduces streamlined ENS name management and new IPFS publishing features. - Register new `.eth` names, create subdomains, and publish IPFS content from the command line, with clear three-phase registration process. - Supports ENS ownership checks, content hash management, and subdomain creation in a single step. - Comprehensive quick start and example workflows included. - Requires Node.js 18+, viem ^1.20.0, and (optionally) content-hash for IPFS support. - Transparent about required contract addresses and gas costs for most actions.
元数据
Slug ens-manager
版本 1.2.0
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 1
常见问题

ens-manager 是什么?

Register ENS names, create subdomains, and publish IPFS sites without manual contract calls. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 251 次。

如何安装 ens-manager?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install ens-manager」即可一键安装,无需额外配置。

ens-manager 是免费的吗?

是的,ens-manager 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

ens-manager 支持哪些平台?

ens-manager 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 ens-manager?

由 Zeugh(@zeugh-eth)开发并维护,当前版本 v1.2.0。

💬 留言讨论