All pages
Powered by GitBook
1 of 1

Loading...

Controller Contract

The dotHYPEController is the logic layer for domain registration. It manages who can mint, how much they pay, and how names are allocated across phases.

All domain registrations and renewals are routed through the controller; it’s the decision-making contract that sits between users and the registry.

This is where pricing, access rules, signature verification, and allowlist enforcement live.

🔍 What It Does

The Controller handles:

  • Enforcing registration pricing (based on name length and duration)

  • Processing payments in $HYPE (based on USD-pegged prices)

  • Verifying signed requests to prevent front-running (via EIP-712)

  • Checking Merkle proofs for allowlisted mints

  • Managing name reservations (for pre-approved addresses)

Think of it as the programmable access layer for the dotHYPE registry.

💸 Pricing Model

dotHYPE uses a simple but powerful pricing structure:

  • Price is based on name length (e.g., 3-char names cost more than 5+)

  • All prices are denominated in USD

  • Payment is made in $HYPE, converted using an onchain oracle

  • Registration and renewal are priced separately

Example (public mint):

  • 3 characters: $100/year

  • 4 characters: $40/year

  • 5+ characters: $15/year

Pricing can be updated over time by the protocol owner, but logic is hardcoded for length-based tiers.

To fetch the price:

function getPrice(string calldata name, uint256 duration) public view returns (uint256);

✍️ Signature-Based Registration

Most mints use EIP-712 structured data to ensure fair access. This prevents bots from front-running open registrations.

function registerWithSignature(...) external payable returns (uint256);

This flow:

  1. Verifies a signed message from an authorized backend signer

  2. Confirms the nonce hasn't been used

  3. Calculates price and duration

  4. Registers the name through the Registry

Signatures are used in public mint, premium auction, and certain reserved phases.


🌿 Merkle-Based Allowlists

For whitelist and partner-only phases, we use Merkle trees to verify whether a user can register a name:

function registerWithMerkleProof(...) external payable returns (uint256);

Each address on the allowlist can register one name. Proofs are verified onchain. The Merkle root is updated periodically by the owner.


🪪 Reserved Name Access

Some names are explicitly reserved for specific addresses—partners, integrations, or founders.

function registerReservedName(...) external payable returns (uint256);

Only the address that a name is reserved for can register it. No one else can front-run or bypass this.

Admin can assign or remove reservations:

function reserveName(...) external onlyOwner;
function removeReservation(...) external onlyOwner;

🔁 Renewal

Renewals are permissionless. Anyone can renew any name by paying the correct amount.

function renew(string calldata name, uint256 duration) external payable returns (uint256);
  • Duration is in seconds

  • Pricing uses the renewal tier (not the first-year price)


🔐 Payment Handling

The Controller:

  • Calculates price in $USD

  • Converts it to $HYPE using a live price oracle

  • Verifies the user paid enough

  • Refunds any overpayment

  • Sends funds to the treasury or designated recipient

All payments are native token compatible—no need for approval flows.


🛠 Admin Functions

The Controller can be configured by the protocol owner (via multisig):

setAnnualPrice()
setAnnualRenewalPrice()
setRegistry()
setSigner()
setPaymentRecipient()
setPriceOracle()

These functions adjust pricing, set key addresses, and manage access without changing the contract itself.


📡 Events for Tracking

Events emitted for downstream analytics:

  • DomainRegistered

  • DomainRenewed

  • ReservedNameRegistered

  • MerkleProofRegistration

  • SignerUpdated, PaymentRecipientUpdated, PriceOracleUpdated

These can be tracked via Subgraph or block explorer for indexers and dashboards.


🔎 For Developers

If you’re building a dApp or CLI for minting:

  • Use getPrice() to fetch cost before submitting

  • Use registerWithSignature() for standard public minting

  • Use registerWithMerkleProof() for allowlisted flows

You don’t need to interact with the Registry directly—the Controller routes all writes.

Want to mint for users via backend signature? Check our SDK guide or integration examples.

To see how a registered name becomes usable across dApps, dashboards, and wallets, continue to the Resolver Contract →