# ENS: Ethereum Name Service

By [syshen](https://paragraph.com/@syshen) · 2022-02-05

---

在 blockchain 的世界裡，每個人的 identity 都會是一個位址，像是`0x956f206BF42B6FCEacacBEb759Bc234921B55eCf`，這是錢包的位址，這是一個 42 字元組成的 public key hash，基本上沒有人記得住這一長串字元，所以大部分遇到時都是用複製貼上，或者 QR Code scan 的方式來傳遞。

所以好像很自然，Name resolve service 就有存在的必要，像是 IP address 與 domain name 互查的 DNS 系統，在區塊鏈中也有套類似的架構，稱之為 ENS: Ethereum Name Service。

你可以為你的錢包位址登記一個好記的名字，像是 `be-rich.eth` ，如果去反查這個名字就會是 `0x956f206BF42B6FCEacacBEb759Bc234921B55eCf` 。

ENS 有兩大智能合約所組成，分別是 Registry ([EIP-137](https://eips.ethereum.org/EIPS/eip-137)) 跟 Resolver，Resolver 也支援好幾種不同的查詢方式，也包含一般的網路域名，還有 TXT Record。

來了解一下它怎麼運作的:

我先到 ens.domain 買了一個域名 `be-rich.eth`，隨後就會透過我的 Metamask 錢包與合約互動。

註冊通常很快，約一分鐘完成，隨後我們打開 etherscan 來看看他做了哪些動作。

這是[該筆](https://etherscan.io/tx/0xc02e17a0cd735bbf178b157c7cf11f0cc0096b4c8f0cf2268cb17c305c0194ab)交易。

首先你會看到交易紀錄，它先 Mint 了一顆 Token ，再把這顆 Token 的 Owner 轉到我的位址下。

![](https://storage.googleapis.com/papyrus_images/e32794d4a27244c60f99286c1c81db61cfe1808757d790790ea5ecd1e2f41f04.png)

然後裡面包含兩次的 Token 轉移，一次是從 0x0 轉到 ENS 的 Registry ，一次是從 ENS Registry 轉移到我的位址。

![](https://storage.googleapis.com/papyrus_images/feb5f1fa9f0572fa0a75ac4218ee8632f2fddf5799ebf02fe1b146f47f236728.png)

Token 是符合 ERC-721 規範，也就是說它是顆 NFT。

所以在我的 Opensea 下也可以看到這顆 Token

![](https://storage.googleapis.com/papyrus_images/ef7670b80ad7ecb78f0536031940288d41cd6e3f1f304f5c415458e87cf80f6c.png)

* * *

再來看看註冊域名時，它怎麼呼叫[合約](https://etherscan.io/address/0x283af0b28c62c092c9727f1ee09c02ca627eb7f5)的：

![](https://storage.googleapis.com/papyrus_images/05cb794c4d864fe3ded25dc41e2099ab8f27e9faa6a881a2568f66c1e6732aa5.png)

![](https://storage.googleapis.com/papyrus_images/bc8042d3da3cf3d78135f39ce5c45b8e72d0f069629ba6a95d8260ffe74afc3a.png)

看來是呼叫合約中的 `registerWithConfig()` 函式，帶的參數有包含名稱 (be-rich.eth)，owner 位址(也就是我的錢包位址)，duration 為 31556952 也就是比 365 天多一點點 (應該是為了處理閏年)，設定的 resolver 位址為 0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41，這個是 ENS 的 [Public Resolver 2](https://etherscan.io/address/0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41) 的合約位址。

ENS 有個特色，`.eth` 屬於根域名，假如你註冊個 `apple.eth` ，未來你可以自行發行子域名，例如 `steve.apple.eth` ，你可以有自己的 Resolver 來反查子域名，不必都透過公用的 resolver，所以在購買 ENS token 時，可以指定 Resolver 合約的位址，而你要寫 Resolver 也很簡單，只要符合它的定義就好。 不過想單然而，因為有這樣的設計，現在就會有很多人搶著註冊有名的域名來當蟑螂，就跟 DNS 一樣，所以未來一些大公司真的開始想進入 blockchain 領域時，可能要準備一筆錢來買域名了。

ENS 合約內並不是儲存完整的域名，而是儲存域名的 Hash，它稱之為 namehash。它的概念是以 dot 為區隔拆出各個名稱 (label)，然後去作 hash，例如 be-rich.eth 可以拆出兩個 label 分別是 be-rich 以及 eth，namehash 的算法如下：

    namehash([]) = 0x0000000000000000000000000000000000000000000000000000000000000000
    namehash([label, …]) = keccak256(namehash(…), keccak256(label))
    

namehash 再去轉換成一個 32bytes 的 unsighted int 作為 tokenID，合約裡儲存的就是 tokenID 與 owner address 間的 mapping。

要反查名稱時，你可以自己寫合約來查詢，也可以透過 ENS 官方提供的 Libraries 來查詢。以 ensjs Javascript library 來作的話就像這樣:

    var address = await ens.name('be-rich.eth').getAddress();
    

原理上也是一樣，透過域名取得 namehash，然後由 namehash 先取得 Resolver，再跟 Resolver 詢問位址。

也可以透過智能合約來查詢

    abstract contract ENS {
        function resolver(bytes32 node) public virtual view returns (Resolver);
    }
    
    abstract contract Resolver {
        function addr(bytes32 node) public virtual view returns (address);
    }
    
    contract MyContract {
        // Same address for Mainet, Ropsten, Rinkerby, Gorli and other networks;
        ENS ens = ENS(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);
    
        function resolve(bytes32 node) public view returns(address) {
            Resolver resolver = ens.resolver(node);
            return resolver.addr(node);
        }
    }
    

* * *

有這個域名能幹嘛？ 目前多數錢包都有支援 ENS，所以當你在做交易時，就不再需要使用錢包位址這麼難記的字串，直接請對方輸入你的域名就好，例如在 metamask 中，你只需要傳送 ETH 到 be-rich.eth 就可以轉進到我的錢包中了。

不過就像目前 Internet ，域名蟑螂是個嚴重的問題，在 ENS 中會更嚴重。想像一下，如果我註冊一個 paypal.eth，是否就機會偽裝成 paypal 到處去跟小白收款，或者註冊 google.eth、apple.eth，就可以等著大公司來跟我收購這些域名，因為這些 Trademark 都是在區塊鏈出來之前就已經存在了，但是在區塊鏈中違反 trademark 對這些蟑螂來說無傷痛癢。而 ENS 唯一能做的是透過每年 renew 的費用來增加蟑螂的成本，但對於資本雄厚，或者已經擁有高價值 trademark 的域名來說，似乎無傷痛癢。

---

*Originally published on [syshen](https://paragraph.com/@syshen/ens-ethereum-name-service)*
