IDotnsRegistrar

Git Source

Inherits: IERC721

Title: dotNS Registrar

ERC721-backed ownership for dotNS names with controller-gated registration.

Intentionally minimal and policy-free. Provides ERC721 ownership for registered name token IDs and controller-gated registration; pricing, PoP enforcement, and flow-specific policy live in the controllers. The ERC721 transfer functions carry no fee and are not payable; a soulbound name reverts on every one of them with @custom:reverts NameSoulbound.

Note: security-contact: admin@parity.io

Functions

available

Returns whether a registration call may proceed for id.

Signals two distinct paths to the controller. Returns true when the owner slot is empty (a fresh @custom:function register call may mint) OR when the current owner is the configured escrow and the released position's redeem window has elapsed (the controller must then route through @custom:function IDotnsNameEscrow.reclaim instead of

Notes:

  • function: register, because register calls _mint which rejects existing tokens). All other holders return false. The controller distinguishes the two true cases via @custom:function exists. Escrow custody inside the redeem window returns false: that window belongs to the previous holder, who may still @custom:function IDotnsNameEscrow.redeem the name, and reclaim would revert until it elapses. Clients wanting the exact moment a released name becomes registrable should read redeemableUntil from

  • function: IDotnsNameEscrow.getReleasePosition.

function available(uint256 id) external view returns (bool isAvailable);

register

Registers a name permanently.

Permanence is by construction: there is no expire, renew, or release path on the registrar. Custody only moves via ERC721 transfers (which the registrar polices via the fee-on-transfer hook) or via escrow reclaim. Restricted to authorised controllers (otherwise @custom:reverts NotController) and rejects ids that are not available (otherwise @custom:reverts NameNotAvailable). Emits @custom:emits NameRegistered on success.

When the caller is the address registered under DotnsConstants.POP_CONTROLLER, the name is marked soulbound and becomes permanently non-transferable (see

Note: function: isSoulbound). Provenance is read from the protocol registry at mint time, so no other authorised controller can mint a soulbound name and the PoP controller cannot mint an unlocked one. Public registrations from any other controller stay transferable.

function register(uint256 id, address owner, string calldata label) external;

Parameters

NameTypeDescription
iduint256
owneraddress
labelstringThe human-readable label string (e.g. "alice").

isSoulbound

Returns whether a token is soulbound (PoP-gateway minted and non-transferable).

Durable on-chain marker set once at mint by @custom:function register and never cleared. A true result means every transfer overload reverts with

Note: reverts: NameSoulbound.

function isSoulbound(uint256 tokenId) external view returns (bool soulbound);

Parameters

NameTypeDescription
tokenIduint256The name's token id.

Returns

NameTypeDescription
soulboundboolTrue when the name was minted through the gateway pallet.

exists

Returns whether a given token id has been minted.

function exists(uint256 tokenId) external view returns (bool tokenExists);

addController

Adds an authorised controller.

Typed against the baseline IDotnsController (not a concrete subtype) so a single authorisation surface accepts every controller flavour (commit-reveal, gateway path, future variants) without per-flavour setters. Owner-gated (otherwise

Note: reverts: OwnableUnauthorizedAccount); emits @custom:emits ControllerAdded on success.

function addController(IDotnsController controller) external;

removeController

Removes an authorised controller.

Mirrors the @custom:function addController baseline-typed signature so any registered controller can be revoked through the same entry point. Owner-gated (otherwise

Note: reverts: OwnableUnauthorizedAccount); emits @custom:emits ControllerRemoved on success.

function removeController(IDotnsController controller) external;

controllers

Returns whether controller is currently authorised to call

Note: function: register.

function controllers(IDotnsController controller) external view returns (bool authorised);

Parameters

NameTypeDescription
controllerIDotnsControllerCandidate controller.

Returns

NameTypeDescription
authorisedboolTrue when controller was added via @custom:function addController and has not been removed.

labelOf

Returns the human-readable label a token was registered with.

Canonical state source for the label string; any client that holds a node or tokenId can resolve the original label in one view call without scanning registration events. Returns the empty string when the token does not exist.

function labelOf(uint256 tokenId) external view returns (string memory label);

Events

NameRegistered

Emitted when a name is registered.

event NameRegistered(uint256 indexed id, address indexed owner, bool soulbound);

Parameters

NameTypeDescription
iduint256The token id (namehash node) that was minted.
owneraddressThe address that received the name.
soulboundboolTrue when the name is soulbound: PoP-gateway minted and non-transferable. Lets indexers classify registrations without a per-token @custom:function isSoulbound read.

ControllerAdded

Emitted when a controller is added.

Typed as the shared baseline @custom:contract IDotnsController so the commit-reveal controller and the PoP controller (and any future controller) all fit the same signature without the registrar depending on any specific controller interface.

event ControllerAdded(IDotnsController indexed controller);

ControllerRemoved

Emitted when a controller is removed.

event ControllerRemoved(IDotnsController indexed controller);

Errors

NameNotAvailable

Thrown when a name is already registered.

error NameNotAvailable(uint256 tokenId);

NotController

Thrown when the caller is not an authorised controller.

error NotController(address caller);

EscrowNotConfigured

Thrown when the protocol registry has no escrow address configured.

error EscrowNotConfigured();

ProtocolRegistryRequired

Thrown when @custom:function initialize is called with the zero address as the protocol registry.

error ProtocolRegistryRequired();

UnexpectedValue

Thrown when a mint carries msg.value. Nothing forwards value onward, so attached value would be permanently trapped.

error UnexpectedValue();

InvalidOwner

Thrown when @custom:function register is called with the escrow address as owner, which would mint directly into escrow custody with no @custom:struct ReleasePosition recorded.

error InvalidOwner();

InvalidLabel

Thrown when @custom:function register receives an empty or non-canonical label.

error InvalidLabel();

NameSoulbound

Thrown when a transfer targets a soulbound name.

Soulbound names are minted through the dotNS gateway pallet and are permanently non-transferable. Raised by the _update transfer gate.

error NameSoulbound(uint256 tokenId);

UnsolicitedEscrowDeposit

Thrown when a name is transferred into escrow custody by anything other than the escrow's own release path.

redeem and reclaim, the two calls that return a name from custody, gate on the release position the escrow records before it moves the name, so custody reached any other way has no exit.

Note: function: IDotnsNameEscrow.onERC721Received refuses such a deposit but does not run on a plain transferFrom, which is why the gate is enforced here too.

error UnsolicitedEscrowDeposit(uint256 tokenId);