# Name Service

In Web3 systems, an address is used as a user's identity. However, addresses are difficult to recognize and remember. Take an address on the Ethereum blockchain for example, it is a heximal string with a length of 40 characters. It is not easy to recognize that in a social setting.

Therefore, we devised a Relation Name Service contract parsing readable names (eg. "relation.soul") as computer-readable identifiers.

<figure><img src="https://2101283974-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYeYon1a8IZta2Zm96hF1%2Fuploads%2Fgit-blob-79ca43b735ad75fb34f41f1ee791861bd5dc9880%2Fname-service.png?alt=media" alt=""><figcaption><p>Figure 5-2 Name Service data flow</p></figcaption></figure>

Meanwhile, we also use arweave, a decentralized storage system, to expand properties of an identity to build a comprehensive profile. Users can store other information in arweave and save the arweave transaction hash in the Name Service contract.

<figure><img src="https://2101283974-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYeYon1a8IZta2Zm96hF1%2Fuploads%2Fgit-blob-ab46e54fc96b8290c9cd2924875af3807d59143a%2Fprofile.png?alt=media" alt=""><figcaption><p>Figure 5-3 Profile data flow</p></figcaption></figure>

Relation Name Service, or RNS, is an important part of the Relation Protocol. RNS is a SBT itself, allowing users to control their own social identity data in the Relation network.

Name Service SBTs are owned by individual addresses. They have two status:

* hold: Under this status, a Name Service SBT can be transferred. But no one can search for it with its name or query its address.
* resolved: When an address undertakes a "resolve" action to bind the token with Soul, the Name Service SBT 's name will be bound to an address. It can not be transferred under this status.

To ensure a unique result for recommendation and searching by the social graph, an address can hold multiple Name Service SBTs, but it can only "Bound" one at the same time.

## Schema

The [schema](https://arweave.net/PsqAxxDYdxfk4iYa4UpPam5vm8XaEyKco3rzYwZJ_4E) corresponding to the Relation Name Service contract is saved to Arweave in the form of a ttl file, with the transaction hash as the schemaURI to be passed to the contract during its initialization stage. For example:

```
ar://PsqAxxDYdxfk4iYa4UpPam5vm8XaEyKco3rzYwZJ_4E
```

* The list of prefixes.

```
PREFIX : <http://relationlabs.ai/entity/>
PREFIX p: <http://relationlabs.ai/property/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
```

* Class

```
:Soul a rdfs:Class ;
    rdfs:label "soul" ;
    rdfs:comment "A soul" .

:Name a rdfs:Class ;
    rdfs:label "name" ;
    rdfs:comment "A name." .
```

":Soul" represents the address accepting and bounding names. ":Domain" represents a domain name.

* Predicate

```
p:hold a rdfs:Class ;
    rdfs:label "connectionAddress" ;
    rdfs:comment "A Soul to own a name." ;
    rdfs:range :Name .

p:resolved a rdfs:Class ;
    rdfs:label "connectionAddress" ;
    rdfs:comment "The resolved name of a soul." ;
    rdfs:range :Name .
    
p:profileURI a rdfs:Class ;
    rdfs:label "profileURI" ;
    rdfs:comment "The profileURI of a soul." ;
    rdfs:domain :Soul ;
    rdfs:range xsd:string .
```

"p:hold" means the address holds an address but has not yet resolved it. "p:resolved" means the address has linked with a domain name, thus one can resolve the address via the domain name."p:profileURI" means the profileURI of an address.

## Contract

#### The interface of the contract

The interface of the Name Service contract is as follows:

```solidity
interface INameService is ISemanticSBT {

    /**
     * To register a domain name
     * @param owner : The owner of a domain name
     * @param name : The domain name to be registered.
     * @param reverseRecord : Whether to set a record for resolving the domain name.
     * @returns tokenId
     */
    function register(address owner, string calldata name, bool reverseRecord) external returns (uint);

    /**
     * To set a record for resolving the domain name, linking the name to an address.
     * @param addr : The owner of the domain name. If the address is "0", then the link is canceled.
     * @param name : The domain name.
     */
    function setNameForAddr(address addr, string calldata name) external;

    /**
     * A profileURI set for the caller
     * @param profileURI : The transaction hash from arweave.
     */
    function setProfileURI(string memory profileURI) external;

    /**
     * To resolve a domain name.
     * @param name : The domain name.
     * @return addr : The address.
     */
    function addr(string calldata name) virtual external view returns (address);

    /**
     * Reverse mapping
     * @param addr : The address.
     * @return name : The domain name.
     */
    function nameOf(address addr) external view returns (string memory);

    /**
     * To query the profileURI of an address.
     * @param addr : The address.
     * @return profileURI : The transaction hash from arweave.
     */
    function profileURI(address addr) external view returns (string memory);
}

```

Full source code:

* [NameService](https://github.com/relationlabs/semanticSBT/blob/main/contracts/template/NameService.sol)

#### Contract implementation note:

We set a few rules for the Name Service:

* The shortest length for a domain name is 3 characters.
* A domain name can only be resolved properly by the contract after setting a resolve record. This can be done in two ways:
  * To set the record during "register".
  * To call the "setNameForAddr" method after "register"
* If the current domain name has set a resolve record, you need to unbound it from the previous address before you can resolve it to a new one.
* The contract disables "transfer" by default, effectively banning all token transfers. To turn on this option, you can call the "setTransferable" method.
* Only tokens without a current resolve record can be transferred.
