# Name Service

在web3系统中，地址通常作为用户的身份标识。然而地址的可读性比较差，拿以太坊上的地址为例，一串16进制的数字，长度为40。不便于作为社交应用的身份展示。

为此，我们提供一个Relation Name Service合约，将可读名称(比如 "relation.soul")解析为计算机可以识别的表示符。

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-79ca43b735ad75fb34f41f1ee791861bd5dc9880%2Fname-service.png?alt=media" alt=""><figcaption><p>图 5-2 Name Service 数据流</p></figcaption></figure>

同时，我们利用Arweave作为去中心化存储，实现身份属性的扩展，构建完整的profile。用户可以将个人的其他信息存储到Arweave，并在Name Service合约上存储Arweave交易哈希。

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-ab46e54fc96b8290c9cd2924875af3807d59143a%2Fprofile.png?alt=media" alt=""><figcaption><p>图 5-3 Profile 数据流</p></figcaption></figure>

Relation Name Service是Relation Protocol中的重要对象，RNS自身是一个SBT，该SBT允许让你控制你在Relation网络中的基础社交身份数据。

Name Service SBT被个人地址拥有，它包含以下两种状态：

* hold：hold状态下 ，Name Service SBT可以被转移，无法通过该名称搜索或查询到对应的地址。
* resolved：Name Service SBT的只有地址通过resolve动作将token与Soul绑定后，视为name与个人地址的绑定，此时，Name Service SBT与地址在社交网络中可以相互映射。resolved状态的Name Service SBT 不可被转移。

为了使社交图谱的推荐和查询可以得到唯一的结果，一个地址可以拥有多个Name Service SBT，但只能同时resolved一个。

## Schema

我们给出Relation Name Service的[schema](https://arweave.net/PsqAxxDYdxfk4iYa4UpPam5vm8XaEyKco3rzYwZJ_4E)。 schema以ttl文件的形式保存至Arweave，交易哈希将作为schemaURI，在初始化合约时传入，参数示例：

```
ar://PsqAxxDYdxfk4iYa4UpPam5vm8XaEyKco3rzYwZJ_4E
```

* schema 前缀列表

```
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表示接受和绑定域名解析的地址;

:Domain用于表示域名

* predicate

```
p:hold a rdf:Property ;
    rdfs:label "hold" ;
    rdfs:comment "A Soul to own a name." ;
    rdfs:domain :Soul ;
    rdfs:range :Name .

p:resolved a rdf:Property ;
    rdfs:label "resolved" ;
    rdfs:comment "The resolved name of a soul." ;
    rdfs:domain :Soul ;
    rdfs:range :Name .

p:profileURI a rdf:Property ;
    rdfs:label "profileURI" ;
    rdfs:comment "The profileURI of a soul." ;
    rdfs:domain :Soul ;
    rdfs:range xsd:string .
```

p:hold表示地址持有域名，并未解析

p:resolved表示地址已经与域名建立联系，可通过域名解析出地址。

p:profileURI 表示用户的profileURI

## 合约

### 合约接口

Name Service的合约接口如下：

```solidity
interface INameService is ISemanticSBT {
    
    /**
     * 注册一个域名
     * @param owner 域名的owner
     * @param name 需要注册的域名
     * @param reverseRecord 是否设置解析记录
     * @returns tokenId
     */
    function register(address owner, string calldata name, bool reverseRecord) external returns (uint);

    /**
     * 设置解析记录，将域名跟地址建立关系
     * @param addr 域名的owner，如果owner为0地址，则认为是解绑关系
     * @param name 域名
     */
    function setNameForAddr(address addr, string calldata name) external;

    /**
     * 给调用者设置profileURI
     * @param profileURI arweave的交易哈希
     */
    function setProfileURI(string memory profileURI) external;

    /**
     * 解析域名
     * @param name 域名
     * @return addr 地址
     */
    function addr(string calldata name) virtual external view returns (address);

    /**
     * 反向解析
     * @param addr 地址
     * @return name 域名
     */
    function nameOf(address addr) external view returns (string memory);
 
    /**
     * 查询地址的profileURI
     * @param addr 地址
     * @return profileURI arweave的交易哈希
     */
    function profileURI(address addr) external view returns (string memory);
}

```

完整的合约代码可访问：

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

### 合约实现说明

我们对Name Service做了一些规则设置：

* 域名默认最小长度为3个字符
* 域名只有设置解析之后，才能被合约正确解析。设置解析有两个方式：
  * register时即设置解析
  * register之后，调用setNameForAddr设置解析
* 如果当前域名已经设置了解析，需要先解绑原地址，才能重新设置
* 合约默认transfer开关关闭，即所有token不能transfer。如果需要打开，可以调用setTransferable方法进行设置
* 只有没设置解析的token才能被transfer
