IDotnsRegistrarController

Git Source

Inherits: IDotnsController

Title: Dotns Registrar Controller

Interface for registering top-level labels using a commit reveal scheme.

Defines allocation only; forward resolution, reverse lookup, pricing mechanics, PoP validation, and store writing are handled by external contracts. Users commit a hash of registration parameters and, after a minimum delay, reveal the same parameters to register. Implementations write the successfully registered name into the user's Store to create an immutable on-chain record that doubles as a quick lookup for all names registered.

Note: security-contact: admin@parity.io

Functions

available

Returns whether a label is available for registration.

Validates the canonical DNS-label shape (otherwise @custom:reverts InvalidLabel) and rejects labels below the minimum-length policy with

Note: reverts: LabelTooShort before checking ERC721 availability on the registrar.

function available(string calldata label) external view returns (bool isAvailable);

makeCommitment

Computes the commitment hash for a registration.

Uses abi.encode so the variable-width label is length-prefixed and the boundary between label and the fixed-width owner, secret, reserved, maxPrice, and pricingVersion fields is unambiguous, binding the commitment to the exact tuple. The price ceiling and cost-model version are part of that tuple, so neither can be altered between commit and reveal.

function makeCommitment(Registration calldata registration)
    external
    pure
    returns (bytes32 commitment);

commit

Submits a commitment for a future registration.

Idempotent over expiry: re-committing an unexpired hash reverts with

Note: reverts: UnexpiredCommitmentExists (front-running guard); a hash whose stored timestamp has passed maxCommitmentAge overwrites the slot so storage cannot be permanently griefed. The expiry boundary is inclusive on the commit side (committedAt + maxCommitmentAge <= block.timestamp overwrites) and exclusive on the reveal side (register rejects at the same instant with @custom:reverts CommitmentTooOld), so the slot is overwritable from exactly the timestamp at which reveal begins rejecting it. Stamps the cost model's current version on the commitment, so the reveal binds to the version live now and rejects a pricingVersion bound to an earlier one with @custom:reverts PricingVersionMismatch. Emits @custom:emits NameCommitted on success.

function commit(bytes32 commitment) external;

register

Registers a name after the commitment delay.

Validates the label shape (otherwise @custom:reverts InvalidLabel), rejects labels below the minimum length policy (@custom:reverts LabelTooShort), and ERC721 availability (otherwise @custom:reverts NameNotAvailable), then consumes the prior commitment, which fails with @custom:reverts CommitmentNotFound when no commitment exists for the supplied registration, @custom:reverts CommitmentTooNew before minCommitmentAge, and

Notes:

  • reverts: CommitmentTooOld past maxCommitmentAge, and finally resolves the configured escrow address from the protocol registry (otherwise

  • reverts: EscrowNotConfigured). Splits on direct vs cross-payer at msg.sender == registration.owner. The direct path runs priceWithCheck (personhood

  • reservation gate) and routes the charge to a refundable escrow deposit owned by registration.owner. The cross-payer path skips the personhood revert in priceWithCheck but applies it directly via @custom:reverts OwnerStatusInsufficient when the owner's recorded tier does not meet the label's required tier, and still rejects governance-reserved labels with @custom:reverts GovernanceReserved and live cross-user stem reservations with @custom:reverts NameReserved. The cross-payer charge is the owner-side registration price; the path applies no separate transfer friction. The charge routes to the escrow protocol fee pot while seeding a zero-amount deposit slot so the release lifecycle stays reachable. The reveal prices the name at the committed pricingVersion, so a model change between commit and reveal leaves the amount unchanged, and rejects a total charge above the committed ceiling with @custom:reverts PriceExceedsMax before checking payment. The caller must supply at least the charge (otherwise @custom:reverts InsufficientValue); any overpayment is pushed back to msg.sender inline and, on failure, credited to the escrow's pull-payment ledger so contract receivers cannot block registration. Emits @custom:emits OverpaymentRefunded on the inline branch, the escrow's own @custom:emits OverpaymentRefunded on the pull fallback, and @custom:emits NameRegistered on success.
function register(Registration calldata registration) external payable;

registerReserved

Registers a granted name after the commitment delay, at zero base cost.

Grant-backed issuance path: skips the PoP price check and the escrow deposit, but reuses the same commit-reveal pipeline so the same anti-front-running guarantees apply. Authority is either a substrate Root dispatch or a grant naming registration.owner on the name whitelist registered under DotnsConstants.NAME_WHITELIST; anything else

Notes:

  • reverts: NameNotGranted, and an unset registry key

  • reverts: WhitelistNotConfigured. The gate reads registration.owner rather than the caller, so a relayer may submit on the beneficiary's behalf: the name can only mint to the granted address, so no caller proof is needed. On the non-Root path the grant is consumed, making it single use; a Root dispatch skips consumption so a governance mint does not spend a grant held by someone else. No reverse record is written. IDotnsReverseResolver.setReverseName overwrites unconditionally and the submitter is not necessarily the beneficiary, so a third party must not be able to relabel another address here. The owner sets their own record through

  • function: IDotnsReverseResolver.claimReverseRecord, which checks ownership. Validates the label shape (otherwise @custom:reverts InvalidLabel) and ERC721 availability (otherwise @custom:reverts NameNotAvailable), then consumes the prior commitment, which fails with @custom:reverts CommitmentNotFound, @custom:reverts CommitmentTooNew, or

  • reverts: CommitmentTooOld under the same conditions as @custom:function register. Emits @custom:emits NameRegistered on success.

function registerReserved(Registration calldata registration) external;

Events

NameCommitted

Emitted when a commitment is submitted.

event NameCommitted(bytes32 indexed commitment);

NameRegistered

Emitted when a name is successfully registered.

event NameRegistered(
    string indexed label,
    bytes32 indexed labelhash,
    address indexed owner,
    uint256 baseCost,
    address store
);

Parameters

NameTypeDescription
labelstring
labelhashbytes32
owneraddress
baseCostuint256The price returned by the oracle for this registration.
storeaddressThe Store instance used to persist an immutable registration record.

OverpaymentRefunded

Emitted when overpayment is refunded to the payer at registration entry.

event OverpaymentRefunded(address indexed payer, uint256 amount);

Errors

NameNotGranted

Thrown when a reserved registration names a label not granted to its owner.

error NameNotGranted(string label, address owner);

Parameters

NameTypeDescription
labelstringThe label being registered.
owneraddressThe intended owner the grant was checked against.

WhitelistNotConfigured

Thrown when the protocol registry has no name whitelist configured.

error WhitelistNotConfigured();

UnexpiredCommitmentExists

Thrown when an unexpired commitment already exists.

error UnexpiredCommitmentExists(bytes32 commitment);

CommitmentNotFound

Thrown when revealing a commitment that does not exist.

error CommitmentNotFound(bytes32 commitment);

CommitmentTooNew

Thrown when a commitment is revealed before the minimum age.

error CommitmentTooNew(bytes32 commitment, uint256 minTime, uint256 currentTime);

CommitmentTooOld

Thrown when a commitment has expired.

error CommitmentTooOld(bytes32 commitment, uint256 maxTime, uint256 currentTime);

NameNotAvailable

Thrown when attempting to register an unavailable name.

error NameNotAvailable(string label);

LabelTooShort

Thrown when a label is below the minimum-length policy.

Distinct from @custom:reverts NameNotAvailable so off-chain consumers can tell a too-short label apart from a name that is already minted.

error LabelTooShort(string label);

Parameters

NameTypeDescription
labelstringCaller-supplied label that failed the minimum-length policy.

InvalidLabel

Thrown when a label is not a canonical lowercase ASCII DNS label.

error InvalidLabel();

InsufficientValue

Thrown when supplied payment is insufficient.

error InsufficientValue();

PriceExceedsMax

Thrown when the total charge exceeds the ceiling the caller committed to.

error PriceExceedsMax(string label, uint256 charged, uint256 maxPrice);

Parameters

NameTypeDescription
labelstringLabel whose charge exceeded the ceiling.
chargeduint256Total charge computed at reveal.
maxPriceuint256Ceiling the caller committed to.

EscrowNotConfigured

Thrown when escrow is not configured in the protocol registry.

error EscrowNotConfigured();

MinCommitmentAgeZero

Thrown when min commitment age is zero, which would allow same-block commit-reveal and defeat the front-running guard.

error MinCommitmentAgeZero();

MaxCommitmentAgeTooLow

Thrown when max commitment age is invalid (must be > minCommitmentAge).

error MaxCommitmentAgeTooLow();

MaxCommitmentAgeTooHigh

Thrown when max commitment age is invalid (exceeds implementation limit).

error MaxCommitmentAgeTooHigh();

Structs

Registration

Parameters used to generate and reveal a commitment.

All fields must match exactly between commitment and reveal.

Note: function: registerReserved does not read this field: that path is gated on a name grant and never writes a reverse record.

struct Registration {
    string label;
    address owner;
    bytes32 secret;
    bool reserved;
    uint256 maxPrice;
    uint256 pricingVersion;
}

Properties

NameTypeDescription
labelstringLabel being registered (e.g. "alice").
owneraddressBeneficiary the registered name is minted to.
secretbytes32Caller-chosen entropy that hides the registration intent in the commit hash; revealed verbatim at registration time.
reservedboolOpts a direct @custom:function register into a default reverse record, set only when the caller registers under their own key and holds no primary yet.
maxPriceuint256Ceiling in wei the caller accepts for this registration; a reveal charged above it reverts, closing the gap between the price at commit and the price at reveal.
pricingVersionuint256Cost-model version the caller committed to; the reveal prices the name at this version, so a model change between commit and reveal leaves the amount unchanged. It must equal the version current when commit ran, which that call stamps on the commitment; a reveal whose pricingVersion differs reverts, so the caller cannot bind an earlier, cheaper version.