# Introduction

## What are Tezos Domains?

[Tezos Domains](https://tezos.domains) is a distributed, open and extensible naming system using Tezos blockchain.&#x20;

The main function is to translate a meaningful and user-friendly alias to a Tezos address and vice versa. This translation is globally consistent so that all participants on the blockchain see the same address for a given alias.

A parallel that's often drawn is to the [DNS](https://en.wikipedia.org/wiki/Domain_Name_System), a familiar and universally adopted system:

> The Domain Name System (DNS) is a hierarchical and decentralized naming system for computers, services, or other resources connected to the Internet or a private network. It associates various information with domain names assigned to each of the participating entities.

An example of one such alias is `alice.tez`. Alice bought it from the central registrar managing `tez` and then assigned it the address of her personal wallet. When she sends money to Bob, he will see `alice.tez` in his wallet's received transactions, because Alice has also set up a reverse record mapping her address back to `alice.tez`.

## Motivation

Using addresses can become an obstacle for the practical use of Tezos as a currency. It’s clear that a string like `tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb` is usable when transferred by a computer program or using the operating system’s clipboard, but it is unwieldy in most other types of communication. It cannot be memorized or even realistically communicated through human speech or visual media.

People are already used to creating names for their e-mail boxes, Instagram accounts, or their web pages. This project is providing them with this familiar approach inside the Tezos ecosystem.

## Older articles

You can read our series on Designing a Name Service on the Tezos Agora which explains some of the design decisions taken:

* [Tezos Domains Alpha Release](https://forum.tezosagora.org/t/tezos-domains-developer-preview/2057)
* [Introducing Tezos Domains](https://forum.tezosagora.org/t/introducing-tezos-domains/1985)
* Our older articles exploring the idea in detail:
  * [Part 1: Introduction](https://forum.tezosagora.org/t/designing-a-name-service-part-1-introduction/1874)
  * [Part 2: Namespace and Structure](https://forum.tezosagora.org/t/designing-a-name-service-part-2-namespace-and-structure/1901)
  * [Part 3: Name Distribution and Pricing](https://forum.tezosagora.org/t/designing-a-name-service-part-3-name-distribution-and-pricing/1914)
  * [Part 4: Validation, Normalization, Encoding](https://forum.tezosagora.org/t/designing-a-name-service-part-4-validation-normalization-encoding/1915)
  * [Part 5: Retaining Trademarks](https://forum.tezosagora.org/t/designing-a-name-service-part-5-retaining-trademarks/1931)


# Client Libraries

We built a set of client libraries for Javascript/Typescript to help with integrating Tezos Domains. You can choose to use either [Taquito](https://tezostaquito.io/) or [ConseilJS](https://cryptonomic.github.io/ConseilJS) to power the client, depending on what you are already using. To learn more and get started check out the [API documentation](https://client-docs.tezos.domains/) and [example repository](https://gitlab.com/tezos-domains/examples).

We are using this library in our own dApp for all interactions with Smart Contracts to ensure it's functional and up to date. If you encounter any issues or have an idea for a new feature or improvement, feel free to create an [issue for us](https://gitlab.com/tezos-domains/client/issues).

## Packages

The functionality is split into two separate packages according to your particular use case:

### Resolver

This part can [resolve](https://client-docs.tezos.domains/interfaces/_tezos_domains_resolver.nameresolver-2.html) domain names to addresses and also the other way around by utilizing reverse records. You can also retrieve all domain metadata, which allows you to read arbitrary data that can be saved with a domain.

### Manager

With this, you can [execute operations](https://client-docs.tezos.domains/interfaces/_tezos_domains_manager.domainsmanager-2.html) that register or update domains, create subdomains, claim or update reverse records, interact with auctions, and more.

*(manager functions are not yet supported in ConseilJS implementation)*


# GraphQL

Our [GraphQL](https://graphql.org/) API allows querying the entire Tezos Domains catalogue of data including the historic versions of each entity at each block.

For more information, you can check:

* Our GraphQL [playground site](https://api.tezos.domains/playground)
* The [current schema](https://api-schema.tezos.domains/)

Our API exposes list data according to [Relay Connection specification](https://relay.dev/graphql/connections.htm). This makes it easy to generate client code and paginate using cursors in general.


# Mainnet

## GraphQL

<mark style="color:green;">`POST`</mark> `https://api.tezos.domains/graphql`

This endpoint allows you to query Tezos Domains data.

#### Request Body

| Name | Type   | Description          |
| ---- | ------ | -------------------- |
|      | object | GraphQL query object |

{% tabs %}
{% tab title="200 Tezos Domains data successfully retrieved." %}

```
{
  "data": {
    "domains": {
      "items": [
        {
          "address": "tz1VxMudmADssPp6FPDGRsvJXE41DD6i9g6n",
          "name": "aaa.tez",
          "owner": "tz1VxMudmADssPp6FPDGRsvJXE41DD6i9g6n",
          "level": 2
        },
        {
          "address": null,
          "name": "a.aaa.tez",
          "owner": "tz1VxMudmADssPp6FPDGRsvJXE41DD6i9g6n",
          "level": 3
        },
        {
          "address": null,
          "name": "alice.tez",
          "owner": "tz1Q4vimV3wsfp21o7Annt64X7Hs6MXg9Wix",
          "level": 2
        }
      ]
    }
  },
  "extensions": {}
}
```

{% endtab %}

{% tab title="429 You are hitting the rate limits of Tezos Domains endpoint." %}

```
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 100 per 1m.
```

{% endtab %}
{% endtabs %}

### Examples:

#### Get addresses for domains:

```
{
   domains(where: { name: { in: ["domains.tez", "registry.domains.tez"] } }) {
    items {
      address
      owner
      name
      level
    }
  }
}
```

#### Get reverse records for addresses:

```
{
  reverseRecords(
    where: {
      address: {
        in: [
          "KT1Mqx5meQbhufngJnUAGEGpa4ZRxhPSiCgB"
          "KT1GBZmSxmnKJXGMdMLbugPfLyUPmuLSMwKS"
        ]
      }
    }
  ) {
    items {
      address
      owner
      domain {
        name
      }
    }
  }
}
```


# Smart Contract Overview

![Overview of Smart Contracts](/files/-M8FY1yLTpWbke6lzcJ5)

## Architecture & Upgradeability

Tezos Domains smart contracts are designed to be upgradeable on multiple levels:

* **bugfixes** can be deployed in the future by changing the implementation of existing code,
* **new features** can be introduced by adding new code,
* **storage structure** can be theoretically also extended (although this would be considered a major change that would require data migration).

Upgradeability is achieved by having:

* a set of implementation or **underlying** **contracts** that contain both storage and mutable code in the form of Michelson lambdas,
* a set of **proxy contracts** that act as an outward interface.

### Proxy Contracts

Proxy contracts provide a fixed interface that will always keep working under the same address and will be kept forward-compatible. A proxy contract can also be repointed to a new underlying contract in case of a major upgrade that requires the storage to be migrated.

To optimize for gas cost, we keep only one entrypoint per proxy contract. Every proxy contract is prefixed by the name of its underlying contract (e.g. `NameRegistry.CheckAddress` is the proxy contract that contains the `check_address` entrypoint and uses `NameRegistry` as the underlying contract). The usage of proxy contracts by clients is further detailed in the [Interoperability](/interoperability/name-resolution) chapter.

### Underlying Contracts

Underlying (or implementation) contracts store the actual Tezos Domains data along with bigmaps that contain executable code. Storing code in this way has two purposes: stored code can later be updated by a trusted multisig contract if needed and there is a significant benefit of lower gas costs (and, by extension, transaction fees paid by the user).

## NameRegistry

An upgradeable contract that stores the actual domain records.

### Forward Records

Forward records (or just records) represent all domains in the system, indexed by their name. There is an implied hierarchy of domains - ownership of a domain allows you to create or replace sub-domains. For every domain, the following information is stored (implementation-specific fields are omitted):

* **Owner** (`address`) is an account authorized to make changes to the record and manage subdomains of the given domain.
* **Resolution address**, the optional `address` the name resolves to.
* **Additional data**, a map with any additional data clients wish to store with the domain.
* **Expiry reference**, a reference inside the expiry map, which contains timestamps for every second-level domain. This timestamp represents a point in time when the domain ceases to be valid.
* **TZIP-12 token ID** that identifies 2nd-level domains when used as [NFTs](/interoperability/domains-as-nfts). Domains that are not 2nd-level don't have a token ID.

Supported **operations** on records are:

* resolving a name and returning the resolved address (implemented as a view),
* updating records,
* creating new sub-records.

### Reverse Records

Reverse records represent mapping of addresses to their names. Reverse records are optional, but if a reverse record exists for a given address, its name (if it has one) must resolve back to that address - consistency is guaranteed on-chain. For every address, the following information is stored:

* **Owner** (`address`) is an account authorized to make changes to the record.
* **Name** is the optional name this reverse record resolves to.

Supported **operations** on reverse records are:

* resolving an address and returning the resolved name (implemented as a view),
* claiming records for the sender and replacing the previous owner,
* updating records.

## TLDRegistrar

This upgradeable smart contract is responsible for managing the top-level domains. It keeps track of registered second-level domains, their owners, and expiration times. More details on the smart contract are available in the [next chapter](/design-document/top-level-domain-registrar).


# Top-Level Domain Registrar

The registrar smart contract is responsible for managing the top-level domains. It sells second-level domains to buyers and allows renewals.

## Open Auction

At service launch, every domain is offered to users through auction first. The registrar implements an [open ascending price auction](https://en.wikipedia.org/wiki/English_auction) model. It is an auction model most people are likely familiar with: all bids are openly visible and every new bid is required to be higher than the last bid. If there are no bids in a given period since the last bid, the auction ends with the highest bidder winning the auction.

### Bids

Any account can submit a bid during an active auction and transfer associated funds along in the same transaction. If a bid is higher or equal to the current highest bid multiplied by (100% + [min\_bid\_increase\_ratio](/design-document/top-level-domain-registrar#configuration)%), it becomes the new highest bid and the previous highest bid becomes refundable or available for future bids (on the same or a different domain). Otherwise, the transaction fails. The auction ends after [bid\_additional\_period](/design-document/top-level-domain-registrar#configuration) seconds since the last bid, but not earlier than [min\_auction\_period](/design-document/top-level-domain-registrar#configuration) since the auction's start.

A special case is the first bid, which has to be greater or equal to [standard\_price\_per\_day](/design-document/top-level-domain-registrar#configuration). When a previously unregistered domain name is first bid on, the name is pre-registered in the name registry to ensure its validity.

### Settlement

After the auction ends, there is a settlement period of the same length as [min\_duration](/design-document/top-level-domain-registrar#configuration). The highest bidder invokes the settlement process transferring the domain to a chosen address, which becomes the new owner. The domain is registered for the [min\_duration](/design-document/top-level-domain-registrar#configuration) (the time spent in the settlement period counts towards that period). If the highest bidder doesn't invoke settlement, the domain is treated as expired after the settlement phase ends.

## First-In First-Served Registration

An expired domain becomes available for FIFS only after its auction ended with no bids. In the FIFS model, all domains are sold for a flat fee equal to the [standard\_price\_per\_day](/design-document/top-level-domain-registrar#configuration). In the period after the launch of the smart contract, all domains are treated as recently expired.

For FIFS registration, the contract implements a commit & reveal scheme to avoid [front-running](https://medium.com/consensys-diligence/transparent-dishonesty-taxonomy-of-front-running-attacks-on-blockchain-317d8ff78068) of transactions.

## Renewals

Owners of domains can renew their domains at any time up until the domain expires. The chosen renewal period has to be greater or equal to [min\_duration](/design-document/top-level-domain-registrar#configuration). Renewals are priced using [standard\_price\_per\_day](/design-document/top-level-domain-registrar#configuration).

## Proceeds

Proceeds from Tezos Domains registrations and auctions are currently being accumulated in the smart contract. Only the [administrative multisig](/design-document/ownership-overview#administrative-multisig) can transfer funds stored in the contract. To learn more about the future plans for Tezos Domains proceeds, please [visit our website](https://tezos.domains/about/proceeds).

## Top-level Domain List

The susceptibility to spoofing attacks using look-alike characters is reduced by limiting TLDs to predefined character scripts. Neither whole-script and mixed-script [confusable](https://www.unicode.org/reports/tr39/#Confusable_Detection) names can be created under one TLD.

The top-level domains available are:

| Name                               | Description                         |
| ---------------------------------- | ----------------------------------- |
| [.tez](/interoperability/.tez-tld) | The standard TLD for names in Latin |

TLDs for more character scripts will be likely made available in the future.

## Configuration

There are several numeric parameters stored to configure this contract in the `config` bigmap. The keys of the bigmap following:

* `0 = max_commitment_age` is the maximum time for a buy commitment to be valid (in seconds)
* `1 = min_commitment_age` is the minimum time for a buy commitment to be valid (in seconds)
* `2 = standard_price_per_day` is the standard FIFS price for a day and the minimum amount that participants have to bid initially in auction (in picotezos = 1e-12 tez)
* `3 = min_duration` is the minimum period anyone can register or renew a domain for (in seconds)
* `4 = min_bid_increase_ratio` is the minimum ratio of a new bid to the current highest bid (in percent)
* `5 = min_auction_period` is the minimum auction period (in seconds)
* `6 = bid_additional_period` is the period after which the auction ends measured since the last successful bid (in seconds)
* `1000 = launch_date` is the start of the initial auction period for all domains, i.e., the date the service was officially launched (in second since epoch). The value of `0` means no launch has been configured
  * `1000 + label_length` is the override of the launch date for all labels that are `label_length` characters long


# Ownership Scheme

![Ownership Scheme](/files/-M8aOT0A5ONbE50WEF1g)

The ownership scheme in the name registry is as follows (from top to bottom):

1. **Top-level domains** are created by the administrative multisig and then transferred to the TLD registrar contract.
2. **Second-level domains** are in turn created by the TLD registrar on behalf of buying users and transferred to them upon creation. The users are then responsible for their management.
3. **Third-and-higher-level domain** creation and management is completely in the hands of the users.

## Administrative Multisig

A [formally verified](https://arxiv.org/pdf/1909.08671.pdf) multisig contract with keys held by well-known community members is the owner of all Tezos Domains contracts. This allows for administrative actions like:

* creating new top-level domains,
* updating the [TLD configuration](/design-document/top-level-domain-registrar#configuration),
* deploying new versions of contracts if a critical vulnerability is found.

Further details about the current multisig configuration are available [on our website](https://tezos.domains/about/keyholders).


# Domain Data

All **records** allow for storing arbitrary information in the "data" map:

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type data_map = (string, bytes) map
```

{% endtab %}

{% tab title="Michelson" %}

```
map %data string bytes
```

{% endtab %}
{% endtabs %}

All entries have:

* A **key** that should have a unique meaning. There is a set of reserved keys for typical use, but users are free to create new keys.
* A **value** which must be represented in JSON ([RFC 8259](https://tools.ietf.org/html/rfc8259)) and encoded in UTF-8.

## Reserved Keys

### Tezos Domains

All keys with the prefix `td:` are reserved for Tezos Domains-related metadata. We currently recognize:

| Key        | Meaning                                                                                                                                                                                                       | Type   | Example |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | ------- |
| **td:ttl** | The time-to-live of the record and an associated reverse record, if any (in seconds). If defined, it specifies the maximum time the record should be stored in caches and other secondary-storage mechanisms. | number | `600`   |

### Etherlink

All keys with the prefix `etherlink:` are reserved for Etherlink-related metadata. We currently recognize:

| Key               | Meaning                 | Type   | Example                                    |
| ----------------- | ----------------------- | ------ | ------------------------------------------ |
| etherlink:address | Your etherlink address. | string | 0x0000000000000000000000000000000000000000 |

### Web

The prefix `web:` is reserved for website urls.

| Key                          | Meaning                                                                                                                                                                              | Type   | Example                                                                                                                    |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| web:governance\_profile\_url | The governance post url which is desribing your Tezos Domains Delegate profile. More details [here](https://blog.tezos.domains/tezos-domains-is-looking-for-delegates-a1949706a8e6). | string | [`https://talk.tezos.domains/t/how-to-become-a-delegate/34/1`](https://talk.tezos.domains/t/how-to-become-a-delegate/34/4) |

### OpenID

The prefix `openid:` is reserved for OpenID claims. The values have their respective meanings according to the [OpenID spec](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). The value types specified in the OpenID spec must be adhered to.

| Key                                                              | Meaning                                                                                  | Type              | Example         |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------- | --------------- |
| <p><strong>openid:\<claim></strong></p><p>(e.g. openid:name)</p> | Any [OpenID claim](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) | *see OpenID spec* | `"Alice Smith"` |

### Gravatar

To provide an avatar representing their account, [Gravatar](https://gravatar.com/) users can equip their Tezos Domain with the MD5 hash of their Gravatar e-mail.

| Key               | Meaning                                                                                                              | Type   | Example                              |
| ----------------- | -------------------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------ |
| **gravatar:hash** | The [MD5 hash of the user's e-mail](https://en.gravatar.com/site/implement/hash/) on Gravatar in hexadecimal format. | string | `"0bc83cb571cd1c50ba6f3e8a78ef1346"` |

### Social media

| Key                  | Meaning                                        | Type   | Example       |
| -------------------- | ---------------------------------------------- | ------ | ------------- |
| **twitter:handle**   | The associated Twitter handle of the domain.   | string | `"BillGates"` |
| **instagram:handle** | The associated Instagram handle of the domain. | string | `"nasa"`      |

### Developer accounts

| Key                  | Meaning                      | Type   | Example      |
| -------------------- | ---------------------------- | ------ | ------------ |
| **github:username**  | User's GitHub account name.  | string | `"torvalds"` |
| **gitlab:username**  | User's GitLab account name.  | string | `"foobar"`   |
| **keybase:username** | User's Keybase account name. | string | `"foobar"`   |

### Source control

| Key                         | Meaning                   | Type   | Example                                            |
| --------------------------- | ------------------------- | ------ | -------------------------------------------------- |
| **project:repository\_url** | Project's Git repository. | string | `"https://gitlab.com/tezos-domains/contracts.git"` |


# Proxy Contracts

To ensure future upgradeability while allowing clients to rely on fixed contract addresses, we offer a set of proxy contracts. Any contract or off-chain client can interact with them directly - the transactions are automatically routed to the correct destination.

You can find the addresses of the proxy contracts in the [Deployed Contracts](broken://pages/-MUhowBkR50wd93jvqBX) section.

## Finding the Underlying Contract

Off-chain clients will often need to read data from an underlying contract. They can retrieve the individual addresses of underlying contracts from the proxy contract's storage. The generic storage structure follows:

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type proxy_storage = {
    contract: address;

    (* ... more fields outside of this interoperability spec *)
}
```

{% endtab %}

{% tab title="Michelson" %}

```
storage (pair
    (address %contract)
    (
        # ... more fields outside of this interoperability spec
    )
);
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Off-chain clients **must not** rely on a particular storage layout. They should always use annotations to find the correct value.
{% endhint %}


# Name Resolution

## NameRegistry

The `NameRegistry` contract provides forward and reverse resolution.

Clients retrieve the current address of `NameRegistry` by reading it from the storage of the proxy contract [NameRegistry.CheckAddress](/interoperability/domain-operations#contract-nameregistry-checkaddress) (as explained in the [Proxy Contracts](/interoperability/proxy-contracts#finding-the-underlying-contract) chapter).

### Resolution by off-chain clients with view support (recommended)

Clients that have the ability to invoke [TZIP-16](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-16/tzip-16.md) views should use the following to resolve names and addresses.

#### View: resolve-name

Resolves a name to an address, optionally [other domain data](/design-document/domain-data), and expiry information for reference. If no such record exists or it has expired, it returns `None`.

Before passing a name for resolution, it should first be normalized using the [encode algorithm](/interoperability/name-resolution#name-validation-and-normalization).

| Parameter Type | Description                        |
| -------------- | ---------------------------------- |
| `bytes`        | The UTF-8 encoded name to resolve. |

#### View: resolve-address

Resolves an address to a name, optionally [other domain data](/design-document/domain-data), and expiry information for reference. If no such record exists or it has expired, it returns `None`.

| Parameter Type | Description             |
| -------------- | ----------------------- |
| `address`      | The address to resolve. |

#### **Return type**

The return type for both `resolve-name` and `resolve-address` is as follows:

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type resolved_domain = [@layout:comb] {
    // The name of the resolved domain
    name: bytes;

    // The address of the resolved domain, if any
    address: address option;

    // A map of any additional data users wish to store with the domain
    data: data_map;

    // The expiration date of the domain, if any.
    // It is already
    expiry: timestamp option;
}

type return_type = resolved_domain option;
```

{% endtab %}
{% endtabs %}

### Instructions for Off-chain Clients lacking view support

Clients that lack TZIP-16 view support can read from the contract storage directly. The `NameRegistry` contract has the following storage structure:

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
(* data map with all possible types that can be stored with an entity *)
type data_map = (string, bytes) map

type record = {
    (* The optional address the record resolves to *)
    address: address option;

    (* The owner of the record allowed to make changes *)
    owner: address;

    (* A map of any additional data clients wish to store with the domain *)
    data: data_map

    (* Validator contract reference used for validating names of new subrecords *)
    validator: nat option;

    (* Key to the expiry map containing the validity of this record *)
    expiry_key: bytes option

    (* ... more fields outside of this interoperability spec *)
}

type reverse_record = {
    (* UTF-8 encoded name *)
    name: bytes option;
    
    (* The owner of the record allowed to make changes *)
    owner: address;

    (* A map of any additional data clients wish to store with the record *)
    data: data_map;
    
    (* ... more fields outside of this interoperability spec *)
}

type storage = {
    (* Map of UTF-8 encoded names to forward records *)
    records: (bytes, record) big_map;

    (* Map of addresses to reverse records *)
    reverse_records: (address, reverse_record) big_map;

    (* Map containing expiry for every second-level domain *)
    expiry_map: (bytes, timestamp) big_map;

    (* ... more fields outside of this interoperability spec *)
}

type main_storage = {
    (* Inner storage of the contract *)
    storage: storage;

    (* ... more fields outside of this interoperability spec *)
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Clients **must not** rely on a particular storage or record layout. They should always use annotations to find the correct value.
{% endhint %}

#### Forward Resolution (name to address)

The resolution algorithm is as follows:

1. Normalize and validate the full domain name using the encode algorithm. See the section [Name Validation and Normalization](/interoperability/name-resolution#name-encode-algorithm) for more details.
2. Look up the name in the `records` bigmap. If the bigmap contains no such key, the given domain is not resolvable.
3. Use the `expiry_key` value of the record to look up the validity in the `expiry_map`. If a timestamp is found and is lower or equal to the current time, the given domain is not resolvable.
4. Extract the optional `address` value from the record. If the optional value is `None`, the given domain is not resolvable. Otherwise use the `address` value.

#### Reverse Resolution (address to name)

The resolution algorithm is as follows:

1. Look up the address in the `reverse_records` bigmap. If the bigmap contains no such key, the given address is not resolvable.
2. Extract the optional `name` value. If the optional value is `None`, the given address is not resolvable.&#x20;
3. Use the `name` value to look up the corresponding forward record.  Use it's `expiry_key` value to look up the validity of the record in the `expiry_map`. If a timestamp is found and is lower or equal to the current timestamp, the given address is not resolvable
4. Otherwise, use the `name` value.

### Instructions for Contracts

**The resolution of names by contracts is currently not supported.** Sometimes, it can be useful to validate on-chain that a name corresponds to an address. For example, a wallet might group a transaction sending money with another transaction that performs this check. If the check fails, both transactions fail and no money changes hands.

Both on-chain and off-chain clients can do this by calling the `check_address` entry-point on `NameRegistry.CheckAddress`.&#x20;

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type check_address_param = [@layout:comb] {
    (* UTF-8 encoded name *)
    name: bytes;

    (* expected address *)
    address: address
}

(* Checks that a name corresponds to an address. *)
| Check_address of check_address_param
```

{% endtab %}

{% tab title="Michelson" %}

```
parameter (or
    (pair %check_address (bytes %name) (address %address)
    # ... more entrypoints outside of this interoperability spec
);
```

{% endtab %}
{% endtabs %}

The transaction will either do nothing (if the address is indeed correct) or fail with the message `NAME_ADDRESS_MISMATCH` if the address is incorrect.

## Name Validation and Normalization

Domain names generally have to conform to the [IDNA 2008](https://en.wikipedia.org/wiki/Internationalized_domain_name) mechanism (RFC 5891, 5892, 5893). The Unicode Standard [UTS 46](https://www.unicode.org/reports/tr46/) is a more specific (and stricter) application standard which is to be used for validation and normalization of domain names to achieve IDNA conformance.

### Length Limit

The length limitations are currently:

* 1 to 100 **characters** in a **single label**,
* up to 400 **bytes** in a **full domain name**.

It is not necessary for clients to check length when performing lookup or reverse lookup, as the names are already validated on-chain. It is however strongly recommended to do so when creating new records to avoid transaction failures.

### Name Encode Algorithm

This algorithm is used both for domain creation and lookup purposes when communicating with contracts. It permits the dot character (`.`) so it can be used both for encoding names and individual labels.

1. The [ToUnicode](https://www.unicode.org/reports/tr46/#ToUnicode) algorithm is used to produce a normalized and validated name string. The UTS 46 version of `ToUnicode` validates the string, making it notably different from `ToUnicode` defined in IDNA, which does not have to fail on invalid labels. The algorithm is invoked with the following parameters:
   * **CheckHyphens** = true
   * **CheckBidi** = true
   * **CheckJoiners** = true
   * **UseSTD3ASCIIRules** = true
   * **Transitional\_Processing** = false
2. The name or label is encoded using UTF-8 into `bytes`.

### Libraries

Some implementations of UTS 46 include:

* [idna-uts46-hx](https://github.com/hexonet/idna-uts46) for JavaScript
* [idna](https://pypi.org/project/idna/) for Python

Libraries that implement IDNA but not UTS 46 can alternatively be used. The string has to be first validated and normalized using `ToAscii` and the result converted back with `ToUnicode`. Some implementations of IDNA (that don't include validation and normalization as part of the `ToUnicode` algorithm and have to be called using `ToUnicode(ToAscii(name))`):

* [System.Globalization.IdnMapping](https://docs.microsoft.com/en-us/dotnet/api/system.globalization.idnmapping) in .NET
* [idna](https://docs.rs/idna/0.2.0/idna/) for Rust
* [java.net.IDN](https://docs.oracle.com/javase/8/docs/api/java/net/IDN.html) in Java (only implements IDNA 2003)


# Buys & Renewals

### Contract: TLDRegistrar.Commit

Creates a commitment to buy a second-level domain without disclosing the actual name. This is implemented according to our [commit\&reveal](https://en.wikipedia.org/wiki/Commitment_scheme) scheme.

**Entrypoint**: `commit`

| Parameter Type | Description                                                                                                                                                                                                                                                                                                                                              |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bytes`        | SHA-512 hash of a packed tuple of **label**, **owner**, and a **random nonce** corresponding to the intended buy (see [TLDRegistrar.Buy](/interoperability/buys-and-renewals#contract-tldregistrar-buy)). The hashed tuple is of the Michelson type`pair (pair bytes address) nat`. Having a random nonce prevents susceptibility to dictionary attacks. |

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type commit_param = bytes

| Commit of bytes
```

{% endtab %}

{% tab title="Michelson" %}

```
parameter (or
  (bytes %commit)
  # ... more entrypoints outside of this interoperability spec
);
```

{% endtab %}
{% endtabs %}

| Error              | Description                                                                     |
| ------------------ | ------------------------------------------------------------------------------- |
| AMOUNT\_NOT\_ZERO  | The transferred **amount** of *tez* is not zero.                                |
| COMMITMENT\_EXISTS | The given commitment exists. A commitment with a new nonce has to be generated. |

### Contract: TLDRegistrar.Buy

Buys a second-level domain based on previous commitment (see [TLDRegistrar.Commit](/interoperability/buys-and-renewals#contract-tldregistrar-commit)).

**Entrypoint**: `buy`

**Amount restriction**: The amount sent with this call has to be equal to the price of the domain. The price in mutez is calculated as `standard_price_per_day * duration / 1000000`.

| Parameter    | Type                  | Description                                                               |
| ------------ | --------------------- | ------------------------------------------------------------------------- |
| **label**    | `bytes`               | The UTF-8 encoded label of the second-level domain to buy.                |
| **duration** | `nat`                 | Ownership duration represented in days.                                   |
| **owner**    | `address`             | The new owner of the given domain.                                        |
| **address**  | `address option`      | The optional address the given domain resolves to.                        |
| **data**     | `(string, bytes) map` | A map of any additional data clients wish to store with the given domain. |
| **nonce**    | `nat`                 | The chosen commitment nonce.                                              |

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type buy_param = {
    label: bytes;
    duration: nat;
    owner: address;
    address: address option;
    data: (string, bytes) map;
    nonce: nat;
}

| Buy of buy_param michelson_pair_left_comb
```

{% endtab %}

{% tab title="Michelson" %}

```
parameter (or
  (pair %buy (bytes %label)
    (pair (nat %duration)
      (pair (address %owner)
        (pair (option %address address)
          (pair (map %data string bytes) (nat %nonce))))))
  # ... more entrypoints outside of this interoperability spec
);
```

{% endtab %}
{% endtabs %}

| Error                        | Description                                                                                                                                    |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| COMMITMENT\_DOES\_NOT\_EXIST | Corresponding commitment (see [TLDRegistrar.Commit](/interoperability/buys-and-renewals#contract-tldregistrar-commit)) was not created before. |
| COMMITMENT\_TOO\_OLD         | The commitment is too old (older than configured age). Try recreating it again.                                                                |
| COMMITMENT\_TOO\_RECENT      | The commitment is too recent (younger than configured age). Wait for some time.                                                                |
| LABEL\_TAKEN                 | The requested **label** already exists and it is not expired.                                                                                  |
| LABEL\_NOT\_AVAILABLE        | The requested **label** is currently not available for registration.                                                                           |
| LABEL\_IN\_AUCTION           | The requested **label** is currently only available in auction.                                                                                |
| INVALID\_LABEL               | The given **label** is not valid. See [Label Validation](/interoperability/domain-operations#label-validation).                                |
| LABEL\_EMPTY                 | The given label is empty.                                                                                                                      |
| LABEL\_TOO\_LONG             | The label is too long.                                                                                                                         |
| NAME\_TOO\_LONG              | The name (label + parent) is too long.                                                                                                         |
| DURATION\_TOO\_LOW           | The requested **duration** is too low (lower than the configured minimum).                                                                     |
| AMOUNT\_TOO\_LOW             | The transferred **amount** is lower than the actual price.                                                                                     |
| AMOUNT\_TOO\_HIGH            | The transferred **amount** is higher than the actual price.                                                                                    |

### Contract: TLDRegistrar.Renew

Renews second-level domain for requested duration.

**Entrypoint**: `renew`

**Amount restriction**: The amount sent with this call has to be equal to the price of the domain. The price in mutez is calculated as `standard_price_per_day * duration / 1000000`.

| Parameter    | Type    | Description                                                |
| ------------ | ------- | ---------------------------------------------------------- |
| **label**    | `bytes` | The UTF-8 encoded label of the second-level domain to buy. |
| **duration** | `nat`   | The renewal duration represented in days.                  |

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type renew_param = {
    label: bytes;
    duration: nat;
}

| Renew of renew_param michelson_pair_left_comb
```

{% endtab %}

{% tab title="Michelson" %}

```
parameter (or
  (pair %renew
    (bytes %label)
    (nat %duration))
  # ... more entrypoints outside of this interoperability spec
);
```

{% endtab %}
{% endtabs %}

| Error              | Description                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------ |
| LABEL\_NOT\_FOUND  | The requested **label** does not exist.                                                    |
| LABEL\_EXPIRED     | The requested **label** exists but it is expired. Therefore it can be bought, not renewed. |
| DURATION\_TOO\_LOW | The specified **duration** is too low (lower than the configured minimum).                 |
| AMOUNT\_TOO\_LOW   | The transferred **amount** is lower than the actual price.                                 |
| AMOUNT\_TOO\_HIGH  | The transferred **amount** is higher than the actual price.                                |


# Auction Operations

### Contract: TLDRegistrar.Bid

Places a new highest bid on a domain that is currently [in auction](/design-document/top-level-domain-registrar#open-auction). The bid will record the indicated amount and the sender as the new highest bidder. The bid amount has to be higher than `round_to_nearest_tenth(previous_highest_bid * (100 + min_bid_increase_ratio) / 100)`.

Additionally:

* If there is a previous highest bid, it is replaced and its amount is credited to the previous highest bidder.
* Any excess amount sent with the bid is credited to the sender.
* If the current auction end is lower than `NOW + bid_additional_period`, it is updated to `NOW + bid_additional_period`.

**Entrypoint**: `bid`

**Amount restriction**: The amount sent in this transaction plus the in-contract balance of the sender has to be higher or equal to the bid amount.

| Parameter | Type    | Description                                 |
| --------- | ------- | ------------------------------------------- |
| **label** | `bytes` | The UTF-8 encoded label the bid relates to. |
| **bid**   | `tez`   | Ownership duration represented in days.     |

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type bid_param = [@layout:comb] {
    label: bytes;
    bid: tez;
}

| Bid of bid_param
```

{% endtab %}
{% endtabs %}

| Error                 | Description                                                                                                     |
| --------------------- | --------------------------------------------------------------------------------------------------------------- |
| AUCTION\_ENDED        | The auction has already ended.                                                                                  |
| LABEL\_TAKEN          | The requested **label** already exists and it is not expired.                                                   |
| LABEL\_NOT\_AVAILABLE | The requested **label** is currently not available for registration.                                            |
| INVALID\_LABEL        | The given **label** is not valid. See [Label Validation](/interoperability/domain-operations#label-validation). |
| LABEL\_EMPTY          | The given label is empty.                                                                                       |
| LABEL\_TOO\_LONG      | The label is too long.                                                                                          |
| NAME\_TOO\_LONG       | The name (label + parent) is too long.                                                                          |
| BID\_TOO\_LOW         | The bid amount does not meet the requirement for a new highest bid.                                             |
| AMOUNT\_TOO\_LOW      | The amount sent (plus the in-contract balance) does not cover the bid.                                          |

### Contract: TLDRegistrar.Settle

Settles an auction that has ended. Removes the auction record and assigns the domain to the new owner. This call can only be made by the auction's highest bidder.&#x20;

The settlement period must not be expired, i.e. this call will only succeed during the period of `min_duration` days after an auction end.

**Entrypoint**: `settle`

| Parameter   | Type                  | Description                                                               |
| ----------- | --------------------- | ------------------------------------------------------------------------- |
| **label**   | `bytes`               | The UTF-8 encoded label of the second-level domain to buy.                |
| **owner**   | `address`             | The new owner of the given domain.                                        |
| **address** | `address option`      | The optional address the given domain resolves to.                        |
| **data**    | `(string, bytes) map` | A map of any additional data clients wish to store with the given domain. |

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type settle_param = [@layout:comb] {
    label: bytes;
    owner: address;
    address: address option;
    data: data_map;
}

| Settle of settle_param
```

{% endtab %}
{% endtabs %}

| Error                 | Description                                                          |
| --------------------- | -------------------------------------------------------------------- |
| LABEL\_TAKEN          | The requested **label** already exists and it is not expired.        |
| LABEL\_NOT\_AVAILABLE | The requested **label** is currently not available for registration. |
| NOT\_SETTLEABLE       | The settlement period is over or there is no such auction.           |
| NOT\_AUTHORIZED       | The call has not been made by the auction's highest bidder.          |
| AMOUNT\_NOT\_ZERO     | The transferred **amount** of *tez* is not zero.                     |

### Contract: TLDRegistrar.Withdraw

Makes a withdrawal of the caller's full in-contract balance. If the caller has no in-contract balance, the operation does nothing.

**Entrypoint**: `withdraw`

| Type      | Description                                         |
| --------- | --------------------------------------------------- |
| `address` | The address the caller's balance should be sent to. |

{% tabs %}
{% tab title="CamelLIGO" %}

```ocaml
type withdraw_param = address

| Widthdraw of withdraw_param
```

{% endtab %}
{% endtabs %}

| Error              | Description                                      |
| ------------------ | ------------------------------------------------ |
| INVALID\_RECIPIENT | The recipient address is invalid.                |
| AMOUNT\_NOT\_ZERO  | The transferred **amount** of *tez* is not zero. |


# Domain Operations

### Contract: NameRegistry.CheckAddress

Checks that there is a valid domain record with the specified **name** and the **address**.

**Entrypoint**: `check_address`

| Parameter   | Type      | Description                      |
| ----------- | --------- | -------------------------------- |
| **name**    | `bytes`   | The UTF-8 encoded name to check. |
| **address** | `address` | The expected address.            |

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type check_address_param = [@layout:comb] {
    name: bytes;
    address: address
}

(* Checks that a name corresponds to an address. *)
| Check_address of check_address_param
```

{% endtab %}

{% tab title="Michelson" %}

```
parameter (or
  (pair %check_address
    (bytes %name)
    (address %address)
  # ... more entrypoints outside of this interoperability spec
);
```

{% endtab %}
{% endtabs %}

| Error                   | Description                                                                                                                   |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| AMOUNT\_NOT\_ZERO       | The transferred **amount** of *tez* is not zero.                                                                              |
| NAME\_ADDRESS\_MISMATCH | There is no valid domain record with the specified **name** or it resolves to an **address** different from the expected one. |

### Contract: NameRegistry.ClaimReverseRecord

Claims a reverse record corresponding to a domain (a forward record). The claimed reverse record will map the **sender**'s address to the specified domain **name**.

**Entrypoint**: `claim_reverse_record`

| Parameter | Type      | Description                                      |
| --------- | --------- | ------------------------------------------------ |
| **name**  | `bytes`   | The UTF-8 encoded name to claim.                 |
| **owner** | `address` | The owner of the record allowed to make changes. |

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type claim_reverse_record_param = [@layout:comb] {
    name: bytes option;
    owner: address;
}

| Claim_reverse_record of claim_reverse_record_param
```

{% endtab %}
{% endtabs %}

| Error                   | Description                                                                                                                     |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| AMOUNT\_NOT\_ZERO       | The transferred **amount** of *tez* is not zero.                                                                                |
| NAME\_ADDRESS\_MISMATCH | There is no domain record with the specified **name** or it resolves to an **address** different from the **sender**'s address. |

### Contract: NameRegistry.SetChildRecord

Creates or overwrites an existing domain record. The current **sender** must be the owner of the **parent** record.

If there was an existing corresponding reverse record referencing this domain and the address of this domain changed, the reverse record's name will be updated to `None` to preserve consistency.

**Entrypoint**: `set_child_record`

| Parameter   | Type                  | Description                                                                                                                            |
| ----------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **label**   | `bytes`               | The UTF-8 encoded label.                                                                                                               |
| **parent**  | `bytes`               | The UTF-8 encoded parent domain.                                                                                                       |
| **address** | `address option`      | The optional address the record resolves to.                                                                                           |
| **owner**   | `address`             | The owner of the record allowed to make changes.                                                                                       |
| **data**    | `(string, bytes) map` | A map of any additional data clients wish to store with the domain.                                                                    |
| **expiry**  | `timestamp option`    | The expiry of this record. Only applicable to second-level domains as all higher-level domains share the expiry of their ancestor 2LD. |

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type set_child_record_param = [@layout:comb] {
    label: bytes;
    parent: bytes;
    address: address option;
    owner: address;
    data: (string, bytes) map;
    expiry: timestamp option;
}

| Set_child_record of set_child_record_param
```

{% endtab %}
{% endtabs %}

| Error              | Description                                                                                                    |
| ------------------ | -------------------------------------------------------------------------------------------------------------- |
| AMOUNT\_NOT\_ZERO  | The transferred **amount** of *tez* is not zero.                                                               |
| PARENT\_NOT\_FOUND | There is no record for the specified **parent** domain.                                                        |
| NOT\_AUTHORIZED    | The current **sender** is not the current record owner.                                                        |
| INVALID\_LABEL     | The given **label** is not valid. See [Label Validation](/interoperability/.tez-tld#label-validation-for-tez). |
| LABEL\_EMPTY       | The given label is empty.                                                                                      |
| LABEL\_TOO\_LONG   | The label is too long.                                                                                         |
| NAME\_TOO\_LONG    | The name (label + parent) is too long.                                                                         |

### Contract: NameRegistry.UpdateRecord

Updates an existing domain record. The current **sender** must be its owner.

If there was an existing corresponding reverse record referencing this domain and the address of this domain changed, the reverse record's name will be updated to `None` to preserve consistency.

**Entrypoint**: `update_record`

| Parameter   | Type                  | Description                                                                    |
| ----------- | --------------------- | ------------------------------------------------------------------------------ |
| **name**    | `bytes`               | The UTF-8 encoded name of the domain to update.                                |
| **address** | `address option`      | The optional new address the record resolves to.                               |
| **owner**   | `address`             | The new owner of the record allowed to make changes.                           |
| **data**    | `(string, bytes) map` | The new map of any additional data that clients wish to store with the domain. |

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type update_record_param = [@layout:comb] {
    name: bytes;
    address: address option;
    owner: address;
    data: (string, bytes) map;
}

| Update_record of update_record_param
```

{% endtab %}
{% endtabs %}

| Error              | Description                                             |
| ------------------ | ------------------------------------------------------- |
| AMOUNT\_NOT\_ZERO  | The transferred **amount** of *tez* is not zero.        |
| RECORD\_NOT\_FOUND | There is no domain record for the specified **name**.   |
| NOT\_AUTHORIZED    | The current **sender** is not the current record owner. |

### Contract: NameRegistry.UpdateReverseRecord

Updates an existing reverse record. The current **sender** must be its owner. There must be a corresponding domain record.

**Entrypoint**: `claim_reverse_record`

| Parameter   | Type           | Description                                        |
| ----------- | -------------- | -------------------------------------------------- |
| **address** | `address`      | The address of the reverse record to update.       |
| **name**    | `bytes option` | The new UTF-8 encoded name the record resolves to. |
| **owner**   | `address`      | The owner of the record allowed to make changes.   |

{% tabs %}
{% tab title="CameLIGO" %}

```ocaml
type update_reverse_record_param = [@layout:comb] {
    address: address;
    name: bytes option;
    owner: address;
}

| Update_reverse_record of update_reverse_record_param
```

{% endtab %}
{% endtabs %}

| Error                   | Description                                                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| AMOUNT\_NOT\_ZERO       | The transferred **amount** of *tez* is not zero.                                                                                                   |
| RECORD\_NOT\_FOUND      | There is no reverse record with the specified **address**.                                                                                         |
| NOT\_AUTHORIZED         | The current **sender** is not the current record owner.                                                                                            |
| NAME\_ADDRESS\_MISMATCH | There is no domain record with the specified **name** or it resolves to a different **address**. This can occur only if the **name** is specified. |


# .tez TLD

Currently, the only supported top-level domain is `.tez`. On testnets, it's always named after the name of the protocol (e.g. `.delphi`, `.edo`, etc.) to avoid potential confusion between a testnet and the mainnet. You can find the corresponding TLDRegistrar addresses in the Deployed Contracts section.

### Label Validation for .tez

In addition to the rules specified in [Name Validation and Normalization](/interoperability/name-resolution#name-validation-and-normalization), the top-level domain requires all labels to only contain the Latin characters `a-z`, `0-9`, and hyphens (`-`). Hyphens cannot appear as the first or the last character.


# Domains as NFTs

The `NameRegistry` is an FA2-compliant smart contract ([TZIP-12](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-12/tzip-12.md)). All 2nd-level domains can be used as non-fungible tokens, with a few caveats:

* After a domain expires, the owner's balance of the token is always `0`. That means that a domain will "disappear" as a token once it expires (although the `token_id` continues to be valid).
* We don't implement the optional `all_tokens` view, because the number of tokens is too large to be returned in one call.
* When a domain changes owners, all existing operators are automatically dropped.

See the [TZIP-12](https://gitlab.com/tzip/tzip/-/blob/master/proposals/tzip-12/tzip-12.md) specification for more information about the FA2 standard.


# Affiliated Buys & Renewals

Tezos Domains introduces an affiliate model that allows partners to offer domain purchases directly through their own apps. Affiliates earn a percentage with each tracked sale. This model is ideal for integration into wallets, marketplaces, and explorers, though any Tezos project can become an affiliate partner. To join the program, please follow the steps on [Tezos Domains Forum](https://talk.tezos.domains/t/registration-verification-for-the-tezos-domains-affiliate-program/317).

Affiliate purchases are tracked using a dedicated smart contract. This contract extends the standard [buy and renewal](/interoperability/buys-and-renewals) entrypoints by including an additional `affiliate` parameter, which identifies the affiliate partner by their Tezos address. You can find the mainnet address in our [deployed contracts list](/deployed-contracts/mainnet).

## Contract: AffiliateBuyRenew

### Entrypoint: buy

Buys a second-level domain based on previous commitment (see [TLDRegistrar.Commit](/interoperability/buys-and-renewals#contract-tldregistrar-commit)).

**Amount restriction**: The amount sent with this call has to be equal to the price of the domain. The price in mutez is calculated as `standard_price_per_day * duration / 1000000`.

| Parameter     | Type                  | Description                                                               |
| ------------- | --------------------- | ------------------------------------------------------------------------- |
| **label**     | `bytes`               | The UTF-8 encoded label of the second-level domain to buy.                |
| **duration**  | `nat`                 | Ownership duration represented in days.                                   |
| **owner**     | `address`             | The new owner of the given domain.                                        |
| **address**   | `address option`      | The optional address the given domain resolves to.                        |
| **data**      | `(string, bytes) map` | A map of any additional data clients wish to store with the given domain. |
| **nonce**     | `nat`                 | The chosen commitment nonce.                                              |
| **affiliate** | `address`             | Address uniquely identifying the affiliate.                               |

**Errors:**

| Error                        | Description                                                                                                                                    |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| COMMITMENT\_DOES\_NOT\_EXIST | Corresponding commitment (see [TLDRegistrar.Commit](/interoperability/buys-and-renewals#contract-tldregistrar-commit)) was not created before. |
| COMMITMENT\_TOO\_OLD         | The commitment is too old (older than configured age). Try recreating it again.                                                                |
| COMMITMENT\_TOO\_RECENT      | The commitment is too recent (younger than configured age). Wait for some time.                                                                |
| LABEL\_TAKEN                 | The requested **label** already exists and it is not expired.                                                                                  |
| LABEL\_NOT\_AVAILABLE        | The requested **label** is currently not available for registration.                                                                           |
| LABEL\_IN\_AUCTION           | The requested **label** is currently only available in auction.                                                                                |
| INVALID\_LABEL               | The given **label** is not valid. See [Label Validation](/interoperability/domain-operations#label-validation).                                |
| LABEL\_EMPTY                 | The given label is empty.                                                                                                                      |
| LABEL\_TOO\_LONG             | The label is too long.                                                                                                                         |
| NAME\_TOO\_LONG              | The name (label + parent) is too long.                                                                                                         |
| DURATION\_TOO\_LOW           | The requested **duration** is too low (lower than the configured minimum).                                                                     |
| AMOUNT\_TOO\_LOW             | The transferred **amount** is lower than the actual price.                                                                                     |
| AMOUNT\_TOO\_HIGH            | The transferred **amount** is higher than the actual price.                                                                                    |

### Entrypoint: renew

Renews second-level domain for requested duration.

**Amount restriction**: The amount sent with this call has to be equal to the price of the domain. The price in mutez is calculated as `standard_price_per_day * duration / 1000000`.

| Parameter     | Type      | Description                                                |
| ------------- | --------- | ---------------------------------------------------------- |
| **label**     | `bytes`   | The UTF-8 encoded label of the second-level domain to buy. |
| **duration**  | `nat`     | The renewal duration represented in days.                  |
| **affiliate** | `address` | Address uniquely identifying the affiliate.                |

**Errors:**

| Error              | Description                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------ |
| LABEL\_NOT\_FOUND  | The requested **label** does not exist.                                                    |
| LABEL\_EXPIRED     | The requested **label** exists but it is expired. Therefore it can be bought, not renewed. |
| DURATION\_TOO\_LOW | The specified **duration** is too low (lower than the configured minimum).                 |
| AMOUNT\_TOO\_LOW   | The transferred **amount** is lower than the actual price.                                 |
| AMOUNT\_TOO\_HIGH  | The transferred **amount** is higher than the actual price.                                |


# Mainnet

The following table contains all contract addresses for Mainnet:

| Contract                             | Address                                      | BCD                                                                        |
| ------------------------------------ | -------------------------------------------- | -------------------------------------------------------------------------- |
| **NameRegistry.CheckAddress**        | `KT1F7JKNqwaoLzRsMio1MQC7zv3jG9dHcDdJ`       | [🔗](https://better-call.dev/mainnet/KT1F7JKNqwaoLzRsMio1MQC7zv3jG9dHcDdJ) |
| **NameRegistry.SetChildRecord**      | `KT1QHLk1EMUA8BPH3FvRUeUmbTspmAhb7kpd`       | [🔗](https://better-call.dev/mainnet/KT1QHLk1EMUA8BPH3FvRUeUmbTspmAhb7kpd) |
| **NameRegistry.UpdateRecord**        | `KT1H1MqmUM4aK9i1833EBmYCCEfkbt6ZdSBc`       | [🔗](https://better-call.dev/mainnet/KT1H1MqmUM4aK9i1833EBmYCCEfkbt6ZdSBc) |
| **NameRegistry.ClaimReverseRecord**  | `KT1TnTr6b2YxSx2xUQ8Vz3MoWy771ta66yGx`       | [🔗](https://better-call.dev/mainnet/KT1TnTr6b2YxSx2xUQ8Vz3MoWy771ta66yGx) |
| **NameRegistry.UpdateReverseRecord** | `KT1J9VpjiH5cmcsskNb8gEXpBtjD4zrAx4Vo`       | [🔗](https://better-call.dev/mainnet/KT1J9VpjiH5cmcsskNb8gEXpBtjD4zrAx4Vo) |
| **NameRegistry**                     | *resolve from **NameRegistry.CheckAddress*** | [🔗](https://better-call.dev/mainnet/KT1GBZmSxmnKJXGMdMLbugPfLyUPmuLSMwKS) |
| **TLDRegistrar.Buy**                 | `KT191reDVKrLxU9rjTSxg53wRqj6zh8pnHgr`       | [🔗](https://better-call.dev/mainnet/KT191reDVKrLxU9rjTSxg53wRqj6zh8pnHgr) |
| **TLDRegistrar.Renew**               | `KT1EVYBj3f1rZHNeUtq4ZvVxPTs77wuHwARU`       | [🔗](https://better-call.dev/mainnet/KT1EVYBj3f1rZHNeUtq4ZvVxPTs77wuHwARU) |
| **TLDRegistrar.Commit**              | `KT1P8n2qzJjwMPbHJfi4o8xu6Pe3gaU3u2A3`       | [🔗](https://better-call.dev/mainnet/KT1P8n2qzJjwMPbHJfi4o8xu6Pe3gaU3u2A3) |
| **TLDRegistrar.Bid**                 | `KT1CaSP4dn8wasbMsfdtGiCPgYFW7bvnPRRT`       | [🔗](https://better-call.dev/mainnet/KT1CaSP4dn8wasbMsfdtGiCPgYFW7bvnPRRT) |
| **TLDRegistrar.Withdraw**            | `KT1CfuAbJQbAGYcjKfvEvbtNUx45LY5hfTVR`       | [🔗](https://better-call.dev/mainnet/KT1CfuAbJQbAGYcjKfvEvbtNUx45LY5hfTVR) |
| **TLDRegistrar.Settle**              | `KT1MeFfi4TzSCc8CF9j3qq5mecTPdc6YVUPp`       | [🔗](https://better-call.dev/mainnet/KT1MeFfi4TzSCc8CF9j3qq5mecTPdc6YVUPp) |
| **TLDRegistrar**                     | *resolve from **TLDRegistrar.Buy***          | [🔗](https://better-call.dev/mainnet/KT1Mqx5meQbhufngJnUAGEGpa4ZRxhPSiCgB) |
| **TED Token**                        | `KT1GY5qCWwmESfTv9dgjYyTYs2T5XGDSvRp1`       | [🔗](https://better-call.dev/mainnet/KT1GY5qCWwmESfTv9dgjYyTYs2T5XGDSvRp1) |
| **TEDv Token**                       | `KT1R4KPQxpFHAkX8MKCFmdoiqTaNSSpnJXPL`       | [🔗](https://better-call.dev/mainnet/KT1R4KPQxpFHAkX8MKCFmdoiqTaNSSpnJXPL) |
| **Governance Pool**                  | `KT1Lu5om8u4ns2VWxcufgQRzjaLLhh3Qvf5B`       | [🔗](https://better-call.dev/mainnet/KT1Lu5om8u4ns2VWxcufgQRzjaLLhh3Qvf5B) |
| **Vesting Contract**                 | `KT1VxKQbYBVD8fSkqaewJGigL3tmcLWrsXcu`       | [🔗](https://better-call.dev/mainnet/KT1VxKQbYBVD8fSkqaewJGigL3tmcLWrsXcu) |
| **AffiliateBuyRenew**                | `KT1Hg3ymQBL5nfAbb1JZ8G8AGPZ4cpcko2H2`       | [🔗](https://better-call.dev/mainnet/KT1Hg3ymQBL5nfAbb1JZ8G8AGPZ4cpcko2H2) |


# Ghostnet

These contracts are deployed on Ghostnet and correspond to the [Ghostnet dApp instance](https://ghostnet.tezos.domains).

| Contract                             | Address                                      | BCD                                                                         |
| ------------------------------------ | -------------------------------------------- | --------------------------------------------------------------------------- |
| **NameRegistry.CheckAddress**        | `KT1B3j3At2XMF5P8bVoPD2WeJbZ9eaPiu3pD`       | [🔗](https://better-call.dev/ghostnet/KT1B3j3At2XMF5P8bVoPD2WeJbZ9eaPiu3pD) |
| **NameRegistry.SetChildRecord**      | `KT1HpddfW7rX5aT2cTdsDaQZnH46bU7jQSTU`       | [🔗](https://better-call.dev/ghostnet/KT1HpddfW7rX5aT2cTdsDaQZnH46bU7jQSTU) |
| **NameRegistry.UpdateRecord**        | `KT1Ln4t64RdCG1bK8zkH6Xi4nNQVxz7qNgyj`       | [🔗](https://better-call.dev/ghostnet/KT1Ln4t64RdCG1bK8zkH6Xi4nNQVxz7qNgyj) |
| **NameRegistry.ClaimReverseRecord**  | `KT1H19ouy5QwDBchKXcUw1QRFs5ZYyx1ezEJ`       | [🔗](https://better-call.dev/ghostnet/KT1H19ouy5QwDBchKXcUw1QRFs5ZYyx1ezEJ) |
| **NameRegistry.UpdateReverseRecord** | `KT1HDUc2xtPHqWQcjE1WuinTTHajXQN3asdk`       | [🔗](https://better-call.dev/ghostnet/KT1HDUc2xtPHqWQcjE1WuinTTHajXQN3asdk) |
| **NameRegistry**                     | *resolve from **NameRegistry.CheckAddress*** | [🔗](https://better-call.dev/ghostnet/KT1REqKBXwULnmU6RpZxnRBUgcBmESnXhCWs) |
| **TLDRegistrar.Buy**                 | `KT1Ks7BBTLLjD9PsdCboCL7fYEfq8z1mEvU1`       | [🔗](https://better-call.dev/ghostnet/KT1Ks7BBTLLjD9PsdCboCL7fYEfq8z1mEvU1) |
| **TLDRegistrar.Renew**               | `KT1Bv32pdMYmBJeMa2HsyUQZiC6FNj1dX6VR`       | [🔗](https://better-call.dev/ghostnet/KT1Bv32pdMYmBJeMa2HsyUQZiC6FNj1dX6VR) |
| **TLDRegistrar.Commit**              | `KT1PEnPDgGKyHvaGzWj6VJJYwobToiW2frff`       | [🔗](https://better-call.dev/ghostnet/KT1PEnPDgGKyHvaGzWj6VJJYwobToiW2frff) |
| **TLDRegistrar.Bid**                 | `KT1P3wdbusZK2sj16YXxRViezzWCPXpiE28P`       | [🔗](https://better-call.dev/ghostnet/KT1P3wdbusZK2sj16YXxRViezzWCPXpiE28P) |
| **TLDRegistrar.Withdraw**            | `KT1C7EF4c1pnPW9qcfNRiTPj5tBFMQJtvUhq`       | [🔗](https://better-call.dev/ghostnet/KT1C7EF4c1pnPW9qcfNRiTPj5tBFMQJtvUhq) |
| **TLDRegistrar.Settle**              | `KT1DMNPg3b3fJQpjXULcXjucEXfwq3zGTKGo`       | [🔗](https://better-call.dev/ghostnet/KT1DMNPg3b3fJQpjXULcXjucEXfwq3zGTKGo) |
| **TLDRegistrar**                     | *resolve from **TLDRegistrar.Buy***          | [🔗](https://better-call.dev/ghostnet/KT1UZmFPpSFWFkma6yGLTJVmkvUjxTaEqXqW) |
| **AffiliateBuyRenew**                | `KT1EPAzYSkjvnwWYKqER6ZXihV7pxu3s1jr3`       | [🔗](https://better-call.dev/ghostnet/KT1EPAzYSkjvnwWYKqER6ZXihV7pxu3s1jr3) |


