# Dapp Developer Guide

**Domains Enabling your DApp**

Domains integration in an application encompasses several critical features, each of which can be implemented independently. While comprehensive Domains integration is ideal, even basic support can be a huge benefit to users. Below, we outline three levels of Domains integration. Level 1 is easily achieved and provides high impact for users, while levels 2 and 3 provide more functionality to your users, improving your DApp's usability and your users' experience interacting with your DApp.

**1. Resolving Domains names**

The first step to supporting Domains in your application is making your application understand Domains names, and accepting them anywhere an address is accepted. To understand how to do this, see Resolving Names.

If possible, when a user enters an Domains name instead of an address, remember the Domains name, not the address it currently resolves to. This makes it possible for users to update their DNS names and have applications they used the name in automatically resolve to the new address, in the same way that you would expect your browser to automatically direct you to the new IP address if a site you use changes servers.

If your application deals with user funds or other critical resources, you may want to keep track of the address a name resolves to and warn them when it changes, to ensure they are aware of the change.

**2. Support Reverse Resolution**

The second level of Domains integration involves displaying Domains names wherever your app currently displays addresses.

If a user entered a Domains in your DApp, you should retain this name and show it to them whenever you would normally show the address.

If a user entered an address, or the address was obtained from elsewhere, you may still be able to show a Domains name, by doing Reverse Resolution. This permits you to find the canonical name for an address and display that when possible. If no canonical name is provided, your application can fall back to displaying the address as it did previously.

By supporting reverse resolution, you make it easier for your users to identify accounts they interact with, associating them with a short human-readable name instead of a long opaque wallet address.

**3. Let Users Name Things**

The final step for comprehensive Domains integration is to facilitate associating Domains names with resources created by or managed with your application. This can take two forms:

**Name Registration**

By obtaining a Domains name for your product and allowing users to easily register subdomains, you can provide users with an easy way to name resources created in your DApp. For example, if your DApp is a cryptocurrency wallet, you can make it easy for users to obtain an Domains domain of the form theirname.yourwallet.tomi, allowing them to give their name out to others more easily.

To learn how to do this, see Writing a Registrar in the Smart Contract Developer Guide.\
**Name Updates**

By providing users with an easy way to update a name they own to point at your application’s resources, users can assign names they already own to your DApp's resources. See Managing Names to learn how to do this.

**Encoding and decoding contenthash**

`contenthash` is used to store IPFS and Swarm content hashes, which permit resolving Domains addresses to distributed content (eg, websites) hosted on these distributed networks. content-hash javascript library provides a convenient way to encode/decode these hashes.

```javascript
const contentHash = require('content-hash')
const encoded = 'e3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f'
const content = contentHash.decode(encoded)
// 'QmRAQB6YaCyidP37UdDnjFY5vQuiBrcqdyoW1CuDgwxkD4'

const onion = 'zqktlwi4fecvo6ri'
contentHash.encode('onion', onion);
// 'bc037a716b746c776934666563766f367269'

const encoded = 'e40101701b20d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162'

const codec = contentHash.getCodec(encoded) // 'swarm-ns'
codec === 'ipfs-ns' // false
```

Note for ipns: For security reasons, the encoding of ipns is only allowed for libp2p-key codec. Decoding with other formats will show a deprecation warning.

**Coin type and encoding/decoding**

While some libraries allow you to query cryptocurrency addresses via their symbol (e.g.: BTC), others do not have the built-in support, and you have to call via each coin id (e.g.: 0 for BTC, 16 for \`ETH). For Javascript/Typescript, we have library that allows you to convert.

```javascript
import { formatsByName, formatsByCoinType } from '@ensdomains/address-encoder';

formatsByName['BTC']
// {
//   coinType: 0,
//   decoder: [Function (anonymous)],
//   encoder: [Function (anonymous)],
//   name: 'BTC'
// }
```

To save storage space as well as prevent users from setting wrong token addresses, the library has an `encoder` and `decoder`.

```javascript
const data = formatsByName['BTC'].decoder('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa');
console.log(data.toString('hex')); // 76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac
const addr = formatsByCoinType[0].encoder(data);
console.log(addr); // 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
```

**Listing cryptocurrency addresses and text records**

For cryptocurrency addresses and text records, you need to know the coin type or key names to get the value. If you want to list down all the cryptocurrency addresses and text records the user has set, you have to either retrieve the information from `Event` or query via Domains subgraph.

**For example**

```javascript
{
 domains(where:{name:"xyz.tomi"}) {
   id
   name
   resolver{
     texts
     coinTypes
   }
 }
}
```

will return the following result

```javascript
{
 "data": {
   "domains": [
     {
       "id": "0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835",
       "name": "xyz.tomi",
       "resolver": {
         "coinTypes": [
           60
         ],
         "texts": [
           "url"
         ]
       }
     }
   ]
}
}
```

**Reverse Resolution**

While 'regular' resolution involves mapping from a name to an address, reverse resolution maps from an address back to a name. Domains supports reverse resolution to allow applications to display Domains names in place of hexadecimal addresses.

Reverse resolution is accomplished via the special purpose domain addr.reverse and the resolver function name(). addr.reverse is owned by a special purpose registrar contract that allocates subdomains to the owner of the matching address - for instance, the address 0xDDe6812a9CEaaC3B6b3AB49F29D3951F2C0A71D8 may claim the name 0xDDe6812a9CEaaC3B6b3AB49F29D3951F2C0A71D8.addr.reverse, and configure a resolver and records on it. The resolver in turn supports the name() function, which returns the name associated with that address.

ost libraries provide functionality for doing reverse resolution:

**ensjs**

```javascript
const address = '0x1234...';
let ensName = null;
({ name: ensName } = await ens.getName(address))
// Check to be sure the reverse record is correct. skip check if the name is null
if(ensName == null || address != await ens.name(ensName).getAddress()) {
 ensName = null;
}
```

**web3.js**

```
Not supported.
```

**ethjs-ens**

```javascript
var address = '0x1234...';
var name = await ens.reverse(address);
// Check to be sure the reverse record is correct.
if(address != await ens.lookup(name)) {
  name = null;
}
```

**ethers.js**

```javascript
var address = '0x1234...';
var name = await provider.lookupAddress(address);
// ethers.js automatically checks that the forward resolution matches.
```

**go-ens**

```javascript
name, err := ens.ReverseResolve(client, common.HexToAddress("0x1234...")
```

**web3.py**

```javascript
address = '0x1234...'
name = ns.reverse(address)
# Check to be sure the reverse record is correct.
if address != ns.address(name):
  name = None
```

**web3j**

```javascript
String address = "0x1234...";
String name = ens.reverseResolve(address);
// Check to be sure the reverse record is correct.
if(address != ens.resolve(name)) {
  name = null;
}
```

Reverse resolution without a library follows the same pattern as forward resolution: Get the resolver for `1234....addr.reverse`(where 1234... is the address you want to reverse-resolve), and call the `name()` function on that resolver. Then, perform a forward resolution to verify the record is accurate.

If you need to process many addresses (eg: showing reverse record of transaction histories), resolving both reverse and forward resolution for each item may not be practical. We have a separate smart contract called `ReverseRecords` which allows you to lookup multiple names in one function call.

```javascript
const namehash = require('eth-ens-namehash');
const allnames = await ReverseRecords.getNames(['0x123','0x124'])
const validNames = allnames.filter((n) => namehash.normalize(n) === n )
```

Make sure to compare that the returned names match with the normalised names to prevent from[ <mark style="color:red;">homograph attack</mark>](https://en.wikipedia.org/wiki/IDN_homograph_attack) as well as people simply using capital letters.
