/ EIPS / eip-181.md
eip-181.md
  1  ---
  2  eip: 181
  3  title: ENS support for reverse resolution of Ethereum addresses
  4  author: Nick Johnson <arachnid@notdot.net>
  5  status: Final
  6  type: Standards Track
  7  category: ERC
  8  created: 2016-12-01
  9  ---
 10  
 11  # Abstract
 12  This EIP specifies a TLD, registrar, and resolver interface for reverse resolution of Ethereum addresses using ENS. This permits associating a human-readable name with any Ethereum blockchain address. Resolvers can be certain that the reverse record was published by the owner of the Ethereum address in question.
 13  
 14  # Motivation
 15  While name services are mostly used for forward resolution - going from human-readable identifiers to machine-readable ones - there are many use-cases in which reverse resolution is useful as well:
 16  
 17   - Applications that allow users to monitor accounts benefit from showing the name of an account instead of its address, even if it was originally added by address.
 18   - Attaching metadata such as descriptive information to an address allows retrieving this information regardless of how the address was originally discovered.
 19   - Anyone can configure a name to resolve to an address, regardless of ownership of that address. Reverse records allow the owner of an address to claim a name as authoritative for that address.
 20  
 21  # Specification
 22  Reverse ENS records are stored in the ENS hierarchy in the same fashion as regular records, under a reserved domain, `addr.reverse`. To generate the ENS name for a given account's reverse records, convert the account to hexadecimal representation in lower-case, and append `addr.reverse`. For instance, the ENS registry's address at `0x112234455c3a32fd11230c42e7bccd4a84e02010` has any reverse records stored at `112234455c3a32fd11230c42e7bccd4a84e02010.addr.reverse`.
 23  
 24  Note that this means that contracts wanting to do dynamic reverse resolution of addresses will need to perform hex encoding in the contract.
 25  
 26  ## Registrar
 27  The owner of the `addr.reverse` domain will be a registrar that permits the caller to take ownership of 
 28  the reverse record for their own address. It provides the following methods:
 29  
 30  ### function claim(address owner) returns (bytes32 node)
 31  
 32  When called by account `x`, instructs the ENS registry to transfer ownership of the name `hex(x) + '.addr.reverse'` to the provided address, and return the namehash of the ENS record thus transferred.
 33  
 34  Allowing the caller to specify an owner other than themselves for the relevant node facilitates contracts that need accurate reverse ENS entries delegating this to their creators with a minimum of code inside their constructor:
 35  
 36      reverseRegistrar.claim(msg.sender)
 37  
 38  ### function claimWithResolver(address owner, address resolver) returns (bytes32 node)
 39  
 40  When called by account `x`, instructs the ENS registry to set the resolver of the name `hex(x) + '.addr.reverse'` to the specified resolver, then transfer ownership of the name to the provided address, and return the namehash of the ENS record thus transferred. This method facilitates setting up a custom resolver and owner in fewer transactions than would be required if calling `claim`.
 41  
 42  ### function setName(string name) returns (bytes32 node)
 43  
 44  When called by account `x`, sets the resolver for the name `hex(x) + '.addr.reverse'` to a default resolver, and sets the name record on that name to the specified name. This method facilitates setting up simple reverse records for users in a single transaction.
 45  
 46  ## Resolver interface
 47  A new resolver interface is defined, consisting of the following method:
 48  
 49      function name(bytes32 node) constant returns (string);
 50  
 51  Resolvers that implement this interface must return a valid ENS name for the requested node, or the empty string if no name is defined for the requested node.
 52  
 53  The interface ID of this interface is 0x691f3431.
 54  
 55  Future EIPs may specify more record types appropriate to reverse ENS records.
 56  
 57  # Appendix 1: Registrar implementation
 58  
 59  This registrar, written in Solidity, implements the specifications outlined above.
 60  
 61      pragma solidity ^0.4.10;
 62  
 63      import "./AbstractENS.sol";
 64  
 65      contract Resolver {
 66          function setName(bytes32 node, string name) public;
 67      }
 68  
 69      /**
 70       * @dev Provides a default implementation of a resolver for reverse records,
 71       * which permits only the owner to update it.
 72       */
 73      contract DefaultReverseResolver is Resolver {
 74          AbstractENS public ens;
 75          mapping(bytes32=>string) public name;
 76  
 77          /**
 78           * @dev Constructor
 79           * @param ensAddr The address of the ENS registry.
 80           */
 81          function DefaultReverseResolver(AbstractENS ensAddr) {
 82              ens = ensAddr;
 83          }
 84  
 85          /**
 86           * @dev Only permits calls by the reverse registrar.
 87           * @param node The node permission is required for.
 88           */
 89          modifier owner_only(bytes32 node) {
 90              require(msg.sender == ens.owner(node));
 91              _;
 92          }
 93  
 94          /**
 95           * @dev Sets the name for a node.
 96           * @param node The node to update.
 97           * @param _name The name to set.
 98           */
 99          function setName(bytes32 node, string _name) public owner_only(node) {
100              name[node] = _name;
101          }
102      }
103  
104      contract ReverseRegistrar {
105          // namehash('addr.reverse')
106          bytes32 constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
107  
108          AbstractENS public ens;
109          Resolver public defaultResolver;
110  
111          /**
112           * @dev Constructor
113           * @param ensAddr The address of the ENS registry.
114           * @param resolverAddr The address of the default reverse resolver.
115           */
116          function ReverseRegistrar(AbstractENS ensAddr, Resolver resolverAddr) {
117              ens = ensAddr;
118              defaultResolver = resolverAddr;
119          }
120  
121          /**
122           * @dev Transfers ownership of the reverse ENS record associated with the
123           *      calling account.
124           * @param owner The address to set as the owner of the reverse record in ENS.
125           * @return The ENS node hash of the reverse record.
126           */
127          function claim(address owner) returns (bytes32 node) {
128              return claimWithResolver(owner, 0);
129          }
130  
131          /**
132           * @dev Transfers ownership of the reverse ENS record associated with the
133           *      calling account.
134           * @param owner The address to set as the owner of the reverse record in ENS.
135           * @param resolver The address of the resolver to set; 0 to leave unchanged.
136           * @return The ENS node hash of the reverse record.
137           */
138          function claimWithResolver(address owner, address resolver) returns (bytes32 node) {
139              var label = sha3HexAddress(msg.sender);
140              node = sha3(ADDR_REVERSE_NODE, label);
141              var currentOwner = ens.owner(node);
142  
143              // Update the resolver if required
144              if(resolver != 0 && resolver != ens.resolver(node)) {
145                  // Transfer the name to us first if it's not already
146                  if(currentOwner != address(this)) {
147                      ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, this);
148                      currentOwner = address(this);
149                  }
150                  ens.setResolver(node, resolver);
151              }
152  
153              // Update the owner if required
154              if(currentOwner != owner) {
155                  ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);
156              }
157  
158              return node;
159          }
160  
161          /**
162           * @dev Sets the `name()` record for the reverse ENS record associated with
163           * the calling account. First updates the resolver to the default reverse
164           * resolver if necessary.
165           * @param name The name to set for this address.
166           * @return The ENS node hash of the reverse record.
167           */
168          function setName(string name) returns (bytes32 node) {
169              node = claimWithResolver(this, defaultResolver);
170              defaultResolver.setName(node, name);
171              return node;
172          }
173  
174          /**
175           * @dev Returns the node hash for a given account's reverse records.
176           * @param addr The address to hash
177           * @return The ENS node hash.
178           */
179          function node(address addr) constant returns (bytes32 ret) {
180              return sha3(ADDR_REVERSE_NODE, sha3HexAddress(addr));
181          }
182  
183          /**
184           * @dev An optimised function to compute the sha3 of the lower-case
185           *      hexadecimal representation of an Ethereum address.
186           * @param addr The address to hash
187           * @return The SHA3 hash of the lower-case hexadecimal encoding of the
188           *         input address.
189           */
190          function sha3HexAddress(address addr) private returns (bytes32 ret) {
191              addr; ret; // Stop warning us about unused variables
192              assembly {
193                  let lookup := 0x3031323334353637383961626364656600000000000000000000000000000000
194                  let i := 40
195              loop:
196                  i := sub(i, 1)
197                  mstore8(i, byte(and(addr, 0xf), lookup))
198                  addr := div(addr, 0x10)
199                  i := sub(i, 1)
200                  mstore8(i, byte(and(addr, 0xf), lookup))
201                  addr := div(addr, 0x10)
202                  jumpi(loop, i)
203                  ret := sha3(0, 40)
204              }
205          }
206      }
207  
208  ## Copyright
209  Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).