@lukso/lsp8-contracts 0.16.5 → 0.17.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +55 -5
  3. package/artifacts/IAccessControlExtended.json +285 -0
  4. package/artifacts/ILSP8CappedBalance.json +27 -0
  5. package/artifacts/ILSP8CappedSupply.json +27 -0
  6. package/artifacts/ILSP8IdentifiableDigitalAsset.json +6 -3
  7. package/artifacts/ILSP8Mintable.json +62 -0
  8. package/artifacts/ILSP8NonTransferable.json +110 -0
  9. package/artifacts/ILSP8Revokable.json +75 -0
  10. package/artifacts/LSP8Burnable.json +7 -4
  11. package/artifacts/LSP8BurnableInitAbstract.json +7 -4
  12. package/artifacts/LSP8CappedBalanceAbstract.json +1285 -0
  13. package/artifacts/LSP8CappedBalanceInitAbstract.json +1293 -0
  14. package/artifacts/{LSP8CappedSupply.json → LSP8CappedSupplyAbstract.json} +8 -15
  15. package/artifacts/LSP8CappedSupplyInitAbstract.json +7 -14
  16. package/artifacts/LSP8CustomizableToken.json +1738 -0
  17. package/artifacts/LSP8CustomizableTokenInit.json +1733 -0
  18. package/artifacts/LSP8Enumerable.json +7 -4
  19. package/artifacts/LSP8EnumerableInitAbstract.json +7 -4
  20. package/artifacts/LSP8IdentifiableDigitalAsset.json +6 -3
  21. package/artifacts/LSP8IdentifiableDigitalAssetInitAbstract.json +6 -3
  22. package/artifacts/LSP8Mintable.json +369 -5
  23. package/artifacts/LSP8MintableAbstract.json +1328 -0
  24. package/artifacts/LSP8MintableInit.json +369 -5
  25. package/artifacts/LSP8MintableInitAbstract.json +1336 -0
  26. package/artifacts/LSP8NonTransferableAbstract.json +1367 -0
  27. package/artifacts/LSP8NonTransferableInitAbstract.json +1375 -0
  28. package/artifacts/LSP8RevokableAbstract.json +1317 -0
  29. package/artifacts/LSP8RevokableInitAbstract.json +1325 -0
  30. package/artifacts/LSP8Votes.json +7 -4
  31. package/artifacts/LSP8VotesInitAbstract.json +7 -4
  32. package/contracts/ILSP8IdentifiableDigitalAsset.sol +1 -1
  33. package/contracts/LSP8Constants.sol +1 -1
  34. package/contracts/LSP8Errors.sol +1 -1
  35. package/contracts/LSP8IdentifiableDigitalAsset.sol +73 -114
  36. package/contracts/LSP8IdentifiableDigitalAssetInitAbstract.sol +69 -116
  37. package/contracts/extensions/AccessControlExtended/AccessControlExtendedAbstract.sol +378 -0
  38. package/contracts/extensions/AccessControlExtended/AccessControlExtendedConstants.sol +13 -0
  39. package/contracts/extensions/AccessControlExtended/AccessControlExtendedErrors.sol +23 -0
  40. package/contracts/extensions/AccessControlExtended/AccessControlExtendedInitAbstract.sol +390 -0
  41. package/contracts/extensions/AccessControlExtended/IAccessControlExtended.sol +51 -0
  42. package/contracts/extensions/{LSP8Burnable.sol → LSP8Burnable/LSP8Burnable.sol} +7 -6
  43. package/contracts/extensions/{LSP8BurnableInitAbstract.sol → LSP8Burnable/LSP8BurnableInitAbstract.sol} +7 -6
  44. package/contracts/extensions/LSP8CappedBalance/ILSP8CappedBalance.sol +11 -0
  45. package/contracts/extensions/LSP8CappedBalance/LSP8CappedBalanceAbstract.sol +124 -0
  46. package/contracts/extensions/LSP8CappedBalance/LSP8CappedBalanceErrors.sol +9 -0
  47. package/contracts/extensions/LSP8CappedBalance/LSP8CappedBalanceInitAbstract.sol +174 -0
  48. package/contracts/extensions/LSP8CappedSupply/ILSP8CappedSupply.sol +11 -0
  49. package/contracts/extensions/LSP8CappedSupply/LSP8CappedSupplyAbstract.sol +59 -0
  50. package/contracts/extensions/LSP8CappedSupply/LSP8CappedSupplyErrors.sol +6 -0
  51. package/contracts/extensions/LSP8CappedSupply/LSP8CappedSupplyInitAbstract.sol +97 -0
  52. package/contracts/extensions/{LSP8Enumerable.sol → LSP8Enumerable/LSP8Enumerable.sol} +2 -2
  53. package/contracts/extensions/{LSP8EnumerableInitAbstract.sol → LSP8Enumerable/LSP8EnumerableInitAbstract.sol} +2 -2
  54. package/contracts/extensions/LSP8Mintable/ILSP8Mintable.sol +27 -0
  55. package/contracts/extensions/LSP8Mintable/LSP8MintableAbstract.sol +105 -0
  56. package/contracts/extensions/LSP8Mintable/LSP8MintableErrors.sol +5 -0
  57. package/contracts/extensions/LSP8Mintable/LSP8MintableInitAbstract.sol +155 -0
  58. package/contracts/extensions/LSP8NonTransferable/ILSP8NonTransferable.sol +48 -0
  59. package/contracts/extensions/LSP8NonTransferable/LSP8NonTransferableAbstract.sol +190 -0
  60. package/contracts/extensions/LSP8NonTransferable/LSP8NonTransferableErrors.sol +14 -0
  61. package/contracts/extensions/LSP8NonTransferable/LSP8NonTransferableInitAbstract.sol +246 -0
  62. package/contracts/extensions/LSP8Revokable/ILSP8Revokable.sol +28 -0
  63. package/contracts/extensions/LSP8Revokable/LSP8RevokableAbstract.sol +132 -0
  64. package/contracts/extensions/LSP8Revokable/LSP8RevokableErrors.sol +4 -0
  65. package/contracts/extensions/LSP8Revokable/LSP8RevokableInitAbstract.sol +178 -0
  66. package/contracts/extensions/{LSP8Votes.sol → LSP8Votes/LSP8Votes.sol} +3 -4
  67. package/contracts/extensions/{LSP8VotesConstants.sol → LSP8Votes/LSP8VotesConstants.sol} +1 -1
  68. package/contracts/extensions/{LSP8VotesInitAbstract.sol → LSP8Votes/LSP8VotesInitAbstract.sol} +3 -3
  69. package/contracts/presets/LSP8CustomizableToken.sol +277 -0
  70. package/contracts/presets/LSP8CustomizableTokenConstants.sol +32 -0
  71. package/contracts/presets/LSP8CustomizableTokenInit.sol +318 -0
  72. package/contracts/presets/LSP8Mintable.sol +13 -28
  73. package/contracts/presets/LSP8MintableInit.sol +13 -6
  74. package/dist/abi.cjs +8233 -158
  75. package/dist/abi.d.cts +12004 -323
  76. package/dist/abi.d.mts +12004 -323
  77. package/dist/abi.d.ts +12004 -323
  78. package/dist/abi.mjs +8217 -158
  79. package/dist/constants.cjs +21 -0
  80. package/dist/constants.d.cts +12 -1
  81. package/dist/constants.d.mts +12 -1
  82. package/dist/constants.d.ts +12 -1
  83. package/dist/constants.mjs +16 -1
  84. package/package.json +38 -15
  85. package/contracts/extensions/LSP8CappedSupply.sol +0 -85
  86. package/contracts/extensions/LSP8CappedSupplyInitAbstract.sol +0 -88
  87. package/contracts/presets/ILSP8Mintable.sol +0 -33
  88. package/contracts/presets/LSP8MintableInitAbstract.sol +0 -62
@@ -0,0 +1,378 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.27;
3
+
4
+ // interfaces
5
+ import {
6
+ IAccessControl
7
+ } from "@openzeppelin/contracts/access/IAccessControl.sol";
8
+ import {
9
+ IAccessControlEnumerable
10
+ } from "@openzeppelin/contracts/access/IAccessControlEnumerable.sol";
11
+ import {IAccessControlExtended} from "./IAccessControlExtended.sol";
12
+
13
+ // modules
14
+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
15
+
16
+ // libraries
17
+ import {
18
+ EnumerableSet
19
+ } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
20
+
21
+ // constants
22
+ import {
23
+ _INTERFACEID_ACCESSCONTROL,
24
+ _INTERFACEID_ACCESSCONTROLENUMERABLE,
25
+ _INTERFACEID_ACCESSCONTROLEXTENDED
26
+ } from "./AccessControlExtendedConstants.sol";
27
+
28
+ // errors
29
+ import {
30
+ AccessControlUnauthorizedAccount,
31
+ AccessControlBadConfirmation,
32
+ AccessControlCannotSetAdminForDefaultAdminRole
33
+ } from "./AccessControlExtendedErrors.sol";
34
+
35
+ /**
36
+ * @title AccessControlExtendedAbstract
37
+ * @dev Abstract contract implementing OZ-compatible role management with reverse lookups
38
+ * Uses EnumerableSet composition (NOT OZ AccessControl inheritance)
39
+ *
40
+ * Provides:
41
+ * - Standard OZ {IAccessControl} functions: hasRole, grantRole, revokeRole, renounceRole, getRoleAdmin
42
+ * - Standard OZ {IAccessControlEnumerable} functions: getRoleMember, getRoleMemberCount
43
+ * - Extended functions: rolesOf, getRoleMembers
44
+ * - Explicit role checks for every role-gated function
45
+ * - DEFAULT_ADMIN_ROLE as root admin for granting and revoking roles
46
+ * - Automatic transfer of all roles between old and new on ownership transfer
47
+ */
48
+ abstract contract AccessControlExtendedAbstract is
49
+ IAccessControlExtended,
50
+ Ownable
51
+ {
52
+ using EnumerableSet for EnumerableSet.AddressSet;
53
+ using EnumerableSet for EnumerableSet.Bytes32Set;
54
+
55
+ // --- Constants
56
+
57
+ /// @dev The default admin role. Value is `bytes32(0)` per OZ convention.
58
+ bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
59
+
60
+ // --- Storage
61
+
62
+ /// @dev Mapping from role to its admin role.
63
+ mapping(bytes32 role => bytes32 adminRole) private _roleAdmins;
64
+
65
+ /// @dev Forward lookup: role -> set of member addresses.
66
+ mapping(bytes32 role => EnumerableSet.AddressSet members)
67
+ private _roleMembers;
68
+
69
+ /// @dev Reverse lookup: address -> set of roles held.
70
+ mapping(address account => EnumerableSet.Bytes32Set rolesAssigned)
71
+ private _addressRoles;
72
+
73
+ // --- Modifier
74
+
75
+ /**
76
+ * @dev Modifier that checks the caller has `role`.
77
+ * Reverts with {AccessControlUnauthorizedAccount} if the check fails.
78
+ */
79
+ modifier onlyRole(bytes32 role) {
80
+ _checkRole(role);
81
+ _;
82
+ }
83
+
84
+ // --- Constructor
85
+
86
+ /**
87
+ * @dev Grants `DEFAULT_ADMIN_ROLE` to the contract owner so to allow it to administer roles to other addresses after deployment.
88
+ * This will also make it appear inside the enumerations (getRoleMember, rolesOf, getRoleMembers).
89
+ */
90
+ constructor() {
91
+ _grantRole(DEFAULT_ADMIN_ROLE, owner());
92
+ }
93
+
94
+ // --- ERC-165
95
+
96
+ /**
97
+ * @dev Returns true for {IAccessControl}, {IAccessControlEnumerable} and {IAccessControlExtended}.
98
+ */
99
+ function supportsInterface(
100
+ bytes4 interfaceId
101
+ ) public view virtual returns (bool) {
102
+ return
103
+ interfaceId == _INTERFACEID_ACCESSCONTROL ||
104
+ interfaceId == _INTERFACEID_ACCESSCONTROLENUMERABLE ||
105
+ interfaceId == _INTERFACEID_ACCESSCONTROLEXTENDED;
106
+ }
107
+
108
+ // --- IAccessControl
109
+
110
+ /**
111
+ * @inheritdoc IAccessControl
112
+ */
113
+ function hasRole(
114
+ bytes32 role,
115
+ address account
116
+ ) public view virtual returns (bool) {
117
+ return _hasRole(role, account);
118
+ }
119
+
120
+ /**
121
+ * @inheritdoc IAccessControl
122
+ */
123
+ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
124
+ return _roleAdmins[role];
125
+ }
126
+
127
+ /**
128
+ * @inheritdoc IAccessControlExtended
129
+ *
130
+ * @dev Sets `adminRole` as the admin of `role`. Available for extensions to configure custom admin hierarchies.
131
+ *
132
+ * @custom:warning
133
+ * - DO NOT expose this function without `onlyOwner` or `onlyRole(DEFAULT_ADMIN_ROLE)` access control.
134
+ * - Be aware that calling `setRoleAdmin(X, X)` creates a self-admin where nobody can grant role `X` unless someone already holds role `X`.
135
+ *
136
+ * @custom:requirements
137
+ * - `role` cannot be the `DEFAULT_ADMIN_ROLE`.
138
+ * - The caller must hold the `DEFAULT_ADMIN_ROLE`.
139
+ *
140
+ * @custom:events {RoleAdminChanged} with the previous and new admin roles.
141
+ */
142
+ function setRoleAdmin(
143
+ bytes32 role,
144
+ bytes32 adminRole
145
+ ) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
146
+ _setRoleAdmin(role, adminRole);
147
+ }
148
+
149
+ /**
150
+ * @inheritdoc IAccessControl
151
+ * @dev Grants `role` to `account`.
152
+ *
153
+ * @custom:requirements The caller must hold the admin role for `role`.
154
+ */
155
+ function grantRole(
156
+ bytes32 role,
157
+ address account
158
+ ) public virtual onlyRole(getRoleAdmin(role)) {
159
+ _grantRole(role, account);
160
+ }
161
+
162
+ /**
163
+ * @inheritdoc IAccessControl
164
+ * @dev Revokes `role` from `account`. The caller must hold the admin role for `role`.
165
+ *
166
+ * @custom:warning `DEFAULT_ADMIN_ROLE` cannot be removed from the current owner to prevent lockout.
167
+ */
168
+ function revokeRole(
169
+ bytes32 role,
170
+ address account
171
+ ) public virtual onlyRole(getRoleAdmin(role)) {
172
+ require(
173
+ !(role == DEFAULT_ADMIN_ROLE && account == owner()),
174
+ AccessControlUnauthorizedAccount(account, role)
175
+ );
176
+ _revokeRole(role, account);
177
+ }
178
+
179
+ /**
180
+ * @inheritdoc IAccessControl
181
+ * @dev Allows `msg.sender` to renounce their own `role`. The `callerConfirmation`
182
+ * parameter must equal `msg.sender` to prevent accidental renouncement (OZ pattern).
183
+ *
184
+ * @custom:warning The current owner cannot renounce `DEFAULT_ADMIN_ROLE`
185
+ * to prevent locking the contract out of role administration.
186
+ *
187
+ * @custom:events Emits {RoleRevoked} if `msg.sender` currently holds `role` and successfully revokes it for itself.
188
+ */
189
+ function renounceRole(
190
+ bytes32 role,
191
+ address callerConfirmation
192
+ ) public virtual {
193
+ require(
194
+ callerConfirmation == msg.sender,
195
+ AccessControlBadConfirmation()
196
+ );
197
+ require(
198
+ !(role == DEFAULT_ADMIN_ROLE && msg.sender == owner()),
199
+ AccessControlUnauthorizedAccount(msg.sender, role)
200
+ );
201
+ _revokeRole(role, msg.sender);
202
+ }
203
+
204
+ // --- IAccessControlEnumerable
205
+
206
+ /**
207
+ * @inheritdoc IAccessControlEnumerable
208
+ */
209
+ function getRoleMember(
210
+ bytes32 role,
211
+ uint256 index
212
+ ) public view virtual returns (address) {
213
+ return _roleMembers[role].at(index);
214
+ }
215
+
216
+ /**
217
+ * @inheritdoc IAccessControlEnumerable
218
+ */
219
+ function getRoleMemberCount(
220
+ bytes32 role
221
+ ) public view virtual returns (uint256) {
222
+ return _roleMembers[role].length();
223
+ }
224
+
225
+ // --- IAccessControlExtended
226
+
227
+ /**
228
+ * @inheritdoc IAccessControlExtended
229
+ */
230
+ function rolesOf(
231
+ address account
232
+ ) public view virtual returns (bytes32[] memory) {
233
+ return _addressRoles[account].values();
234
+ }
235
+
236
+ /**
237
+ * @notice Returns all members that hold `role`.
238
+ *
239
+ * @dev Convenience function that returns the full membership array in a single call.
240
+ * Equivalent to calling {getRoleMember} for each index from `0` to `getRoleMemberCount(role) - 1`.
241
+ *
242
+ * @param role The role identifier to query members for.
243
+ * @return An array of addresses that currently hold the specified role.
244
+ *
245
+ * @custom:warning This function copies the entire role members set from storage into memory.
246
+ * This is designed to mostly be used by view accessors that are queried without any gas fees.
247
+ * For roles with a large number of members, this may consume a significant amount of gas. If calling this function on-chain, consider calling `{getRoleMember}` repeatedly, using `getRoleMemberCount` to know as max index.
248
+ * This function is primarily intended for off-chain usage.
249
+ */
250
+ function getRoleMembers(
251
+ bytes32 role
252
+ ) public view virtual returns (address[] memory) {
253
+ return _roleMembers[role].values();
254
+ }
255
+
256
+ // --- Internal functions
257
+
258
+ /**
259
+ * @dev Grants `role` to `account`. No-op if the account already holds the role
260
+ * (matching OZ behavior). Updates both forward and reverse lookups.
261
+ *
262
+ * @custom:events Emits {RoleGranted} if the role was newly granted.
263
+ */
264
+ function _grantRole(bytes32 role, address account) internal virtual {
265
+ bool added = _roleMembers[role].add(account);
266
+
267
+ if (added) {
268
+ _addressRoles[account].add(role);
269
+ emit RoleGranted({
270
+ role: role,
271
+ account: account,
272
+ sender: msg.sender
273
+ });
274
+ }
275
+ }
276
+
277
+ /**
278
+ * @dev Revokes `role` from `account`. No-op if the account does not hold the role.
279
+ *
280
+ * @custom:events Emits {RoleRevoked} if the role was revoked.
281
+ */
282
+ function _revokeRole(bytes32 role, address account) internal virtual {
283
+ bool removed = _roleMembers[role].remove(account);
284
+
285
+ if (removed) {
286
+ _addressRoles[account].remove(role);
287
+ emit RoleRevoked({
288
+ role: role,
289
+ account: account,
290
+ sender: msg.sender
291
+ });
292
+ }
293
+ }
294
+
295
+ /**
296
+ * @dev Checks that `msg.sender` has `role`. Reverts with
297
+ * {AccessControlUnauthorizedAccount} if the check fails.
298
+ *
299
+ * @custom:warning Overriding this function changes the behavior of the {onlyRole} modifier.
300
+ */
301
+ function _checkRole(bytes32 role) internal view virtual {
302
+ _checkRole(role, msg.sender);
303
+ }
304
+
305
+ /**
306
+ * @dev Checks that `account` has `role`.
307
+ *
308
+ * Reverts with {AccessControlUnauthorizedAccount} if the account does not
309
+ * explicitly hold the role.
310
+ */
311
+ function _checkRole(bytes32 role, address account) internal view virtual {
312
+ require(
313
+ _hasRole(role, account),
314
+ AccessControlUnauthorizedAccount(account, role)
315
+ );
316
+ }
317
+
318
+ function _hasRole(
319
+ bytes32 role,
320
+ address account
321
+ ) internal view virtual returns (bool) {
322
+ return _roleMembers[role].contains(account);
323
+ }
324
+
325
+ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
326
+ require(
327
+ role != DEFAULT_ADMIN_ROLE,
328
+ AccessControlCannotSetAdminForDefaultAdminRole()
329
+ );
330
+
331
+ bytes32 previousAdminRole = getRoleAdmin(role);
332
+ _roleAdmins[role] = adminRole;
333
+
334
+ emit RoleAdminChanged({
335
+ role: role,
336
+ previousAdminRole: previousAdminRole,
337
+ newAdminRole: adminRole
338
+ });
339
+ }
340
+
341
+ // --- Ownership sync
342
+
343
+ /**
344
+ * @dev Overrides `_transferOwnership` to automatically transfer ALL roles held by
345
+ * the old owner to the new owner. This includes `DEFAULT_ADMIN_ROLE` and any other
346
+ * custom roles the old owner was assigned.
347
+ *
348
+ * For each role held by the old owner:
349
+ * 1. The role is revoked from the old owner.
350
+ * 2. The role is granted to the new owner (if not already held).
351
+ *
352
+ * @custom:info When renouncing ownership, roles are only removed from the old owner. Roles are not passed to `address(0)` (being the `newOwner` in the case of renounce ownership).
353
+ *
354
+ * @custom:warning
355
+ * - Gas cost scales linearly with the number of roles the old owner holds.
356
+ * - If the old owner holds a large number of roles, the transaction may approach or exceed
357
+ * the block gas limit and fail. Avoid assigning too many roles to the owner to ensure
358
+ * ownership transfers remain callable.
359
+ */
360
+ function _transferOwnership(address newOwner) internal virtual override {
361
+ address oldOwner = owner();
362
+ Ownable._transferOwnership(newOwner);
363
+
364
+ // Snapshot the old owner's roles before mutating storage (values() returns a memory copy)
365
+ bytes32[] memory oldOwnerRoles = _addressRoles[oldOwner].values();
366
+
367
+ for (uint256 ii = 0; ii < oldOwnerRoles.length; ++ii) {
368
+ bytes32 role = oldOwnerRoles[ii];
369
+
370
+ _revokeRole(role, oldOwner);
371
+
372
+ // exclude case when renouncing ownership
373
+ if (newOwner != address(0)) {
374
+ _grantRole(role, newOwner);
375
+ }
376
+ }
377
+ }
378
+ }
@@ -0,0 +1,13 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.27;
3
+
4
+ /// @dev ERC-165 interface ID for IAccessControl from OpenZeppelin.
5
+ bytes4 constant _INTERFACEID_ACCESSCONTROL = 0x7965db0b;
6
+
7
+ /// @dev ERC-165 interface ID for IAccessControlEnumerable from OpenZeppelin.
8
+ bytes4 constant _INTERFACEID_ACCESSCONTROLENUMERABLE = 0x5a05180f;
9
+
10
+ /// @dev ERC-165 interface ID for IAccessControlExtended.
11
+ /// Computed as XOR of selectors:
12
+ /// getRoleMembers(bytes32) ^ rolesOf(address) ^ setRoleAdmin(bytes32,bytes32)
13
+ bytes4 constant _INTERFACEID_ACCESSCONTROLEXTENDED = 0x90832245;
@@ -0,0 +1,23 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.27;
3
+
4
+ /**
5
+ * @dev Reverts when an address attempts a role-gated action and is missing the `neededRole`.
6
+ *
7
+ * @param account The address that attempted the action.
8
+ * @param neededRole The role that was required.
9
+ */
10
+ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
11
+
12
+ /**
13
+ * @dev Reverts error when the caller of the `renounceRole` function is not the expected one.
14
+ * NOTE: Do not confuse with {AccessControlUnauthorizedAccount}.
15
+ */
16
+ error AccessControlBadConfirmation();
17
+
18
+ /**
19
+ * @dev Reverts when trying to change the admin of the `DEFAULT_ADMIN_ROLE`.
20
+ * The `DEFAULT_ADMIN_ROLE` is its own admin, meaning only accounts with the `DEFAULT_ADMIN_ROLE` can grant or revoke it.
21
+ * This hierarchy cannot be changed.
22
+ */
23
+ error AccessControlCannotSetAdminForDefaultAdminRole();