一、为什么要做ENS域名解析优化用户地址展示体验

我们用区块链钱包的时候,比如小狐狸钱包(MetaMask),会经常看到一串乱码一样的地址,比如0x1234abcd...这种,普通人根本记不住,甚至连区分两个地址都费劲。比如你要给朋友转钱,输错一个字符钱就没了,风险特别大。

ENS域名就解决了这个问题,它相当于区块链世界的“手机号”,可以把那串乱码地址绑定成好记的名字,比如张三.eth、我的钱包.eth这种。而Web3.js是专门用来和区块链交互的前端工具包,用它就能实现ENS的正向解析(把名字转成地址)和反向解析(把地址转成名字),让用户在DApp(去中心化应用)里看到的不再是乱码,而是好记的名字,体验好太多。

二、准备工作:先搭好基础环境

要做这个功能,得先把需要的东西准备好,步骤很简单,跟着走就行。

2.1 安装需要的工具包

首先得有一个前端项目,不管是用Vue还是React还是纯HTML都可以,这里我们统一用纯HTML+JavaScript的组合,不用框架,所有人都能看懂。然后要装Web3.js,直接用CDN引入就行,不用打包,省得麻烦。

CDN引入的代码很简单,放在HTML的head标签里就行:

<script src="https://cdn.jsdelivr.net/npm/web3@1.10.0/dist/web3.min.js"></script>

这里选1.10.0版本是因为这个版本稳定,和ENS的兼容性好,新的版本可能有一些API变动,新手容易踩坑。

2.2 连接区块链节点

Web3.js要和区块链交互,得连一个节点,相当于和区块链“通话”的电话线。我们可以用公共节点,比如Infura的,不用自己搭,很方便。首先得去Infura官网注册一个账号,免费的额度足够测试用,然后拿到一个节点地址,比如以太坊主网的节点地址是https://mainnet.infura.io/v3/你的项目ID。

然后用Web3.js连接这个节点,代码大概是这样:

// 初始化Web3,连接以太坊主网节点
const web3 = new Web3('https://mainnet.infura.io/v3/你的项目ID');
// 测试连接是否成功,比如获取当前区块号
web3.eth.getBlockNumber((err, blockNumber) => {
  if (err) {
    console.error('连接节点失败:', err);
  } else {
    console.log('连接成功,当前区块号:', blockNumber);
  }
});

这里要注意,如果你想测试测试网,比如Ropsten,就把节点地址换成Ropsten的就行,测试网的ETH是免费的,适合练手。

三、正向解析:把ENS名字转成地址

正向解析就是输入一个好记的ENS名字,比如alice.eth,转成对应的区块链地址,方便转账或者调用合约。

3.1 核心原理:调用ENS合约的解析方法

ENS本身是部署在以太坊上的智能合约,Web3.js可以直接调用这个合约的方法来解析。我们不用自己写合约,只要知道合约的地址和方法就行。

3.2 完整代码示例

我们做一个简单的功能,用户输入一个ENS名字,点击按钮,显示对应的地址。代码如下:

<!-- 前端页面部分 -->
<div id="app">
  <input type="text" id="ensName" placeholder="输入ENS名字,比如alice.eth">
  <button id="resolveBtn">解析为地址</button>
  <p id="result">解析结果:</p>
</div>

<script>
// 1. 初始化Web3,连接以太坊主网节点(替换成你自己的Infura项目ID)
const web3 = new Web3('https://mainnet.infura.io/v3/你的项目ID');

// 2. ENS合约的核心配置:主网的ENS注册表合约地址
const ENS_REGISTRY_ADDRESS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';

// 3. 定义调用ENS合约的方法:根据ENS名字获取解析器合约地址
async function getResolverAddress(ensName) {
  // 把ENS名字转成哈希,这是ENS合约要求的格式
  const nameHash = web3.utils.namehash(ensName);
  // 构造合约调用的ABI(应用二进制接口,告诉Web3.js怎么调用合约方法)
  const registryAbi = [
    {
      "constant": true,
      "inputs": [{"name":"node","type":"bytes32"}],
      "name":"resolver",
      "outputs": [{"name":"","type":"address"}],
      "payable": false,
      "type":"function"
    }
  ];
  // 实例化ENS注册表合约
  const registryContract = new web3.eth.Contract(registryAbi, ENS_REGISTRY_ADDRESS);
  // 调用合约的resolver方法,获取解析器地址
  return await registryContract.methods.resolver(nameHash).call();
}

// 4. 定义调用解析器合约的方法:根据ENS名字获取对应的地址
async function getAddressFromResolver(ensName, resolverAddress) {
  const nameHash = web3.utils.namehash(ensName);
  // 解析器合约的ABI,核心是addr方法,用来获取地址
  const resolverAbi = [
    {
      "constant": true,
      "inputs": [{"name":"node","type":"bytes32"}],
      "name":"addr",
      "outputs": [{"name":"","type":"address"}],
      "payable": false,
      "type":"function"
    }
  ];
  // 实例化解析器合约
  const resolverContract = new web3.eth.Contract(resolverAbi, resolverAddress);
  // 调用addr方法,获取地址
  return await resolverContract.methods.addr(nameHash).call();
}

// 5. 整合:完整的正向解析流程
async function forwardResolve(ensName) {
  try {
    // 第一步:获取解析器地址
    const resolverAddress = await getResolverAddress(ensName);
    // 如果解析器地址是0,说明这个ENS名字不存在
    if (resolverAddress === '0x0000000000000000000000000000000000000000') {
      return '该ENS名字不存在';
    }
    // 第二步:获取对应的地址
    const address = await getAddressFromResolver(ensName, resolverAddress);
    return address;
  } catch (err) {
    console.error('正向解析出错:', err);
    return '解析失败,请检查输入的ENS名字';
  }
}

// 6. 给按钮绑定点击事件
document.getElementById('resolveBtn').addEventListener('click', async () => {
  const ensName = document.getElementById('ensName').value.trim();
  if (!ensName) {
    document.getElementById('result').textContent = '请输入ENS名字';
    return;
  }
  const result = await forwardResolve(ensName);
  document.getElementById('result').textContent = `解析结果:${result}`;
});
</script>

这个代码很完整,你只要把Infura的项目ID换成自己的,就能直接运行。比如输入alice.eth,就能得到对应的地址。

四、反向解析:把地址转成ENS名字

反向解析就是把一串乱码的地址,转成对应的ENS名字,比如用户连接钱包后,DApp里显示“欢迎回来,张三.eth”,而不是“欢迎回来,0x1234abcd...”,体验好太多。

4.1 核心原理:反向解析的特殊规则

和正向解析不一样,反向解析需要先把地址转成一个特殊的ENS名字,比如地址0x1234abcd...转成对应的反向名字是“1234abcd...addr.reverse”,然后再用正向解析的方法解析这个特殊名字,得到对应的ENS名字。

4.2 完整代码示例

我们做一个功能,用户输入一个地址,点击按钮,显示对应的ENS名字。代码如下:

<!-- 前端页面部分 -->
<div id="reverseApp">
  <input type="text" id="addressInput" placeholder="输入以太坊地址,比如0x1234...">
  <button id="reverseResolveBtn">解析为ENS名字</button>
  <p id="reverseResult">解析结果:</p>
</div>

<script>
// 1. 初始化Web3,连接以太坊主网节点(替换成你自己的Infura项目ID)
const web3 = new Web3('https://mainnet.infura.io/v3/你的项目ID');

// 2. ENS合约的核心配置:主网的ENS注册表合约地址
const ENS_REGISTRY_ADDRESS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';

// 3. 定义把地址转成反向ENS名字的方法
function addressToReverseName(address) {
  // 把地址转成小写,去掉前面的0x
  const lowerAddress = address.toLowerCase().slice(2);
  // 拼接成反向名字:地址 + .addr.reverse
  return `${lowerAddress}.addr.reverse`;
}

// 4. 复用正向解析的核心方法:根据ENS名字获取地址(这里用来获取反向名字对应的地址)
async function forwardResolve(ensName) {
  try {
    // 把ENS名字转成哈希
    const nameHash = web3.utils.namehash(ensName);
    // 构造注册表合约ABI
    const registryAbi = [
      {
        "constant": true,
        "inputs": [{"name":"node","type":"bytes32"}],
        "name":"resolver",
        "outputs": [{"name":"","type":"address"}],
        "payable": false,
        "type":"function"
      }
    ];
    const registryContract = new web3.eth.Contract(registryAbi, ENS_REGISTRY_ADDRESS);
    const resolverAddress = await registryContract.methods.resolver(nameHash).call();
    if (resolverAddress === '0x0000000000000000000000000000000000000000') {
      return '0x0000000000000000000000000000000000000000';
    }
    // 构造解析器合约ABI,注意这里的ABI是专门用来获取名字的,和正向解析的addr方法不一样
    const resolverAbi = [
      {
        "constant": true,
        "inputs": [{"name":"node","type":"bytes32"}],
        "name":"name",
        "outputs": [{"name":"","type":"string"}],
        "payable": false,
        "type":"function"
      }
    ];
    const resolverContract = new web3.eth.Contract(resolverAbi, resolverAddress);
    // 调用name方法,获取ENS名字
    return await resolverContract.methods.name(nameHash).call();
  } catch (err) {
    console.error('反向解析核心出错:', err);
    return '解析失败';
  }
}

// 5. 整合:完整的反向解析流程
async function reverseResolve(address) {
  try {
    // 第一步:验证地址格式是否正确
    if (!web3.utils.isAddress(address)) {
      return '地址格式不正确';
    }
    // 第二步:把地址转成反向ENS名字
    const reverseName = addressToReverseName(address);
    // 第三步:解析反向名字,得到对应的ENS名字
    const ensName = await forwardResolve(reverseName);
    // 如果返回的是空字符串,说明这个地址没有绑定ENS名字
    if (!ensName) {
      return '该地址没有绑定ENS名字';
    }
    return ensName;
  } catch (err) {
    console.error('反向解析出错:', err);
    return '解析失败,请检查输入的地址';
  }
}

// 6. 给按钮绑定点击事件
document.getElementById('reverseResolveBtn').addEventListener('click', async () => {
  const address = document.getElementById('addressInput').value.trim();
  if (!address) {
    document.getElementById('reverseResult').textContent = '请输入地址';
    return;
  }
  const result = await reverseResolve(address);
  document.getElementById('reverseResult').textContent = `解析结果:${result}`;
});
</script>

这个代码也很完整,你只要把Infura的项目ID换成自己的,就能直接运行。比如输入一个绑定了ENS名字的地址,就能得到对应的名字。

五、实际应用场景、技术优缺点和注意事项

5.1 应用场景

这个功能在DApp里的应用场景非常多,比如:

  1. 钱包连接后的欢迎语:用户连接钱包后,DApp显示“欢迎回来,张三.eth”,而不是乱码地址;
  2. 转账页面的接收方显示:用户输入接收方的ENS名字,DApp自动转成地址,或者显示接收方的ENS名字;
  3. 社交类DApp的用户昵称:比如去中心化社交平台,用户的昵称就是自己的ENS名字,不用额外设置;
  4. 交易类DApp的历史记录:交易记录里显示对方的ENS名字,而不是乱码地址,方便用户识别。

5.2 技术优缺点

优点:

  1. 大大提升用户体验:好记的名字比乱码地址好太多,用户不容易输错;
  2. 去中心化:ENS是部署在以太坊上的,没有中心化的机构控制,不会被封号或者删除;
  3. 兼容性好:几乎所有的钱包和DApp都支持ENS,不用额外适配;
  4. 可以自定义:用户可以把ENS名字绑定到自己的多个地址,方便管理。

缺点:

  1. 依赖以太坊网络:解析需要调用以太坊合约,速度受以太坊网络拥堵的影响,可能会有延迟;
  2. 有成本:注册ENS名字需要付以太坊的Gas费,虽然不贵,但还是有成本;
  3. 解析失败的情况多:如果ENS名字不存在、没有绑定地址、网络不好,都会导致解析失败;
  4. 安全问题:如果ENS名字被恶意注册,可能会被用来钓鱼,比如把和官方相似的ENS名字绑定到恶意地址,骗用户转账。

5.3 注意事项

  1. 节点选择:一定要选稳定的节点,比如Infura、Alchemy的节点,不要用不稳定的公共节点,否则解析容易失败;
  2. 错误处理:一定要做好错误处理,比如解析失败的时候,要给用户友好的提示,不要让页面崩溃;
  3. 缓存机制:如果同一个地址或者ENS名字经常被解析,最好加缓存,比如把解析结果存在本地存储(localStorage)里,下次再解析的时候直接用缓存,减少网络请求,提升速度;
  4. 安全验证:转账的时候,即使解析出了地址,也要给用户显示完整的地址,让用户确认,防止钓鱼;
  5. 版本兼容:Web3.js的版本要和ENS合约的版本兼容,不要用太新的或者太旧的版本,避免API变动导致出错。

六、总结

用Web3.js实现ENS的正向和反向解析,其实就是调用以太坊上的ENS合约,把乱码的地址和好记的名字互相转换,从而优化DApp的用户体验。整个流程不难,只要跟着步骤走,准备好节点,写好代码,做好错误处理和缓存,就能实现。

这个功能对于DApp来说是非常实用的,能大大降低用户的使用门槛,提升用户的好感度。当然,也要注意安全问题,做好验证,防止用户被骗。