DotnsPopController
Inherits: Initializable, UUPSUpgradeable, OwnableUpgradeable, ERC165Upgradeable, IDotnsPopController
Title: DotnsPopController
Dedicated PoP controller orchestrating lite-person and full-person username issuance on behalf of the PoP gateway pallet.
Lives behind its own UUPS proxy with its own storage. Registered on DotnsRegistrar
via addController, which is how multiple controllers coexist on the same registrar
without interfering with each other.
Enforcement:
Personhood is attested off-chain by the gateway pallet before the call reaches this
contract, so the on-chain personhood precompile is not re-queried on the gateway path.
Every base-label mint path still calls @custom:function IPopRules.classifyName to reject
governance-reserved labels (@custom:reverts InvalidBaseLabel on the base path,
Notes:
-
reverts: InvalidLiteLabel on the lite path). The lite leg accepts any two-digit lite label whose stem is not governance-reserved, regardless of stem length. Native-token pricing is bypassed entirely; the gateway pays no rent. Decoupling: This contract does not import or call
IDotnsRegistrarController. The public commit-reveal controller is equally unaware of this one. Cross-flow collision handling relies on two distinct properties, neither of which requires the two controllers to know about each other: (1) Lite-person labels (NAMEXX) share the public namespace: they are just DNS labels with exactly two trailing digits. First-to-mint wins at the ERC721 layer, so a lite-user and a public registrant cannot hold the same flat label simultaneously. Keeping one namespace removes the ambiguity downstream tooling (dotli, dweb) would see with a separate separator form. (2) Base-name reservations are synchronised intoIPopRules. The head of this controller's reservation queue is written throughIPopRules.reserveBaseNameForPopon every head transition; the slot is cleared throughIPopRules.releaseBaseNamewhen the queue empties (claim, final relinquish, final expiry). The public commit-reveal controller routes throughIPopRules.priceWithCheck, which rejects any registration targeting a base-name stem reserved for another user, so the public flow respects gateway reservations without ever importing this contract. PopRules is the single cross-flow authority; the queue here is the intra-PoP ordering layer on top of it. Shared primitives: labelhash / namehash via @custom:contract LabelUtils; the mint + forward-registry + store-write triad via @custom:contract RegistrationUtils; chat-key and lite-to-full link persistence via -
contract: IDotnsPopResolver. Keeping per-name records on the resolver preserves the "Store = labels only" invariant.
-
security-contact: admin@parity.io
Constants
MAX_RESERVATION_QUEUE
Upper bound for the number of simultaneously queued reservations per label.
Keeps expireReservation gas bounded.
uint16 public constant MAX_RESERVATION_QUEUE = 64
MIN_RESERVATION_DURATION
Minimum value accepted by @custom:function setReservationDuration.
Prevents owner misconfiguration from instantly expiring every live queue and pending-claim entry. The actual production duration is governance-tuned higher.
uint64 public constant MIN_RESERVATION_DURATION = 1 hours
CHAT_KEY_LENGTH
Required byte length for a non-empty chat key.
Mirrors @custom:contract IDotnsPopResolver InvalidChatKeyLength so the controller
can fail closed before the mint instead of bubbling the resolver's revert after partial
state has been committed.
uint256 private constant CHAT_KEY_LENGTH = 65
State Variables
protocolRegistry
Protocol-level address registry for all DotNS contracts.
IDotnsProtocolRegistry public protocolRegistry
_reservationMeta
Per-label queue metadata (head/tail pointers).
mapping(bytes32 labelhash => ReservationQueueMeta meta) internal _reservationMeta
_reservationEntries
Per-label sparse entries keyed by monotonically-increasing index.
mapping(bytes32 labelhash => mapping(uint64 index => ReservationEntry entry)) internal
_reservationEntries
_userReservations
Single per-user pointer into the reservation queues.
Keeps per-user reservation data behind one key and one struct value so callers read both fields in one call instead of two.
mapping(address user => UserReservation reservation) internal _userReservations
_reservedBaseLabel
Remembers the base-label string for each reserved labelhash so the PopRules
sync path can address the reservation by its original string form (PopRules keys its
reservations mapping by string).
Populated on first enqueue for a label, cleared when the queue empties. Exists
only to bridge the queue's bytes32 key space to PopRules' string key space;
nothing else reads it.
mapping(bytes32 labelhash => string baseLabel) internal _reservedBaseLabel
reservationDuration
Duration (in seconds) after which a reservation entry is considered expired.
Mirrors pallet_resources::UsernameReservationDuration. Configurable by
governance via setReservationDuration.
uint64 public override reservationDuration
_pendingClaimUsers
Enumeration set of users holding at least one pending claim.
Membership equals the set of users with a non-empty queue. Used by
pendingClaimUserCount and pendingClaimUsers for paginated enumeration.
EnumerableSet.AddressSet private _pendingClaimUsers
_pendingClaimQueue
Per-user pile of deferred names awaiting a LabelStore.
The Root gateway origin cannot deploy a LabelStore (contract creation is forbidden
from Root), so deferred names accumulate here until a signed-origin
Note:
function: settlePendingClaims deploys the store and writes the stashed labels. Each
entry's deadline is measured from its own mintedAt against reservationDuration.
mapping(address user => PendingClaim[] queue) internal _pendingClaimQueue
__gap
Reserved storage space to allow for layout changes in future upgrades.
uint256[50] private __gap
Functions
onlyRoot
Restricts calls to a substrate Root origin.
modifier onlyRoot() ;
constructor
Note: oz-upgrades-unsafe-allow: constructor
constructor() ;
initialize
Initialises the PoP controller.
Called once through the UUPS proxy; _disableInitializers on the implementation
makes direct calls revert with @custom:reverts InvalidInitialization, and any nested
call outside an active initialiser scope reverts with @custom:reverts NotInitializing.
Emits @custom:emits ReservationDurationSet so indexers observe the initial value
through the same event the setter uses later.
function initialize(
IDotnsProtocolRegistry registry,
uint64 reservationDuration_
)
external
initializer;
reserveLiteName
Registers a lite-person username on behalf of the supplied user without touching the base-name reservation queue.
Callable only under a substrate Root origin (otherwise @custom:reverts NotRoot). The
supplied label must satisfy the dotted stem.NN shape and the flattened label must classify
as PopLite (otherwise @custom:reverts InvalidLiteLabel); a supplied chat
key whose length is neither zero nor CHAT_KEY_LENGTH reverts
Notes:
-
reverts: InvalidChatKey before mint and resolver writes run. On a warm-path mint
-
emits: LiteNameReserved and @custom:emits NameRegistered. On a cold-path mint @custom:emits LiteNameReserved and @custom:emits PendingClaimStashed, with
function reserveLiteName(LiteRegistration calldata params) external override onlyRoot;
Parameters
| Name | Type | Description |
|---|---|---|
params | LiteRegistration | Registration request; see @custom:struct LiteRegistration. |
reserveBaseName
Registers a lite-person username on behalf of the supplied user and optionally enqueues a reservation for a base name they intend to claim as a full person later.
Callable only under a substrate Root origin (otherwise @custom:reverts NotRoot). The
lite leg validates the dotted stem.NN shape and requires the flattened label to classify
as PopLite (otherwise @custom:reverts InvalidLiteLabel), and rejects a
supplied chat key whose length is neither zero nor CHAT_KEY_LENGTH
(otherwise @custom:reverts InvalidChatKey). On a warm-path mint (user already has a
LabelStore) it @custom:emits LiteNameReserved and @custom:emits NameRegistered;
on a cold-path mint it @custom:emits LiteNameReserved and
Notes:
-
emits: PendingClaimStashed, with @custom:emits NameRegistered deferred to
-
function: settlePendingClaims when the claim settles. The base-name leg only runs when
reservedBaseLabelis non-empty: it validates the DNS-label shape and requires a true base label with no trailing digits (otherwise @custom:reverts InvalidBaseLabel) and with no owner on the registrar (otherwise @custom:reverts BaseNameAlreadyRegistered), since a name that already has an owner could never be claimed. This validation runs before both the lite mint and any queue mutation, so an already-registeredreservedBaseLabelaborts the whole call and the candidate receives no lite username either; callers should validate the reserved label before attesting rather than relying on this revert. It then advances the head past expired entries (@custom:emits ReservationExpired for each one), removes the user from any prior queue position so a single user holds at most one live reservation across all labels, and enqueues a fresh entry (@custom:emits ReservationQueued). The enqueue rejects with @custom:reverts AlreadyReserved when the user already holds a reservation that was not cleared by the prior removal and with @custom:reverts QueueFull when the per-label queue has reachedMAX_RESERVATION_QUEUE. Cross-chain callers pass the ABI-encoded reservation tuple as the call's payload, which Solidity decodes directly.
function reserveBaseName(BaseReservation calldata params) external override onlyRoot;
Parameters
| Name | Type | Description |
|---|---|---|
params | BaseReservation | Reservation request; see @custom:struct BaseReservation. |
reserveBaseNameOnly
Enqueues only the full/base-name reservation for a user.
Callable only under a substrate Root origin (otherwise @custom:reverts NotRoot). This is the second step of the split gateway flow: @custom:function reserveLiteName mints the lite username first, then this function reserves the full/base label in a separate transaction so proof-size stays below per-call limits. Reverts with @custom:reverts InvalidBaseLabel when the label is empty, non-canonical, digit-suffixed, or governance-reserved, and with
Note: reverts: BaseNameAlreadyRegistered when the label already has an owner on the registrar and so could never be claimed. The caller remains agnostic about backend batching; it simply exposes a small retryable primitive.
function reserveBaseNameOnly(BaseNameReservation calldata params) external override onlyRoot;
Parameters
| Name | Type | Description |
|---|---|---|
params | BaseNameReservation | Reservation request; see @custom:struct BaseNameReservation. |
_reserveLite
Lite-only mint shared by @custom:function reserveLiteName and the lite leg of @custom:function reserveBaseName.
Gateway attestation is the authority for personhood on this path; the on-chain
precompile is not consulted. The dotted-format check accepts only stem.NN, then
PopRules classification must place the flattened label outside the governance-reserved
tier before minting; any non-reserved two-digit lite label is accepted regardless of stem
length. Takes the @custom:struct LiteRegistration struct directly so both call sites pass
the same payload shape: the typed entrypoint forwards its own params, the
reserveBaseName entrypoint forwards params.lite.
function _reserveLite(IPopRules rules, LiteRegistration calldata params) internal;
registerBaseName
Registers a full-person username on behalf of the supplied user.
Callable only under a substrate Root origin (otherwise @custom:reverts NotRoot). The
base label must satisfy the DNS-label shape and be a true base label with no trailing digits
(otherwise @custom:reverts InvalidBaseLabel), and the label must not
classify as governance-reserved (otherwise @custom:reverts InvalidBaseLabel). The
gateway also defers to PopRules as the single cross-flow authority: when PopRules
carries a live base-name slot held by another user (stamped by the public commit-reveal
flow or this controller's prior queue head), the call reverts @custom:reverts NotHolder
before any queue mutation. Two orthogonal axes drive the state machine. The reservation
axis treats the user as claiming if and only if they hold the live head-of-queue
reservation on the base label: a claim wipes the entire queue, releases the PopRules
slot, and @custom:emits BaseNameClaimed; a non-claim silently relinquishes any
pending entry the user holds and @custom:emits StandaloneNameRegistered. Advancing
the queue head past expired entries @custom:emits ReservationExpired for each
one. The chat-key axis selects whether a fresh key is persisted on the resolver or the
new entry inherits its key from a prior lite-person username. The fresh-key branch
rejects a chat key whose length is neither zero nor CHAT_KEY_LENGTH (otherwise
Notes:
-
reverts: InvalidChatKey). The
LiteUsernamebranch validates the lite label'sNAMEXXshape (otherwise @custom:reverts InvalidLiteLabel), requires the registrant to own the lite token (otherwise @custom:reverts LiteLabelNotOwnedByUser), reads the lite node's chat key from the resolver and copies it across; if the lite node carries no chat key the inherited value is empty and the full node's chat-key write is silently skipped (theLiteToFullLinkedevent still fires). @custom:emits LiteToFullLinked alongside the registration event. On a warm-path mint the event order is -
emits: NameRegistered first (from the inner mint), then
function registerBaseName(FullRegistration calldata params) external override onlyRoot;
Parameters
| Name | Type | Description |
|---|---|---|
params | FullRegistration | Registration request; see @custom:struct FullRegistration. |
expireReservation
Permissionlessly removes expired entries from the head of a reservation queue.
Permissionless on purpose: anyone (typically a UI or a bot) can poke a stale queue
so the next live head takes over without waiting for the next gateway call. Validates
the DNS-label shape of reservedBaseLabel (otherwise @custom:reverts InvalidBaseLabel)
and @custom:emits ReservationExpired for every expired entry reaped from the
head. Only base-shaped labels (no trailing digits) ever key a reservation queue, so a
lite-shaped label still passes the shape check but resolves to an empty queue and the
call is a no-op.
function expireReservation(string calldata reservedBaseLabel) external override;
relinquishReservation
Lets the caller voluntarily drop their own active reservation.
Reverts with @custom:reverts NoActiveReservation when the caller holds no live reservation. On success the caller's entry is removed from its queue and
Note: emits: ReservationRelinquished is emitted; if the removed entry was the queue head, head advancement may additionally @custom:emits ReservationExpired for any stale entries reaped behind it.
function relinquishReservation() external override;
claimLabelStore
Settles the caller's own pending claims into their LabelStore.
Convenience for a user settling their own store: equivalent to
Notes:
-
function: settlePendingClaims with
msg.senderand a bounded batch. The caller deploys and pays for their store on the first write. Settles at most one bounded batch so the call cannot exceed the block gas limit;moreRemainingreports whether the caller still holds unsettled entries, in which case they call again. Emits the same -
emits: PendingClaimSettled and @custom:emits NameRegistered as
function claimLabelStore() external override returns (bool moreRemaining);
Returns
| Name | Type | Description |
|---|---|---|
moreRemaining | bool | Whether the caller still holds unsettled entries. |
settlePendingClaims
Settles up to limit of a user's pending claims, writing each stashed label into
the user's LabelStore and deploying that store when the user has none yet.
Permissionless: any caller may settle any user's claims and bears the full cost,
including the LabelStore storage deposit, which pallet-revive charges to the
transaction signer. Settlement is never destructive: the name is already minted, so this
only completes the deferred label write. Each settled entry is removed from the queue and
the user leaves the pending-claim enumeration set once their queue empties. At most
limit entries are processed so a large queue cannot exceed the block gas limit;
moreRemaining reports whether entries are left for a follow-up call, and a limit of
zero settles nothing. Writes are idempotent on an already-locked store slot, so a claim
whose label was independently written settles harmlessly. Emits
Note:
emits: PendingClaimSettled and @custom:emits NameRegistered per settled entry, with
settledBy set to the caller so a third-party settlement is distinguishable from a
self-settlement.
function settlePendingClaims(
address user,
uint256 limit
)
external
override
returns (uint256 settledCount, bool moreRemaining);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Account whose pending claims are settled. |
limit | uint256 | Maximum number of entries to settle in this call. |
Returns
| Name | Type | Description |
|---|---|---|
settledCount | uint256 | Number of entries settled. |
moreRemaining | bool | Whether the user still holds unsettled entries. |
_settlePending
Shared settlement loop behind @custom:function claimLabelStore and
Settles up to limit of the user's pending claims, deploying the store on the first
write, and removes the user from the enumeration set once their queue empties.
Note: function: settlePendingClaims.
function _settlePending(
address user,
uint256 limit
)
internal
returns (uint256 settledCount, bool moreRemaining);
_settlePendingLabel
Writes a single pending label into the user's store, deploying the store lazily.
The store is created only when there is a label to write, so a caller who settles an empty queue never leaves a fresh store behind with nothing in it. Returns the (possibly newly deployed) store so the caller threads it through the remaining entries.
function _settlePendingLabel(
IStoreFactory factory,
address store,
address user,
string memory label
)
internal
returns (address);
isReservedForClaim
Returns whether a label currently has a live reservation at the queue head.
Validates the DNS-label shape of reservedBaseLabel (otherwise
Note: reverts: InvalidBaseLabel) before inspecting the queue.
function isReservedForClaim(string calldata reservedBaseLabel)
external
view
override
returns (bool reserved, address holder);
setReservationDuration
Updates the reservation duration used to decide when queue entries expire.
Owner-gated (otherwise @custom:reverts OwnableUnauthorizedAccount); emits
Note: emits: ReservationDurationSet on success.
function setReservationDuration(uint64 duration) external override onlyOwner;
reservationMeta
Returns the queue metadata (head, tail) for labelhash.
Read-only accessor over the per-label reservation queue. head == tail means
the queue is empty; active entries occupy [head, tail). Exposed on the interface
because invariant tests and off-chain consumers (dotli, dweb) use it to enumerate
live queue state without scanning storage.
function reservationMeta(bytes32 labelhash)
external
view
override
returns (uint64 head, uint64 tail);
Parameters
| Name | Type | Description |
|---|---|---|
labelhash | bytes32 | Keccak-256 of the base label whose queue is being read. |
Returns
| Name | Type | Description |
|---|---|---|
head | uint64 | Index of the live queue head. |
tail | uint64 | Index one past the last queued entry. |
reservationEntry
Returns the queue entry at index for labelhash.
Sparse storage: a zero entryOwner means the slot was relinquished, expired and
reaped, or never written. Callers pair this with @custom:function reservationMeta to walk
the live window [head, tail).
function reservationEntry(
bytes32 labelhash,
uint64 index
)
external
view
override
returns (address entryOwner, uint64 joinedAt);
Parameters
| Name | Type | Description |
|---|---|---|
labelhash | bytes32 | Keccak-256 of the base label whose queue is being read. |
index | uint64 | Queue index to look up. |
Returns
| Name | Type | Description |
|---|---|---|
entryOwner | address | Owner of the slot (zero if empty/relinquished). |
joinedAt | uint64 | Timestamp the entry was enqueued (only meaningful when entryOwner != address(0)). |
userReservation
Returns user's current reservation pointer.
A zero labelhash on the returned struct means the user holds no reservation;
index is meaningful only when labelhash is non-zero.
function userReservation(address user)
external
view
override
returns (UserReservation memory reservation);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Account whose reservation pointer is being read. |
Returns
| Name | Type | Description |
|---|---|---|
reservation | UserReservation | Per-user reservation pointer; see @custom:struct UserReservation. |
pendingClaims
Returns a paginated slice of a user's pending claims in queue order.
An empty array means the user has no pending claims at offset. Each entry carries
its mintedAt; the settlement deadline is mintedAt + reservationDuration. An offset
past the end returns an empty array rather than reverting, and a page holds at most
DotnsConstants.MAX_PAGE_SIZE entries.
function pendingClaims(
address user,
uint256 offset,
uint256 limit
)
external
view
override
returns (PendingClaim[] memory claims);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Account whose pending claims are read. |
offset | uint256 | Start index into the queue. |
limit | uint256 | Maximum entries to return. |
Returns
| Name | Type | Description |
|---|---|---|
claims | PendingClaim[] | Page of the user's pending claims; see @custom:struct PendingClaim. |
pendingClaimCountOf
Returns the number of pending claims currently staged for user.
function pendingClaimCountOf(address user) external view override returns (uint256 count);
Parameters
| Name | Type | Description |
|---|---|---|
user | address | Account whose pending claims are counted. |
Returns
| Name | Type | Description |
|---|---|---|
count | uint256 | Number of staged pending claims. |
pendingClaimUserCount
Returns the number of users with at least one live pending claim.
Exact live count, not an all-time tally: fully settled users are removed from the enumeration set so off-chain consumers can page through every stalled user without filtering.
function pendingClaimUserCount() external view override returns (uint256 count);
Returns
| Name | Type | Description |
|---|---|---|
count | uint256 | Number of users currently holding a pending claim. |
pendingClaimUsers
Returns a paginated slice of users with at least one live pending claim.
Pair with @custom:function pendingClaims to read each user's stashed entries.
Ordering is not chronological; callers MUST NOT assume mintedAt is monotonic
across the slice. Returns an empty array when offset is past the live count, and a page
holds at most DotnsConstants.MAX_PAGE_SIZE entries.
function pendingClaimUsers(
uint256 offset,
uint256 limit
)
external
view
override
returns (address[] memory users);
Parameters
| Name | Type | Description |
|---|---|---|
offset | uint256 | Start index. |
limit | uint256 | Maximum entries to return. |
Returns
| Name | Type | Description |
|---|---|---|
users | address[] | Slice of users currently holding a pending claim. |
reservedBaseLabelOf
Returns the base label a reservation queue is keyed under.
Reverse lookup from the bytes32 queue key to its label string, so a consumer that
observed a queue by labelhash (for example from a reservation event) can recover the
human-readable label without holding its preimage. Returns an empty string when no
reservation was ever enqueued under labelhash.
function reservedBaseLabelOf(bytes32 labelhash)
external
view
override
returns (string memory baseLabel);
Parameters
| Name | Type | Description |
|---|---|---|
labelhash | bytes32 | Keccak-256 of the base label. |
Returns
| Name | Type | Description |
|---|---|---|
baseLabel | string | The base label string, or empty when unknown. |
supportsInterface
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC165Upgradeable, IERC165)
returns (bool);
version
Returns implementation version.
function version() external pure virtual returns (string memory versionString);
Returns
| Name | Type | Description |
|---|---|---|
versionString | string | Current version string. |
_completeGatewayRegistration
Mints a name, wires forward registry, persists PoP-flow records (chat key,
lite link) on the PoP resolver, and either writes the label into the owner's
existing LabelStore or stashes a pending claim when the owner has none yet.
The mint + forward-registry pair is delegated to
Notes:
-
function: RegistrationUtils.registerAndStore so this flow and the public commit-reveal flow share exactly one implementation of that sequence. The label is passed empty so the registrar does not deploy a
LabelStore; substrate Root cannot run theLabelStoreconstructor underpallet-revive. PoP-flow per-name records (chat key, lite link) are persisted eagerly on @custom:contract IDotnsPopResolver here, before the label is written, so the resolver carries the full identity record from mint time regardless of whether the owner already has aLabelStore. The Store stays labels-only. Warm path emits @custom:emits NameRegistered immediately; the cold path emits @custom:emits PendingClaimStashed at mint and defers -
emits: NameRegistered to @custom:function settlePendingClaims when the claim settles.
function _completeGatewayRegistration(
address user,
string memory label,
bytes32 labelhash,
bytes32 node,
bytes memory chatKeyBytes,
bytes32 liteLabelhash
)
internal;
_writeRecord
Writes a name's label into store.
Single canonical persistence step shared by the warm gateway path and
Note:
function: settlePendingClaims. The store key is node, matching
the registrar's _writeOwnerLabel convention. Idempotent on already-locked slots so a
user whose store was pre-populated under the same node (e.g. by a sibling protocol
flow) can still settle their pending claim without bricking on LabelAlreadyExists.
function _writeRecord(address store, bytes32 node, string memory label) internal;
Parameters
| Name | Type | Description |
|---|---|---|
store | address | Owner's LabelStore proxy. |
node | bytes32 | namehash(labelhash) for the entry. |
label | string | Bare DNS label (no TLD); the TLD is appended on write. |
_stashPendingClaim
Appends a deferred binding for user and adds them to the enumeration set.
The Root gateway origin cannot deploy the user's LabelStore, so deferred names pile
up in _pendingClaimQueue until a signed-origin @custom:function settlePendingClaims
writes them. Adding the user to the set is idempotent, so repeat stashes keep a single
enumeration entry. Emits @custom:emits PendingClaimStashed.
function _stashPendingClaim(address user, string memory label, bytes32 labelhash) internal;
_isExpired
Returns whether a queue entry is expired relative to block.timestamp.
function _isExpired(uint64 joinedAt) internal view returns (bool);
_enqueueReservation
Appends a new reservation entry to the tail of the queue for labelhash.
Reverts if the queue is full or the user already holds a reservation. When the
enqueued entry is the new head of an empty queue, the controller also reserves the
base name on PopRules so the public commit-reveal flow sees the reservation through
its existing priceWithCheck guard. Subsequent waiters only live in the local queue
until they are promoted.
function _enqueueReservation(
IPopRules rules,
bytes32 labelhash,
string memory baseLabel,
address user
)
internal;
_clearQueue
Wipes the entire reservation queue for labelhash and releases the
corresponding PopRules reservation.
Used when a holder claims their reservation: every waiter is evicted and their per-user tracking state is cleared, and PopRules is told the slot is free so future public registrations are unblocked (the claim itself just minted the name, so there is nothing left to reserve).
function _clearQueue(bytes32 labelhash) internal;
_advanceExpiredHead
Advances the queue head past every expired entry at the head of the queue.
Reset semantics matter: when the queue empties (head catches tail), the meta slot is deleted AND the PopRules base-name slot is released, so the public commit-reveal flow can register the label again. When a new live head emerges, PopRules is re-synced to that head so reservations cannot be paid around by another address. Emits
Note: emits: ReservationExpired once per expired entry reaped from the head.
function _advanceExpiredHead(bytes32 labelhash) internal;
_removeUserFromQueue
Removes user from whichever reservation queue they currently occupy.
For a head removal, we delete the entry without bumping meta.head and delegate
the advance to _advanceExpiredHead. Its existing zero-owner skip walks past the
freshly-deleted slot, and its head != meta.head branch fires the PopRules resync
in the one place head promotion is actually handled. Non-head removals leave the
queue shape intact, so no advance or resync is needed.
function _removeUserFromQueue(address user) internal;
_validateLiteLabel
Validates a lite-person NAMEXX label and derives (labelhash, node).
function _validateLiteLabel(string memory liteLabel)
internal
view
returns (bytes32 labelhash, bytes32 node);
_validateBaseLabel
Validates a base (full-person) DNS label and derives (labelhash, node).
function _validateBaseLabel(string calldata baseLabel)
internal
view
returns (bytes32 labelhash, bytes32 node);
_validateReservableBaseLabel
Validates a base label as reservable and returns its hashes.
Shared by both reservation entrypoints so the guard cannot drift between them. Runs
three checks and reverts on the first failure, before any reservation state is mutated: the
label must classify outside the governance-reserved tier and be a base name, be a canonical
single label, and have no owner on the registrar. The last check is the fix for a
reservation queued over an already-registered name: the queue keys by stem, so such a
reservation could never be redeemed yet would lock every two-digit variant of the stem for
the full reservation window. exists (owner set) mirrors exactly what makes the eventual
claim's mint revert, so a label that passes here is one a claim can still register.
function _validateReservableBaseLabel(
IPopRules rules,
string calldata baseLabel
)
internal
view
returns (bytes32 labelhash, bytes32 node);
_requireValidChatKey
Reverts when a non-empty chat key is not exactly CHAT_KEY_LENGTH bytes.
Mirrors the resolver's own length gate so the gateway sees a controller-local
InvalidChatKey revert before any mint state is written.
function _requireValidChatKey(bytes memory chatKey) internal pure;
_popResolver
Resolves the PoP resolver via the protocol registry.
function _popResolver() internal view returns (IDotnsPopResolver);
_popRules
Resolves the PopRules contract via the protocol registry.
function _popRules() internal view returns (IPopRules);
_storeFactory
Resolves the Store factory via the protocol registry.
function _storeFactory() internal view returns (IStoreFactory);
_registrar
Resolves the registrar via the protocol registry.
function _registrar() internal view returns (IDotnsRegistrar);
_syncPopRulesToHead
Writes the new head of the queue into PopRules so the public commit-reveal flow
rejects registrations of this base name for anyone other than newHead.
Callers guarantee newHead is non-zero (the queue holds a live entry) and that
_reservedBaseLabel[labelhash] is non-empty (any non-empty queue had its first head
write the slot). The release-then-reserve pair satisfies PopRules' ownership gate on
reserveBaseNameForPop.
function _syncPopRulesToHead(bytes32 labelhash, address newHead) internal;
_releasePopRulesSlot
Clears the PopRules slot and the local label bookkeeping when the queue empties (claim, last-relinquish, last-expire).
function _releasePopRulesSlot(bytes32 labelhash) internal;
_onlyRoot
Internal check enforcing a substrate Root origin.
Authorises a call when @custom:function SystemUtils.originIsRoot is true, and
reverts with NotRoot otherwise. msg.sender is deliberately not consulted: a
Root origin has no account behind it, so reading msg.sender traps. The same
applies to anything reachable from an onlyRoot entrypoint.
function _onlyRoot() internal view;
_authorizeUpgrade
Function that should revert when msg.sender is not authorized to upgrade the contract.
Called by
{upgradeToAndCall}.
Normally, this function will use an xref:access.adoc[access control] modifier such as
{Ownable-onlyOwner}.
function _authorizeUpgrade(address) internal onlyOwner {}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner;