IPopRules

Git Source

Title: Proof of Personhood Rules for Dotns

Proof of personhood interface defining Dotns price calculation, PoP-tier requirements, and base-name reservation rules.

Classifies labels into the PoP tier required for registration and exposes reservation metadata. Length <= 5 is reserved for governance; lengths 6-8 require PopFull unless they carry exactly two trailing digits (PopLite, gateway-issued); lengths >= 9 are open to every caller as NoStatus when they carry zero or exactly two trailing digits. Any one-digit suffix, and any suffix longer than two digits, is invalid; internal digits do not affect classification. Reservations are keyed by the digit-stripped stem so alice and alice42 share a slot. Pricing is a flat per-name deposit on the NoStatus tier; verified PopLite and PopFull users pay zero.

Note: security-contact: admin@parity.io

Functions

classifyName

Classifies a name into a required PoP tier per DotNS naming rules.

Pure; inputs are the label bytes only. Callers use the returned tier to decide which pricing and verification branch applies. Non-canonical labels (anything other than a single lowercase ASCII DNS label) and labels with exactly one or more than two trailing digits both trigger @custom:reverts PopError.

function classifyName(string calldata name)
    external
    pure
    returns (PopStatus requirement, string memory message);

Parameters

NameTypeDescription
namestringThe name label being evaluated.

Returns

NameTypeDescription
requirementPopStatusRequired tier for registration.
messagestringExplanation of the classification result.

updateStartingPrice

Updates the spam-deterrent starting price for NoStatus pricing.

Owner-only; unauthorised callers trigger @custom:reverts OwnableUnauthorizedAccount. newStartingPrice must be strictly positive, otherwise

Note: reverts: PopError. The new value flows into _priceValidatedName on the next pricing read; no redeploy. Emits @custom:emits StartingPriceUpdated with the prior and new values.

function updateStartingPrice(uint256 newStartingPrice) external;

Parameters

NameTypeDescription
newStartingPriceuint256New base price in wei.

reserveBaseName

Creates or refreshes a reservation entry for a PopLite-eligible stem.

Commit-reveal reservation path. Only an authorised controller on the registrar may call this, otherwise @custom:reverts NotRegistry. The caller passes the already-stripped stem; the contract enforces stem shape (no trailing digits) and PopLite-eligibility (length in [6, 8]), and a non-canonical label or a label outside that shape triggers

Note: reverts: PopError. Cross-user collision on a live slot triggers @custom:reverts PopError so the caller cannot silently overwrite another user's reservation; same-user refresh and writes into an empty or expired slot emit @custom:emits BaseNameReserved.

function reserveBaseName(string calldata stem, address user) external;

Parameters

NameTypeDescription
stemstringThe base label with no trailing digits.
useraddressThe address receiving reservation rights.

reserveBaseNameForPop

Writes or refreshes a reservation for a bare base-name stem.

Gateway-driven reservation path used by the PoP controller. Only a controller in the registrar's controllers set may call this, otherwise @custom:reverts NotRegistry. Does not apply the lite-format length window that @custom:function reserveBaseName enforces, but does require the input to be canonical and stem-shaped (no trailing digits); a non-canonical or non-stem label triggers @custom:reverts PopError. If the slot is already live and held by a different user, @custom:reverts PopError so the caller's local bookkeeping and PopRules state stay in lockstep; if it is live for the same user, expiry is refreshed to block.timestamp + MAX_RESERVATION_TIME. Emits

Note: emits: BaseNameReserved on every successful write.

function reserveBaseNameForPop(string calldata stem, address user) external;

Parameters

NameTypeDescription
stemstringThe base label with no trailing digits.
useraddressThe address receiving reservation rights.

releaseBaseName

Clears a reservation for a base-name stem.

Only a controller in the registrar's controllers set may call this, otherwise

Notes:

  • reverts: NotRegistry. Non-canonical or non-stem labels trigger

  • reverts: PopError. Live reservations may only be cleared by the same controller that wrote them; another authorised controller attempting to clear a live slot triggers

  • reverts: PopError. Expired reservations may be cleared by any authorised controller as garbage collection. Used by the PoP controller when a reservation is claimed, relinquished, or a queue head promotion leaves the slot empty. Emits

  • emits: BaseNameReleased once the slot is cleared.

function releaseBaseName(string calldata stem) external;

Parameters

NameTypeDescription
stemstringThe base label whose reservation should be cleared (no trailing digits).

releaseReservationForReclaim

Clears a reservation when the slot owner matches expectedOwner, allowing any registrar-authorised controller (not only the stamping one) to release the slot.

Narrower than @custom:function releaseBaseName: callers must prove they know the slot owner, so cross-controller release is gated on a positive match rather than on caller identity. Intended for the public registrar controller's reclaim path, where a prior occupant has handed the name back to escrow and the new registrant needs the cross-flow guard cleared regardless of which controller originally stamped it. Only a registrar-authorised controller may call this (@custom:reverts NotRegistry). Non-canonical or non-stem labels trigger @custom:reverts PopError. A live reservation whose owner does not match expectedOwner triggers @custom:reverts PopError; expired reservations are cleared regardless. Emits @custom:emits BaseNameReleased.

function releaseReservationForReclaim(string calldata stem, address expectedOwner) external;

Parameters

NameTypeDescription
stemstringThe base label whose reservation should be cleared (no trailing digits).
expectedOwneraddressThe address the caller expects to be the current reservation owner.

getBaseNameReservation

Retrieves reservation information for a base name.

Raw accessor: returns the stored slot regardless of expiry. Use

Notes:

  • function: isBaseNameReserved when live-window semantics are needed. Non-canonical labels trigger

  • reverts: PopError.

function getBaseNameReservation(string calldata baseName)
    external
    view
    returns (address owner, uint64 expires);

Parameters

NameTypeDescription
baseNamestringThe base label without trailing digits.

Returns

NameTypeDescription
owneraddressThe address assigned to the reservation.
expiresuint64UNIX timestamp when the reservation expires.

stripDigits

Returns the bare stem of a label, i.e. the label with any trailing ASCII digits removed.

Mirrors the normalisation that @custom:function reserveBaseName applies before writing a reservation, so callers can look up or release a reservation by passing the full label without re-implementing the digit-stripping rule. Non-canonical labels trigger @custom:reverts PopError.

function stripDigits(string calldata name) external pure returns (string memory stem);

Parameters

NameTypeDescription
namestringFull label (with or without trailing digits).

Returns

NameTypeDescription
stemstringThe label with trailing digits removed.

isBaseNameReserved

Indicates whether a base name is currently reserved.

Applies the live-window predicate to the stored slot so an expired reservation reads as free. Non-canonical labels trigger @custom:reverts PopError.

function isBaseNameReserved(string calldata baseName)
    external
    view
    returns (bool reservedStatus, address owner, uint64 expires);

Parameters

NameTypeDescription
baseNamestringThe base label without trailing digits.

Returns

NameTypeDescription
reservedStatusboolTrue if a live reservation is active.
owneraddressThe reservation holder (zero when not reserved).
expiresuint64UNIX timestamp when the reservation expires.

priceWithCheck

Calculates price with PoP classification and reservation enforcement.

Reverting pricing path used by the commit-reveal controller. Price is a spam deterrent and is significant only for NoStatus users; verified users pay zero. Non-canonical labels, a base stem held live by another user, a governance-reserved label, or a userAddress whose personhood tier does not meet the label's required tier each trigger @custom:reverts PopError.

function priceWithCheck(
    string calldata name,
    address userAddress
)
    external
    view
    returns (PriceWithMeta memory metadata);

Parameters

NameTypeDescription
namestringDomain label.
userAddressaddressRegistering user for the given label.

Returns

NameTypeDescription
metadataPriceWithMetaPrice with PoP requirements and classification.

priceWithoutCheck

Calculates price with PoP classification and reservation metadata, without reverting on conflicts.

Non-reverting counterpart to priceWithCheck: surfaces the same fields, but reports a Reserved status through metadata instead of reverting when the base stem is held by another user. Used by front-ends that need to present a price and eligibility preview without forcing a transaction attempt. Governance-reserved names are not rejected here either; the caller decides what to do. Non-canonical labels still trigger @custom:reverts PopError because the input is malformed rather than just contested.

function priceWithoutCheck(
    string calldata name,
    address userAddress
)
    external
    view
    returns (PriceWithMeta memory metadata);

Parameters

NameTypeDescription
namestringDomain label.
userAddressaddressRegistering user for the given label.

Returns

NameTypeDescription
metadataPriceWithMetaPrice with PoP requirements and classification.

reachFee

Friction fee owed when account reaches into a label tier above its verification level.

Non-zero only when account cannot meet the label's required PoP tier; the value is the flat NoStatus deposit. Acts as cross-payer friction at registration time. Use

Note: function: transferFloor for transfer-time friction, which folds in the sender-tier-downgrade component as well. Non-canonical labels and labels with exactly one or more than two trailing digits trigger @custom:reverts PopError.

function reachFee(string calldata name, address account) external view returns (uint256 fee);

Parameters

NameTypeDescription
namestringDomain label being acted on.
accountaddressAccount whose verification reach is being measured.

transferFloor

Transfer-time friction floor: the greater of the recipient-reach component and the sender-tier-downgrade component.

Returns the flat NoStatus deposit when either (i) the recipient does not meet the label's required tier, or (ii) the recipient's personhood tier is strictly below the sender's. Returns zero when neither condition holds. The two components overlap on pure tier mismatches, so the function takes their maximum rather than their sum to avoid double-charging. Consumed by @custom:function DotnsRegistrar.quoteTransferFee. Non-canonical labels and labels with exactly one or more than two trailing digits trigger @custom:reverts PopError.

function transferFloor(
    string calldata name,
    address from,
    address to
)
    external
    view
    returns (uint256 floor);

Parameters

NameTypeDescription
namestringDomain label being transferred.
fromaddressCurrent holder of the name.
toaddressIncoming holder of the name.

isBaseName

Returns whether name is a base name under PoP rules.

A base name has no trailing digits; lite-person labels always have exactly two trailing digits, so the two spaces are disjoint. Non-canonical labels trigger

Note: reverts: PopError.

function isBaseName(string calldata name) external pure returns (bool isBase);

Parameters

NameTypeDescription
namestringThe label to check.

Returns

NameTypeDescription
isBaseboolTrue when the label has no trailing digits.

price

Calculates registration cost for a label.

Returns zero for any label shorter than 9 characters; lengths >= 9 pay the flat startingPrice deposit. Ignores the caller's personhood status and reservation state. Non-canonical labels trigger @custom:reverts PopError.

function price(string calldata name) external view returns (uint256 cost);

Parameters

NameTypeDescription
namestringDomain label to price.

Returns

NameTypeDescription
costuint256Registration cost in wei.

Events

BaseNameReserved

Emitted when a base name receives a reservation.

event BaseNameReserved(string indexed baseName, address indexed owner, uint64 expires);

Parameters

NameTypeDescription
baseNamestringThe digit-stripped label receiving the reservation.
owneraddressAddress obtaining the reservation right.
expiresuint64UNIX timestamp when the reservation expires.

StartingPriceUpdated

Emitted when the spam-deterrent NoStatus starting price is rotated.

Owner-only setter @custom:function updateStartingPrice; the new value is consumed by _priceValidatedName on the next pricing read.

event StartingPriceUpdated(uint256 oldPrice, uint256 newPrice);

Parameters

NameTypeDescription
oldPriceuint256Previous wei value.
newPriceuint256New wei value.

BaseNameReleased

Emitted when a base-name reservation is cleared.

event BaseNameReleased(string indexed baseName);

Parameters

NameTypeDescription
baseNamestringThe base label whose reservation was released.

Errors

PopError

Thrown when a name violates PoP-tier or reservation requirements.

error PopError(string reason);

Parameters

NameTypeDescription
reasonstringHuman-readable explanation of the failure condition.

NotRegistry

Thrown when a caller is not an authorised controller on the registrar.

error NotRegistry();

Structs

PriceWithMeta

Bundle returned from metadata-aware pricing queries.

struct PriceWithMeta {
    uint256 price;
    PopStatus status;
    PopStatus userStatus;
    string message;
}

Properties

NameTypeDescription
priceuint256Registration cost; typically non-zero only for NoStatus users.
statusPopStatusRequired PoP tier for this name.
userStatusPopStatusCurrent PoP status recorded for the querying user.
messagestringHuman-readable classification description.

Reservation

Reservation metadata for a base name (digits removed).

struct Reservation {
    address owner;
    uint64 expires;
    address controller;
}

Properties

NameTypeDescription
owneraddressAddress holding exclusive claim rights during the reservation window.
expiresuint64UNIX timestamp when the reservation expires.
controlleraddressAddress that wrote the reservation; the only address permitted to release it before expiry.

Enums

PopStatus

Proof-of-Personhood eligibility tier.

NoStatus is the default for unverified users; PopLite and PopFull are the two personhood tiers; Reserved covers both governance-held names and base stems held by another user through the reservation table.

enum PopStatus {
    NoStatus,
    PopLite,
    PopFull,
    Reserved
}