Skip to content

Commit 3f27810

Browse files
authored
Merge branch 'Dapp-Learning-DAO:main' into main
2 parents cce82d2 + a2442d1 commit 3f27810

11 files changed

+237
-2
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ DAPP架构请参考文章--[从架构维度看Web2.0与Web3.0应用之别](https
165165
58. [Ethereum Virtual Machine Opcodes](basic/58-EVM/readme.md)
166166
59. [web3.0 dapp](basic/59-web3-dapp)
167167
60. [Referral Code](https://developers.thundercore.com/docs/referral-contract/)
168-
61. [ENS](https://app.ens.domains/)
169-
63. [HTLC-crosschain](https://yuanxuxu.com/2020/08/05/%E5%8C%BA%E5%9D%97%E9%93%BE%E8%B7%A8%E9%93%BE%E6%8A%80%E6%9C%AF%E4%B9%8B%E5%93%88%E5%B8%8C%E6%97%B6%E9%97%B4%E9%94%81/)
168+
61. [ENS](https://app.ens.domains/)
169+
63. [HTLC-crosschain](https://yuanxuxu.com/2020/08/05/%E5%8C%BA%E5%9D%97%E9%93%BE%E8%B7%A8%E9%93%BE%E6%8A%80%E6%9C%AF%E4%B9%8B%E5%93%88%E5%B8%8C%E6%97%B6%E9%97%B4%E9%94%81/)
170170
64. [Web3-Rust](https://github.com/tomusdrw/rust-web3)
171171
65. [ZK-NFT](https://github.com/kevinz917/zk-NFT)
172172
66. [Kleros](https://kleros.io/)

basic/61-ENS/.gitignore

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
.env
3+
coverage
4+
coverage.json
5+
typechain
6+
7+
#Hardhat files
8+
cache
9+
artifacts

basic/61-ENS/1-ENSRegistry.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# ENSRegistry.sol 合约介绍
2+
ENSRegistry 是 ENS 的主合约, 用于注册用户地址对应的域名
3+
4+
## 合约接口解析
5+
- construct
6+
在 constrcut 中设置根域名的拥有者为合约的部署者, 之后设置一级子域名的时候会校验调用者是否为根域名的拥有者
7+
```solidity
8+
constructor() public {
9+
records[0x0].owner = msg.sender;
10+
}
11+
```
12+
13+
- authorised
14+
authorised 修饰器确保只有对应域名的 owner 才能进行相应的操作
15+
```solidity
16+
modifier authorised(bytes32 node) {
17+
address owner = records[node].owner;
18+
require(owner == msg.sender || operators[owner][msg.sender]);
19+
_;
20+
}
21+
```
22+
23+
- setOwner
24+
转移域名的所有权, 转移时会校验被转移域名的所有者是否为当前的调用者
25+
```solidity
26+
function setOwner(bytes32 node, address owner) public virtual override authorised(node) {
27+
_setOwner(node, owner);
28+
emit Transfer(node, owner);
29+
}
30+
```
31+
32+
- setResolver
33+
设置域名的反相解析器, 此解析器可以用来反向解析域名 Hash 对应的可读域名, 比如 "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2" => 'addr.reverse'
34+
```solidity
35+
function setResolver(bytes32 node, address resolver) public virtual override authorised(node) {
36+
emit NewResolver(node, resolver);
37+
records[node].resolver = resolver;
38+
}
39+
```
40+
41+
- setTTL
42+
设置域名的过期时间, 时间单位为 秒, 比如设置 ttl 为 3600, 表示 1 个小时后此域名过期
43+
```solidity
44+
function setTTL(bytes32 node, uint64 ttl) public virtual override authorised(node) {
45+
emit NewTTL(node, ttl);
46+
records[node].ttl = ttl;
47+
}
48+
```
49+
50+
- setRecord
51+
设置域名的拥有者, 反向解析器地址, ttl 时间. 这个方法是在域名已经存在的情况后, 进行设置的
52+
```solidity
53+
function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external virtual override {
54+
setOwner(node, owner);
55+
_setResolverAndTTL(node, resolver, ttl);
56+
}
57+
```
58+
59+
- setSubnodeOwner
60+
设置子域名的拥有者, 所有一级域名及后续的子域名都需要通过这个接口进行设置
61+
```solidity
62+
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public virtual override authorised(node) returns(bytes32) {
63+
bytes32 subnode = keccak256(abi.encodePacked(node, label));
64+
_setOwner(subnode, owner);
65+
emit NewOwner(node, label, owner);
66+
return subnode;
67+
}
68+
````
69+
70+
71+
## 总结
72+
观察 ENSRegistry 的接口和内部变量, 可以看到合约中只处理了从 "node" => "owner address" 即域名到拥有者的映射, 但没有处理从 "owner address" => "node" 的映射.
73+
其实, 从 "owner address" => "node" 的映射可以通过 Graph 进行处理, 在 setOwner 接口中会出发 Transfer 事件, 而通过 Graph 的处理, 就可以得到 "owner address" => "node" 的映射关系.
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# ENSRegistryWithFallback.sol 合约介绍
2+
ENSRegistryWithFallback 同 ENSRegistry 功能相同, 唯一的区别是当对应的域名信息在当前合约中不存在时, 会去旧 ENS 合约中查找对应的数据
3+
4+
## 合约接口解析
5+
- construct
6+
在 constrcut 中设置旧 ENS 合约地址
7+
```solidity
8+
constructor(ENS _old) public ENSRegistry() {
9+
old = _old;
10+
}
11+
```
12+
13+
- resolver
14+
查找对应域名 Hash 对应的反向解析器, 如果当前 ENS 中没有查找到, 就在 old ENS 中查找
15+
```solidity
16+
function resolver(bytes32 node) public override view returns (address) {
17+
if (!recordExists(node)) {
18+
return old.resolver(node);
19+
}
20+
21+
return super.resolver(node);
22+
}
23+
```
24+
25+
- owner
26+
查找域名的所有者, 如果当前 ENS 中没有查找到, 就在 old ENS 中查找
27+
```solidity
28+
function owner(bytes32 node) public override view returns (address) {
29+
if (!recordExists(node)) {
30+
return old.owner(node);
31+
}
32+
33+
return super.owner(node);
34+
}
35+
```
36+
37+
- ttl
38+
查找域名的 TTL , 如果当前 ENS 中没有查找到, 就在 old ENS 中查找
39+
```solidity
40+
function ttl(bytes32 node) public override view returns (uint64) {
41+
if (!recordExists(node)) {
42+
return old.ttl(node);
43+
}
44+
45+
return super.ttl(node);
46+
}
47+
```

basic/61-ENS/3-FIFSRegistrar.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# FIFSRegistrar.sol 合约介绍
2+
FIFSRegistrar 是子域名注册器, 用户设置没有被注册的子域名, 或是更改已经注册的子域名 ( 属于调用者的子域名 )
3+
4+
## 合约接口解析
5+
- only_owner
6+
用户判断注册子域名的状态. 如果子域名没有被注册, 或是当前子域名属于调用者, 则允许调用; 负责不允许更改子域名状态
7+
```solidity
8+
modifier only_owner(bytes32 label) {
9+
address currentOwner = ens.owner(keccak256(abi.encodePacked(rootNode, label)));
10+
require(currentOwner == address(0x0) || currentOwner == msg.sender);
11+
_;
12+
}
13+
```
14+
15+
- constructor
16+
构造器中设置了 ENS 的地址和当前的父域名的 Hash
17+
```solidity
18+
constructor(ENS ensAddr, bytes32 node) public {
19+
ens = ensAddr;
20+
rootNode = node;
21+
}
22+
```
23+
24+
- register
25+
子域名注册接口, 调用者通过调用这个接口进行子域名注册.
26+
如果我们回到 ENS 合约中观察 ens.setSubnodeOwner 这个接口, 就会发现调用这个接口的时候, ENS 合约会检查 rootNode 域名对应的 owner 是否为调用者 ( 这里为 FIFSRegistrar 合约 ), 所以 ENS 一级域名 ( 如 .eth , .com 域名 ) 的所有者是当前 FIFSRegistrar 合约, 这样当 FIFSRegistrar 调用 ens.setSubnodeOwner 接口时, 就可以成功进行调用
27+
```solidity
28+
function register(bytes32 label, address owner) public only_owner(label) {
29+
ens.setSubnodeOwner(rootNode, label, owner);
30+
}
31+
}
32+
```
33+
34+
## 总结
35+
一般这个这个合约是给一级域名使用的, 对于用户说, 用户在获得对应的二级、 三级 域名后, 可以直接调用 ENS 接口进行相应的设置

basic/61-ENS/4-ReverseRegistrar.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ReverseRegistrar.sol 合约介绍
2+
ReverseRegistrar 反向域名解析器注册器, 用户注册反向域名解析器.
3+
反向域名解析器即把对应的域名 Hash 转换为可读域名 , 如 "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2" => 'addr.reverse'.
4+
在 ENS 合于中, 我们了解到可以通过查询 Graph 获取 "owner address" => "node Hash" 的映射, 但这里获取 "node Hash" 后,依然不是可读字符, 需要把它转换为可读字符.
5+
6+
## 合约接口解析
7+
- constructor
8+
在构造器中, 设置 ENS 地址和 反向域名解析器地址.
9+
在部署时, 如果叶子域名对应的所有者不是合约部署者, 则设置叶子域名的所有者为合约部署者.
10+
举例来说, 如果存在域名 .edu.eth , 那么用户 0x00123 在这个域名下的叶子域名为 0x00123.edu.eth , 那么设置 0x00123.edu.eth 域名的所有者为 0x00123
11+
```solidity
12+
constructor(ENS ensAddr, NameResolver resolverAddr) public {
13+
ens = ensAddr;
14+
defaultResolver = resolverAddr;
15+
16+
// Assign ownership of the reverse record to our deployer
17+
ReverseRegistrar oldRegistrar = ReverseRegistrar(ens.owner(ADDR_REVERSE_NODE));
18+
if (address(oldRegistrar) != address(0x0)) {
19+
oldRegistrar.claim(msg.sender);
20+
}
21+
}
22+
```
23+
24+
25+
- claim
26+
转移叶子域名的所有者到对应的用户.
27+
此接口主要在部署新 ReverseRegistrar 合约的时候, 调用旧 ReverseRegistrar 合约的 claim 时使用
28+
```solidity
29+
function claim(address owner) public returns (bytes32) {
30+
return claimWithResolver(owner, address(0x0));
31+
}
32+
```
33+
34+
- setName
35+
设置域名 Hash 的对应的可读字符, 比如 "0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2" => 'addr.reverse'
36+
```solidity
37+
function setName(string memory name) public returns (bytes32) {
38+
bytes32 node = claimWithResolver(address(this), address(defaultResolver));
39+
defaultResolver.setName(node, name);
40+
return node;
41+
}
42+
```
43+
44+
- claimWithResolver
45+
设置域名 Hash 的反向解析器,主要在两个接口中被调用.
46+
1) claim : 转移叶子域名的所有者到对应的用户. 调用时, resolver 为 0 地址, 此时不更新 resolver 地址, 只更新 owner 地址
47+
2) setName : owner 和 resolver 参数都不为 0 地址, 此时先更新叶子域名 ( 如 0x001234.edu.eth ) 的 owner 为当前合约. 注意, 这里更新 owner 的原因为在后续的 ens.setResolver(node, resolver) 中需要 owner 权限的地址才能调用, 所有这里需要先进行权限转移. 然后再调用 ens.setResolver(node, resolver) 进行解析器地址的更新.
48+
```solidity
49+
function claimWithResolver(address owner, address resolver) public returns (bytes32) {
50+
bytes32 label = sha3HexAddress(msg.sender);
51+
bytes32 node = keccak256(abi.encodePacked(ADDR_REVERSE_NODE, label));
52+
address currentOwner = ens.owner(node);
53+
54+
// Update the resolver if required
55+
if (resolver != address(0x0) && resolver != ens.resolver(node)) {
56+
// Transfer the name to us first if it's not already
57+
if (currentOwner != address(this)) {
58+
ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, address(this));
59+
currentOwner = address(this);
60+
}
61+
ens.setResolver(node, resolver);
62+
}
63+
64+
// Update the owner if required
65+
if (currentOwner != owner) {
66+
ens.setSubnodeOwner(ADDR_REVERSE_NODE, label, owner);
67+
}
68+
69+
return node;
70+
}
71+
```

0 commit comments

Comments
 (0)