# DomainsIP-3: Reverse Resolution

**Abstract**

This DomainsP specifies a TLD, registrar, and resolver interface for reverse resolution of Ethereum addresses using Domains. 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.

**Motivation**

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:

* 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.
* Attaching metadata such as descriptive information to an address allows retrieving this information regardless of how the address was originally discovered.
* 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.

**Specification**

Reverse Domains records are stored in the Domains hierarchy in the same fashion as regular records, under a reserved domain, `addr.reverse`. To generate the Domains name for a given account's reverse records, convert the account to hexadecimal representation in lower-case, and append `addr.reverse.`

**Registrar**

The owner of the `addr.reverse` domain will be a registrar that permits the caller to take ownership of the reverse record for their own address. It provides the following methods:

function claim(address owner) returns (bytes32 node)

When called by account  `x` , instructs the Domains registry to transfer ownership of the name `hex(x) + '.addr.reverse'` to the provided address, and return the namehash of the Domains record thus transferred.

Allowing the caller to specify an owner other than themselves for the relevant node facilitates contracts that need accurate reverse Domains entries delegating this to their creators with a minimum of code inside their constructor:

```
reverseRegistrar.claim(msg.sender)
```

**function claimWithResolver(address owner, address resolver) returns (bytes32 node)**

When called by account x, instructs the Domains 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 Domains record thus transferred. This method facilitates setting up a custom resolver and owner in fewer transactions than would be required if calling  `claim`.

**function setName(string name) returns (bytes32 node)**

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.

**Resolver interface**

A new resolver interface is defined, consisting of the following method:

```javascript
function name(bytes32 node) constant returns (string
```

Resolvers that implement this interface must return a valid Domains name for the requested node, or the empty string if no name is defined for the requested node.

The interface ID of this interface is 0x691f3431.

Future DomainsIPs may specify more record types appropriate to reverse DNS records.

**Appendix 1: Registrar implementation**

This registrar, written in Solidity, implements the specifications outlined above.

```javascript
pragma solidity >=0.8.4;

import "./TDNS.sol";
import "./IReverseRegistrar.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../root/Controllable.sol";

abstract contract NameResolver {
   function setName(bytes32 node, string memory name) public virtual;
}

bytes32 constant lookup = 0x3031323334353637383961626364656600000000000000000000000000000000;

bytes32 constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;

// namehash('addr.reverse')

contract ReverseRegistrar is Ownable, Controllable, IReverseRegistrar {
   TDNS public immutable tdns;
   NameResolver public defaultResolver;

   event ReverseClaimed(address indexed addr, bytes32 indexed node);

   /**
    * @dev Constructor
    * @param tdnsAddr The address of the TDNS registry.
    */
   constructor(TDNS tdnsAddr) {
       tdns = tdnsAddr;

       // Assign ownership of the reverse record to our deployer
       ReverseRegistrar oldRegistrar = ReverseRegistrar(
           tdnsAddr.owner(ADDR_REVERSE_NODE)
       );
       if (address(oldRegistrar) != address(0x0)) {
           oldRegistrar.claim(msg.sender);
       }
   }

   modifier authorised(address addr) {
       require(
           addr == msg.sender ||
               controllers[msg.sender] ||
               tdns.isApprovedForAll(addr, msg.sender) ||
               ownsContract(addr),
           "ReverseRegistrar: Caller is not a controller or authorised by address or the address itself"
       );
       _;
   }

   function setDefaultResolver(address resolver) public override onlyOwner {
       require(
           address(resolver) != address(0),
           "ReverseRegistrar: Resolver address must not be 0"
       );
       defaultResolver = NameResolver(resolver);
   }

   /**
    * @dev Transfers ownership of the reverse TDNS record associated with the
    *      calling account.
    * @param owner The address to set as the owner of the reverse record in TDNS.
    * @return The TDNS node hash of the reverse record.
    */
   function claim(address owner) public override returns (bytes32) {
       return claimForAddr(msg.sender, owner, address(defaultResolver));
   }

   /**
    * @dev Transfers ownership of the reverse TDNS record associated with the
    *      calling account.
    * @param addr The reverse record to set
    * @param owner The address to set as the owner of the reverse record in TDNS.
    * @return The TDNS node hash of the reverse record.
    */
   function claimForAddr(
       address addr,
       address owner,
       address resolver
   ) public override authorised(addr) returns (bytes32) {
       bytes32 labelHash = sha3HexAddress(addr);
       bytes32 reverseNode = keccak256(
           abi.encodePacked(ADDR_REVERSE_NODE, labelHash)
       );
       emit ReverseClaimed(addr, reverseNode);
       tdns.setSubnodeRecord(ADDR_REVERSE_NODE, labelHash, owner, resolver, 0);
       return reverseNode;
   }

   /**
    * @dev Transfers ownership of the reverse TDNS record associated with the
    *      calling account.
    * @param owner The address to set as the owner of the reverse record in TDNS.
    * @param resolver The address of the resolver to set; 0 to leave unchanged.
    * @return The TDNS node hash of the reverse record.
    */
   function claimWithResolver(address owner, address resolver)
       public
       override
       returns (bytes32)
   {
       return claimForAddr(msg.sender, owner, resolver);
   }

   /**
    * @dev Sets the `name()` record for the reverse TDNS record associated with
    * the calling account. First updates the resolver to the default reverse
    * resolver if necessary.
    * @param name The name to set for this address.
    * @return The TDNS node hash of the reverse record.
    */
   function setName(string memory name) public override returns (bytes32) {
       return
           setNameForAddr(
               msg.sender,
               msg.sender,
               address(defaultResolver),
               name
           );
   }

   /**
    * @dev Sets the `name()` record for the reverse TDNS record associated with
    * the account provided. First updates the resolver to the default reverse
    * resolver if necessary.
    * Only callable by controllers and authorised users
    * @param addr The reverse record to set
    * @param owner The owner of the reverse node
    * @param name The name to set for this address.
    * @return The TDNS node hash of the reverse record.
    */
   function setNameForAddr(
       address addr,
       address owner,
       address resolver,
       string memory name
   ) public override returns (bytes32) {
       bytes32 node = claimForAddr(addr, owner, resolver);
       NameResolver(resolver).setName(node, name);
       return node;
   }

   /**
    * @dev Returns the node hash for a given account's reverse records.
    * @param addr The address to hash
    * @return The TDNS node hash.
    */
   function node(address addr) public pure override returns (bytes32) {
       return
           keccak256(
               abi.encodePacked(ADDR_REVERSE_NODE, sha3HexAddress(addr))
           );
   }

   /**
    * @dev An optimised function to compute the sha3 of the lower-case
    *      hexadecimal representation of an Ethereum address.
    * @param addr The address to hash
    * @return ret The SHA3 hash of the lower-case hexadecimal encoding of the
    *         input address.
    */
   function sha3HexAddress(address addr) private pure returns (bytes32 ret) {
       assembly {
           for {
               let i := 40
           } gt(i, 0) {

           } {
               i := sub(i, 1)
               mstore8(i, byte(and(addr, 0xf), lookup))
               addr := div(addr, 0x10)
               i := sub(i, 1)
               mstore8(i, byte(and(addr, 0xf), lookup))
               addr := div(addr, 0x10)
           }

           ret := keccak256(0, 40)
       }
   }

   function ownsContract(address addr) internal view returns (bool) {
       try Ownable(addr).owner() returns (address owner) {
           return owner == msg.sender;
       } catch {
           return false;
       }
   }
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tomi-domains.gitbook.io/tomi-domains/introduction/domains/domainsip-3-reverse-resolution.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
