@@ -3,7 +3,9 @@ pragma solidity ^0.8.19;
3
3
4
4
import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol " ;
5
5
import { IERC721State , IERC721 , ERC721 , INSUnified, RNSToken } from "./RNSToken.sol " ;
6
+ import { Math } from "@openzeppelin/contracts/utils/math/Math.sol " ;
6
7
import { LibRNSDomain } from "./libraries/LibRNSDomain.sol " ;
8
+ import { LibString } from "./libraries/LibString.sol " ;
7
9
import { LibSafeRange } from "./libraries/math/LibSafeRange.sol " ;
8
10
import { ModifyingField, LibModifyingField } from "./libraries/LibModifyingField.sol " ;
9
11
import {
@@ -14,18 +16,24 @@ import {
14
16
} from "./types/ModifyingIndicator.sol " ;
15
17
16
18
contract RNSUnified is Initializable , RNSToken {
19
+ using LibString for string ;
17
20
using LibRNSDomain for string ;
18
21
using LibModifyingField for ModifyingField;
19
22
20
23
bytes32 public constant CONTROLLER_ROLE = keccak256 ("CONTROLLER_ROLE " );
21
24
bytes32 public constant RESERVATION_ROLE = keccak256 ("RESERVATION_ROLE " );
25
+ bytes32 public constant TIER_SETTLER_ROLE = keccak256 ("TIER_SETTLER_ROLE " );
22
26
bytes32 public constant PROTECTED_SETTLER_ROLE = keccak256 ("PROTECTED_SETTLER_ROLE " );
23
27
uint64 public constant MAX_EXPIRY = type (uint64 ).max;
28
+ uint8 public constant DEFAULT_MAX_TIER = 5 ;
24
29
25
30
/// @dev Gap for upgradeability.
26
31
uint256 [50 ] private ____gap;
27
32
33
+ /// @dev The grace period in second(s).
28
34
uint64 internal _gracePeriod;
35
+ /// @dev The maximum tier value.
36
+ uint8 internal _maxTier;
29
37
/// @dev Mapping from token id => record
30
38
mapping (uint256 => Record) internal _recordOf;
31
39
@@ -65,6 +73,11 @@ contract RNSUnified is Initializable, RNSToken {
65
73
return block .timestamp > LibSafeRange.add (_expiry (id), _gracePeriod);
66
74
}
67
75
76
+ /// @inheritdoc INSUnified
77
+ function getMaxTier () public view returns (uint8 ) {
78
+ return _maxTier == 0 ? DEFAULT_MAX_TIER : _maxTier;
79
+ }
80
+
68
81
/// @inheritdoc INSUnified
69
82
function getGracePeriod () external view returns (uint64 ) {
70
83
return _gracePeriod;
@@ -75,6 +88,11 @@ contract RNSUnified is Initializable, RNSToken {
75
88
_setGracePeriod (gracePeriod);
76
89
}
77
90
91
+ /// @inheritdoc INSUnified
92
+ function setMaxTier (uint8 maxTier ) external whenNotPaused onlyRole (TIER_SETTLER_ROLE) {
93
+ _setMaxTier (maxTier);
94
+ }
95
+
78
96
/// @inheritdoc INSUnified
79
97
function mint (uint256 parentId , string calldata label , address resolver , address owner , uint64 duration )
80
98
external
@@ -92,8 +110,13 @@ contract RNSUnified is Initializable, RNSToken {
92
110
_requireValidExpiry (parentId, expiryTime);
93
111
Record memory record;
94
112
// Preserve previous state of the protected field
95
- record.mut =
96
- MutableRecord ({ resolver: resolver, owner: owner, expiry: expiryTime, protected: _recordOf[id].mut.protected });
113
+ record.mut = MutableRecord ({
114
+ resolver: resolver,
115
+ owner: owner,
116
+ expiry: expiryTime,
117
+ protected: _recordOf[id].mut.protected,
118
+ tier: 0
119
+ });
97
120
record.immut = ImmutableRecord ({ depth: _recordOf[parentId].immut.depth + 1 , parentId: parentId, label: label });
98
121
// allow 3rd level domain for {account}.addr.reverse
99
122
if (parentId != LibRNSDomain.ADDR_REVERSE_ID && record.immut.depth >= 3 ) revert ThirdLevelDomainUnallowed ();
@@ -112,6 +135,7 @@ contract RNSUnified is Initializable, RNSToken {
112
135
record = _recordOf[id];
113
136
record.mut.owner = ownerOf (id);
114
137
record.mut.expiry = _expiry (id);
138
+ record.mut.tier = _tier (id);
115
139
}
116
140
117
141
/// @inheritdoc INSUnified
@@ -173,6 +197,28 @@ contract RNSUnified is Initializable, RNSToken {
173
197
}
174
198
}
175
199
200
+ /// @inheritdoc INSUnified
201
+ function bulkSetTier (uint256 [] calldata ids , uint8 [] calldata tiers ) external onlyRole (TIER_SETTLER_ROLE) {
202
+ uint256 id;
203
+ uint8 tier;
204
+ Record memory record;
205
+ uint256 maxTier = getMaxTier ();
206
+ ModifyingIndicator indicator = ModifyingField.Tier.indicator ();
207
+
208
+ for (uint256 i; i < ids.length ;) {
209
+ id = ids[i];
210
+ if (_tier (id) != (tier = tiers[i])) {
211
+ if (tier > maxTier) revert ExceedMaxTier ();
212
+ _recordOf[id].mut.tier = record.mut.tier = tier;
213
+ emit RecordUpdated (id, indicator, record);
214
+ }
215
+
216
+ unchecked {
217
+ ++ i;
218
+ }
219
+ }
220
+ }
221
+
176
222
/// @inheritdoc INSUnified
177
223
function setRecord (uint256 id , ModifyingIndicator indicator , MutableRecord calldata mutRecord )
178
224
external
@@ -191,6 +237,10 @@ contract RNSUnified is Initializable, RNSToken {
191
237
if (indicator.hasAny (ModifyingField.Resolver.indicator ())) {
192
238
sMutRecord.resolver = record.mut.resolver = mutRecord.resolver;
193
239
}
240
+ if (indicator.hasAny (ModifyingField.Tier.indicator ())) {
241
+ if (mutRecord.tier > getMaxTier ()) revert ExceedMaxTier ();
242
+ sMutRecord.tier = record.mut.tier = mutRecord.tier;
243
+ }
194
244
emit RecordUpdated (id, indicator, record);
195
245
196
246
// Updating owner might emit more {RecordUpdated} events. See method {_transfer}.
@@ -219,6 +269,9 @@ contract RNSUnified is Initializable, RNSToken {
219
269
if (indicator.hasAny (ModifyingField.Protected.indicator ()) && ! hasRole (PROTECTED_SETTLER_ROLE, requester)) {
220
270
return (false , MissingProtectedSettlerRole.selector );
221
271
}
272
+ if (indicator.hasAny (ModifyingField.Tier.indicator ()) && ! hasRole (TIER_SETTLER_ROLE, requester)) {
273
+ return (false , MissingTierSettlerRole.selector );
274
+ }
222
275
bool hasControllerRole = hasRole (CONTROLLER_ROLE, requester);
223
276
if (indicator.hasAny (ModifyingField.Expiry.indicator ()) && ! hasControllerRole) {
224
277
return (false , MissingControllerRole.selector );
@@ -257,6 +310,15 @@ contract RNSUnified is Initializable, RNSToken {
257
310
return _recordOf[id].mut.expiry;
258
311
}
259
312
313
+ /**
314
+ * @dev Helper method to get tier of a token.
315
+ */
316
+ function _tier (uint256 id ) internal view returns (uint8 tier ) {
317
+ Record storage $ = _recordOf[id];
318
+ tier = $.mut.tier;
319
+ if (tier == 0 ) tier = uint8 (Math.min ($.immut.label.strlen (), getMaxTier ()));
320
+ }
321
+
260
322
/**
261
323
* @dev Helper method to check whether the address is owner of parent token.
262
324
*/
@@ -328,6 +390,16 @@ contract RNSUnified is Initializable, RNSToken {
328
390
emit GracePeriodUpdated (_msgSender (), gracePeriod);
329
391
}
330
392
393
+ /**
394
+ * @dev Helper method to set maximum tier.
395
+ *
396
+ * Emits an event {MaxTierUpdated}.
397
+ */
398
+ function _setMaxTier (uint8 maxTier ) internal {
399
+ _maxTier = maxTier;
400
+ emit MaxTierUpdated (_msgSender (), maxTier);
401
+ }
402
+
331
403
/// @dev Override {ERC721-_transfer}.
332
404
function _transfer (address from , address to , uint256 id ) internal override {
333
405
super ._transfer (from, to, id);
0 commit comments