-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBaseRegistrarImplementation.sol
161 lines (139 loc) · 6.46 KB
/
BaseRegistrarImplementation.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
pragma solidity >=0.8.4;
import "../registry/ENS.sol";
import "./IBaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract BaseRegistrarImplementation is ERC721, IBaseRegistrar, Ownable {
// A map of expiry times
mapping(uint256=>uint) expiries;
// The ENS registry
ENS public ens;
// The namehash of the TLD this registrar owns (eg, .eth)
bytes32 public baseNode;
// A map of addresses that are authorised to register and renew names.
mapping(address => bool) public controllers;
uint256 public constant GRACE_PERIOD = 90 days;
bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
bytes4 constant private ERC721_ID = bytes4(
keccak256("balanceOf(address)") ^
keccak256("ownerOf(uint256)") ^
keccak256("approve(address,uint256)") ^
keccak256("getApproved(uint256)") ^
keccak256("setApprovalForAll(address,bool)") ^
keccak256("isApprovedForAll(address,address)") ^
keccak256("transferFrom(address,address,uint256)") ^
keccak256("safeTransferFrom(address,address,uint256)") ^
keccak256("safeTransferFrom(address,address,uint256,bytes)")
);
bytes4 constant private RECLAIM_ID = bytes4(keccak256("reclaim(uint256,address)"));
/**
* v2.1.3 version of _isApprovedOrOwner which calls ownerOf(tokenId) and takes grace period into consideration instead of ERC721.ownerOf(tokenId);
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v2.1.3/contracts/token/ERC721/ERC721.sol#L187
* @dev Returns whether the given spender can transfer a given token ID
* @param spender address of the spender to query
* @param tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view override returns (bool) {
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
constructor(ENS _ens, bytes32 _baseNode) ERC721("","") {
ens = _ens;
baseNode = _baseNode;
}
modifier live {
require(ens.owner(baseNode) == address(this));
_;
}
modifier onlyController {
require(controllers[msg.sender]);
_;
}
/**
* @dev Gets the owner of the specified token ID. Names become unowned
* when their registration expires.
* @param tokenId uint256 ID of the token to query the owner of
* @return address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 tokenId) public view override(IERC721, ERC721) returns (address) {
require(expiries[tokenId] > block.timestamp);
return super.ownerOf(tokenId);
}
// Authorises a controller, who can register and renew domains.
function addController(address controller) external override onlyOwner {
controllers[controller] = true;
emit ControllerAdded(controller);
}
// Revoke controller permission for an address.
function removeController(address controller) external override onlyOwner {
controllers[controller] = false;
emit ControllerRemoved(controller);
}
// Set the resolver for the TLD this registrar manages.
function setResolver(address resolver) external override onlyOwner {
ens.setResolver(baseNode, resolver);
}
// Returns the expiration timestamp of the specified id.
function nameExpires(uint256 id) external view override returns(uint) {
return expiries[id];
}
// Returns true iff the specified name is available for registration.
function available(uint256 id) public view override returns(bool) {
// Not available if it's registered here or in its grace period.
return expiries[id] + GRACE_PERIOD < block.timestamp;
}
/**
* @dev Register a name.
* @param id The token ID (keccak256 of the label).
* @param owner The address that should own the registration.
* @param duration Duration in seconds for the registration.
*/
function register(uint256 id, address owner, uint duration) external override returns(uint) {
return _register(id, owner, duration, true);
}
/**
* @dev Register a name, without modifying the registry.
* @param id The token ID (keccak256 of the label).
* @param owner The address that should own the registration.
* @param duration Duration in seconds for the registration.
*/
function registerOnly(uint256 id, address owner, uint duration) external returns(uint) {
return _register(id, owner, duration, false);
}
function _register(uint256 id, address owner, uint duration, bool updateRegistry) internal live onlyController returns(uint) {
require(available(id));
require(block.timestamp + duration + GRACE_PERIOD > block.timestamp + GRACE_PERIOD); // Prevent future overflow
expiries[id] = block.timestamp + duration;
if(_exists(id)) {
// Name was previously owned, and expired
_burn(id);
}
_mint(owner, id);
if(updateRegistry) {
ens.setSubnodeOwner(baseNode, bytes32(id), owner);
}
emit NameRegistered(id, owner, block.timestamp + duration);
return block.timestamp + duration;
}
function renew(uint256 id, uint duration) external override live onlyController returns(uint) {
require(expiries[id] + GRACE_PERIOD >= block.timestamp); // Name must be registered here or in grace period
require(expiries[id] + duration + GRACE_PERIOD > duration + GRACE_PERIOD); // Prevent future overflow
expiries[id] += duration;
emit NameRenewed(id, expiries[id]);
return expiries[id];
}
/**
* @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
*/
function reclaim(uint256 id, address owner) external override live {
require(_isApprovedOrOwner(msg.sender, id));
ens.setSubnodeOwner(baseNode, bytes32(id), owner);
}
function supportsInterface(bytes4 interfaceID) public override(ERC721, IERC165) view returns (bool) {
return interfaceID == INTERFACE_META_ID ||
interfaceID == ERC721_ID ||
interfaceID == RECLAIM_ID;
}
}