Skip to content

Walodja1987/xns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

280 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

XNS – The Name Layer on Ethereum

//////////////////////////////
//                          //
//    __   ___   _  _____   //
//   \ \ / / \ | |/ ____|   //
//    \ V /|  \| | (___     //
//     > < | . ` |\___ \    //
//    / . \| |\  |____) |   //
//   /_/ \_\_| \_|_____/    //
//                          //
//////////////////////////////

Table of contents

  1. Overview
  2. How It Works
    2.1 Name Registration
    2.2 Name Registration With Authorization
    2.3 Name Resolution
    2.4 Namespace Registration
  3. How Is XNS Different from ENS?
  4. XNS Price list
  5. Contract Address
  6. Integration Guide for Contract Developers
  7. Contract Ownership Transfer
  8. Namespace Owner Transfer
  9. Privacy Considerations
  10. License and Deployment Policy
  11. API
  12. Developer Notes

πŸš€ Overview

XNS is an immutable address book for Ethereum. It maps human-readable names to Ethereum addresses so you can send crypto to vitalik.xns instead of 0x8AdEFeb576dcF52F5220709c1B267d89d5208E78. With XNS, applications and wallets can show user-friendly names in place of long hexadecimal addresses, making every Ethereum interaction simpler and safer.

Key properties:

  • Permanent: Each name is irrevocably bound to an Ethereum address; no expiration, no transfer, no resale.
  • Fully on-chain: No off-chain dependencies. Names and addresses can be resolved entirely on-chain via getName and getAddress function.
  • Universal naming: Both EOAs and smart contracts can be named in the same unified registry.
  • Globally unique: Each name is unique across all Ethereum addresses, preventing conflicts like duplicate ERC20 token names.
  • Permissionless namespaces: Anyone can create their own namespace without requiring approval from any central party.
  • Private namespaces: Supports private namespaces where the namespace owner maintains exclusive control over name registrations within their namespace.
  • ETH burning: 80% of registration fees are permanently burned, supporting Ethereum's deflationary mechanism.

Name Format

XNS names follow the format <label>.<namespace>.

Labels and namespaces are subject to the following format rules:

  • Must be 1–20 characters long
  • Must consist only of lowercase letters (a-z), digits (0-9), and hyphens (-)
  • Cannot start or end with -
  • Cannot contain consecutive hyphens (--)
  • "eth" as namespace is disallowed to avoid confusion with ENS

Valid name examples:

  • βœ… alice.xns
  • βœ… vitalik.100x
  • βœ… crypto-degen.yolo
  • βœ… to-the-moon.bull
  • βœ… gm.wen-lambo
  • βœ… 2-rich.4-real

Invalid name examples:

  • ❌ thisisaveryverylongname.xns (label too long)
  • ❌ Name.xns (uppercase in label)
  • ❌ gm@web3.xyz (special character in label)
  • ❌ -name.gm (label cannot start with hyphen)
  • ❌ name-.og (label cannot end with hyphen)
  • ❌ my--name.888 (label cannot have consecutive hyphens)

The same format rules apply to namespaces. For example, --name, $rich, and -ns are all invalid and cannot be registered.

Bare Names

XNS supports bare names, i.e. names without a namespace suffix (e.g., bob, vitalik, alice-walker, 1xy). Bare names are premium names costing 10 ETH per name.

Note: Internally, all bare names are associated with the special namespace "x". That is, vitalik and vitalik.x are the same and resolve to the same address.

Namespaces

XNS features two types of namespaces: public and private.

Public Namespaces:

  • Anyone can register names within a public namespace after a 7-day exclusivity period after namespace creation has ended.
  • During the exclusivity period, only the namespace owner can register or sponsor names.
  • Namespace owners receive 10% of all name registration fees in perpetuity.
  • Registration fee: 50 ETH.

Private Namespaces:

  • Only the namespace owner can register names forever.
  • Namespace owners do not receive fees; all fees go to the XNS contract owner.
  • Registration fee: 10 ETH.

Anyone can register a new namespace by paying the one-time registration fee. The eth namespace is disallowed to avoid confusion with ENS.

ETH Burn and Fee Distribution

  • 80% of ETH sent is burnt via DETH.
  • 20% is credited as fees:
    • Public namespaces: 10% to namespace owner, 10% to XNS contract owner
    • Private namespaces: 20% to XNS owner

Notes:

  • Namespace owners only receive fees from name registrations in their namespace (public namespaces only).
  • All ETH burns are recorded via the DETH contract, a global ETH sink and burn attestation registry. Burns are tracked and verifiable as non-transferrable DETH credits minted at a 1:1 ratio, providing proof of contribution to Ethereum's deflationary mechanism.

πŸ” How Is XNS Different from ENS?

ENS replicates the web2 domain model with a rent-seeking approach:

  • Names expire: Users must renew their names, creating ongoing subscription costs for users.
  • Name sniping: If a user forgets to renew, others can grab their name, especially if it previously received funds. If they don't notice and continue sharing the name, funds will be lost.
  • Transferable names: ENS names are transferable and tradeable, thereby encouraging speculation rather than use as permanent identity.
  • Complex: Unnecessarily complex architecture for the purpose of simple name-to-address mapping.
  • Lack of Ethereum alignment: ENS previously considered launching a separate "namechain" (now cancelled) and has a token that does not provide direct value accrual to ETH holders.

To put it simply: ENS names work like bank account numbers that expire. Forget to renew, and your number is reassigned to a stranger. Keep sharing it without noticing, and every payment goes to the wrong person.

XNS takes a fundamentally different approach:

  • Names are permanent and never expire.
  • Names are non-transferable, discouraging speculation.
  • Aligned with ETH holders: 80 % of registration fees (paid in ETH) are burned, accruing value to ETH holders by reducing the supply. No valueless governance token needed.

Beyond these core differences, XNS offers additional capabilities: permissionless namespace registration (for a fee), support for private namespaces with exclusive control as well as smart contract naming.

✨ How It Works

Name Registration

Registering an XNS name in a public namespace is straightforward:

  1. Check Available Namespaces: Browse the XNS price list to find available namespaces and their registration fees (e.g., names within the xns namespace cost 0.001 ETH).
  2. Choose a Name: e.g., alice.xns (must not be registered yet).
  3. Register Name: Send a transaction with the required ETH amount to register a name (see registerName in API docs). Any excess will be refunded.
  4. Verify Resolution: Wait a few blocks, then verify the name is registered (see getAddress and getName in API docs).

Note: registerName only works for public namespaces after the exclusivity period (7 days) has ended. During the exclusivity period or for private namespaces, namespace owners must use registerNameWithAuthorization even for their own registrations.

Example scripts:

Name Registration via Etherscan

Names can be registered for EOAs directly via Etherscan.

⚠️Important: Ensure the connected wallet address is the one to be named.

image

Example 1: Registering bob.xns in the xns namespace (costs 0.001 ETH): image

Example 2: Registering the bare name vitalik (costs 10 ETH): image

Note: As mentioned earlier, bare names are internally mapped to the special namespace "x". When registering a bare name like vitalik, specify "x" as the namespace. vitalik and vitalik.x are equivalent and resolve to the same address.

Name Registration With Authorization

XNS supports authorized name registration via registerNameWithAuthorization, which allows a third party (sponsor) to pay the registration fee and gas costs while the recipient explicitly authorizes the registration via an EIP-712 signature.

How it works:

  1. The recipient signs an EIP-712 message authorizing a specific name registration (label, namespace, and recipient address).
  2. The sponsor calls registerNameWithAuthorization with the recipient's signature and pays the registration fee.
  3. The name is registered to the recipient's address.

Use cases:

  • Organizations registering names for their team members.
  • Projects airdropping names to their community.
  • Enabling contract wallets (EIP-1271) to register names, as contracts can't send transactions themselves.
  • Any scenario where someone else pays registration fees on behalf of recipients.

Important restrictions:

  • For public namespaces: During the 7-day exclusivity period, only the namespace owner can sponsor registrations.
  • For private namespaces: Only the namespace owner can sponsor registrations forever.

Batch registration:

  • XNS also supports batchRegisterNameWithAuthorization to register multiple names within the same namespace in a single transaction. See the API documentation for details.

Example scripts:

Name Resolution

XNS provides simple on-chain resolution for names and addresses.

Look up Address from Name: getAddress

  • Resolve a name like vitalik.001 or bob to its Ethereum address.
  • Works directly on Etherscan or any Ethereum interface.
  • Returns zero address if the name is not registered.

Look up Name from Address: getName

  • Find the XNS name for any Ethereum address.
  • Returns the full name format (e.g., alice.001 or just vitalik for bare names).
  • Returns an empty string if the address has no name.

Example scripts:

Namespace Registration

How to register a public namespace:

  1. Choose a Namespace: Select an available namespace and set the desired price per name (must be >= 0.001 ETH and a multiple of 0.001 ETH).
  2. Register Namespace: Submit a transaction with the required ETH to register the namespace (see registerPublicNamespace in the API docs). Any excess will be refunded.

Public namespace owners have an exclusive 7-day window to register or sponsor any name within their namespace. After this period, anyone can freely register names via registerName. During the exclusivity period, use registerNameWithAuthorization even for their own registrations.

How to register a private namespace:

  1. Choose a Namespace: Select an available namespace and set the desired price per name (must be >= 0.005 ETH and a multiple of 0.001 ETH).
  2. Register Namespace: Submit a transaction with the required ETH to register the namespace (see registerPrivateNamespace in the API docs). Any excess will be refunded.

The private namespace owner registers names via the authorized flow (see registerNameWithAuthorization in the API docs). This is the only way to register names in private namespaces, including registrations for the namespace owner themselves.

Notes:

Example: Public Namespace Registration via Etherscan

Namespaces can be registered directly via Etherscan.

image

πŸ’‘Note: In the screenshot, 2000000000000000 (in wei) is the registration fee set by the namespace owner for users to pay when registering names in the namespace.

To register a private namespace, use the registerPrivateNamespace function with the same input fields as the public version. The required registration fee is 10 ETH (entered in the first field instead of 50); if more than 10 ETH is sent, the excess will be automatically refunded.

Example scripts:

Querying Namespace Information

Namespace details can be retrieved using getNamespaceInfo. The details include:

  • Price per name
  • Namespace owner address
  • Creation timestamp
  • Whether it's private or public

The exclusivity period can be checked using isInExclusivityPeriod, which returns true if the namespace is still within the 7-day exclusivity window.

Example scripts:

Claiming Fees

Fees earned by namespace owners and the XNS contract owner accumulate within the XNS contract and must be claimed to be withdrawn. Available actions:

Example scripts:

πŸ”₯ XNS Price list

Price Namespaces Example Names
0.001 ETH 0-balance, 1-cent, 123, 314159, 8pm, a-lot, abi, acc, action, address, aggr, agree, allez, alliance, alt, always-winning, ani, apr, auditor, aug, bagholder, banger, banned, believe-in-something, bin, bird, black, blanc, bonk, book, boom, brave, break, broke-bro, browser, buy-high-sell-low, buy-the-dip, by-design, cafe, carpe-diem, carrot, chain, cheater, check-this-out, cheers, cheese, cloud, cold, come-in-and-register, commit, cooking, copium, cozy, crispy, crops, cross, dance, dca, dec, deth, diamond, discount, done, drako, dream, dude, earth, edition, elite, emoji, enum, ethcc, ether, facet, fam, feb, fire, for-real, for-sale, frog, game-over, get-it-done, goal, goat, green, green-candle-lover, green-only, group, guardian, haha, hard-rug, harmony, have-fun, hello, hide, hold-my-beer, honey, hooligan, hopium, horn, hyper, hyperinflation, i-am, i-am-not, i-dont, i-know, i-think, idgaf, idk, indeed, jan, jpg, jul, jun, kek, layer, level, leverage, lion, liquidated, literally, looking-for-a-job, lowcost, mar, married, mate, matrix, max-pain, may, maybe, milk, mint, miracle, mmiwg2slgbtqqiaplus, my-problem, native, nature, nevertheless, no-brainer, no-idea, no-problem, no-war, north, not-a-scam, not-ens, nov, oct, off, office, offside, ok-ok, on-it, online, orange, otc, other, ouais, p2p, p33, panda, peanut, penny, platin, play, pleb, png, poc, pre-rich, probably, purple, race, rails, rainbow, refill, reload, reset, rgb, road, route, rulez, sauce, scam, scared, scout, sep, service, share, ship, shit, sidelined, silver, skill-issue, slow-rug, smile, smoke, snake, snow, soft-rug, south, spartan, spend, stack, stack-too-deep, status, structured, style, svg, synth, tab, talisman, the-end, this-is-fine, thor, thumbs-up, tour-de-finance, transfer, trb, trust-me-bro, ubi, unlimited, unwind, very, victim, virus, we-are-so-back, week, whatever, white, why-not, wolve, x-factor, x2x, xns, yellow, your-problem, zation bob.xns, my-oracle.trb, best.auditor
0.002 ETH 0-9, 16-bit, 24h, 32-bit, 50c, 64-bit, 8-bit, af, afro, after, ago, app, asap, atom, aux, awesome, back, beast, bell, bid, billion, blue, bug, bum, bumpy, can, chef, chick, chip, classic, closed, co2, crash, crew, cxm, day, day0, den, desk, dev, dirt, dj, dnd, drop, east, eco, edit, else, emu, era, ethless, exactly, exs, fan, farm, ffs, flash, flex, flow, freak, frens, fte, ftw, fud, gang, gem, give, glad, gm, gn, go-up, hey, hill, hood, how, hundred, icon, impact, intro, inx, ion, joy, jump, kit, lean, lemon, ley, mail, md, me, mf, million, mind, mini, minus, mono, mont, mr, mrs, nada, nail, never, ngo, nonstop, not, not-me, omg, only, open, or, org, outro, own, pain, path, pearl, pen, pill, pink, pipe, plus, pool, pop, px, rebel, red, renegade, retro, rey, ride, run, rx, sea, sis, so-what, sov, spicy, stfu, stop, sub, tbh, team, the, think, this, time, tion, tn, trader, trillion, twin, verge, volt, wallet, way, west, wish, xau, xgr, xlsx, yea, yes, yet, z12, zeus, zone max.gm, its.me, front.dev
0.003 ETH 00s, 01, 247, 3d, 4d, 80s, 90s, abc, air, amen, any, ash, bad, billy, blade, bold, broker, bruh, bunny, cake, cam, car, cat, chop, coz, craft, crm, cubic, darling, diva, dog, don, donate, dot, dpm, ebr, eez, exe, exo, fly, foo, galaxy, gmd, graph, gum, guy, her, hex, him, ink, intern, jr, lady, land, llm, lloyd, m320, mana, max, mir, moi, mug, nemo, noob, nyk, ok, oops, payme, pinx, plug, ppon, pvd, ram, rnd, rollin, rvy, sax, sci, some, sr, ten, turn, uint256, vyn, wen, wifi, win, www, xly, yan, ymca, zap miss.diva, give.mana, exact.xly
0.004 ETH 046, 100k, 1st, 21m, 365, 58sec, 828, 99pct, a-z, agi, all, all-in, amc, atx, aura, bang, bond, bs, cia, clyo, debt, drift, dunk, dy, dyor, equity, flip, gate, hr, hub, hype, iron, jj, joker, kong, loan, loop, lxl, mania, mlx, mobi, nfa, ngl, ngmi, none, orange21, out, pct, pico, pmf, put, qbit, raw, rock, tetris, uno, veo, vibe, wagmi, wild, wow, wwe, xyu, zai, zaya, zhk bob.wagmi, we.ngmi, numero.uno
0.005 ETH 0xygen, 2xp, 777x, 9-5, acx, algo, arb, babe, bay, buidl, call, club, cow, crown, crv, crypto, elix, fame, fxxk, gtfo, guru, h2o, imo, inf, jewel, jo, love, ly, null, nyc, o3, o7, oz, permabull, pm, polar, pyro, qw, retard, rtx, safe, ser, snap, swap, tg, tokyo, troll, ultra, vn, x64, x86, xeno, xyro, ygg, yolo alice.yolo, jack.buidl, gm.ser
0.006 ETH 4real, a0x, aero, astro, ath, b3z, bag, beatz, bot, bz, dice, etherrock, geo, ice, mars, mfer, mod, ninja, super, vy, xccy wallee.bot
0.007 ETH 007, casino, chad, db, eip-000, fbi, gmc, iq200, rekt, royal, shark, sky, titan, yew crypto.chad, get.rekt
0.008 ETH 1x, anon, ape, bet, daddy, dragon, hash, jackpot, lol, long, neo, octo, og, short, uh, vpn, xd, yq, yzi, zero punk.og, 100x.ape, based.anon
0.009 ETH api, ay, az, gwei, py, rs7, slot-0, xyk give-me.gwei
0.010 ETH 5ff, 7xx, a2a, amb, bd, be, bit, boss, bq, cc, ch, coin, ct, dat, dna, down-99pct, down-bad, down-only, ec, erc, erc20, evm, ez, game, giga, go, gp, gu, hot, it, mc, new, o2, on, one, os, pi, sha256, token, tx, up, up-only, us, web3, what, ws, yy9, zk uni.token, pepe.coin, end.game
0.011 ETH code, ef, ip, xio write.code
0.012 ETH 1024, 2048, 4096, agent, in, pro, xtra clawd.agent
0.013 ETH quant, ypz -
0.015 ETH 128, 256, 512, ai, bull, clan, cool, degen, dex, dope, f33, gg, halo, id, kol, lambo, m8, meme, o8, pepe, perp, prince, princess, rex, rocket, rocks, szn, vault, vega, x8, yoda, zh cyber.bull, dank.meme, defi.vault
0.016 ETH milady, punk glam.milady, anon.punk
0.017 ETH lex, xoxo -
0.018 ETH brrr, oxy printer-goes.brrr
0.019 ETH ooo m.ooo
0.020 ETH 16, 18, 32, 36, 64, ag, alpha, art, ceo, comp, etf, fi, fund, g1, globe, gold, hq, inc, index, king, labs, ltd, lux, ny, pay, prime, queen, rv, rwa, ry, store, tech, vx, world, x7 soros.alpha, de.fi, genesis.labs
0.023 ETH cash jonny.cash
0.025 ETH 0x, 3e, bank, capital, vc my-protocol.0x, a16z.vc, swiss.bank
0.030 ETH 100x pump.100x
0.035 ETH czar crypto.czar
0.040 ETH star -
0.050 ETH 2, 4, 8, a7x, pl4 -
0.055 ETH xxl -
0.067 ETH 67 meme.67
0.069 ETH 69 nice.69
0.200 ETH dao dev.dao
0.589 ETH 589 lucky.589
0.666 ETH 18plus, porn, sex, xxx duck.xxx
0.777 ETH 777 jackpot.777
0.888 ETH 888 lucky.888
0.999 ETH 999 -
1.000 ETH 1, defi myprotocol.defi, one.1
1.500 ETH u, v, y tom-ba.y, vee.v
10.000 ETH x vitalik (bare name)

The "x" namespace is special and associated with bare names. "vitalik.x" is equivalent to "vitalik" (bare name).

Notes:

  • The price list only shows public namespaces.
  • The price list may not be complete as new namespaces can be added over time. If you notice a missing namespace, feel free to open an issue to request an update to the table.
  • Prices on Sepolia may differ from mainnet. To obtain the current price for any namespace, use the getNamespaceInfo or getNamespacePrice functions.

🧾 Contract Address

Ethereum Mainnet

The official XNS contract is live on Ethereum mainnet at: 0x648E4F05aF2b7eB85109A8dc8AE81D8E006457D8

This contract also owns the XNS "bare name": xns.

Sepolia Testnet

For testing purposes, the deployed contract on Sepolia can be used at: 0x708a6a410Ea26E536F6534Ac5c98FDD73a4BFe23

The testnet contract has been parametrized as follows:

  • Public namespace registration fee: 0.05 ether (instead of 50 ether)
  • Private namespace registration fee: 0.01 ether (instead of 10 ether)
  • Namespace owner exclusive period: 300 seconds (instead of 7 days)
  • Onboarding period: 100 days (instead of 365 days)
  • Bare name price: 0.01 ether (instead of 10 ether)

πŸ”§ Integration Guide for Contract Developers

XNS can be integrated into smart contracts, allowing users to identify contracts by a human-readable name (e.g., myprotocol.xns) instead of a long address.

Note: Existing contracts without EIP-1271 support cannot register names retroactively. For contracts that implement EIP-1271, see Option 3 for instructions on how to register names.

This section includes examples of how to name smart contracts on Ethereum, the canonical XNS chain, as well as a guide on using XNS with multi-chain deployments.

Integration on Ethereum

There are three ways to integrate XNS:

Note: The following examples demonstrate XNS integration for contracts that are only deployed on Ethereum. For contracts deployed on multiple chains, see the Using XNS Names with Multi-Chain Deployments section below for important guidance and considerations.

Option 1: Register via Constructor

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IXNS} from "./interfaces/IXNS.sol";

contract MyProtocol {
    constructor(address _xns, string memory label, string memory namespace) payable {
        IXNS(_xns).registerName{value: msg.value}(label, namespace);
    }

    /// @notice Optional: Accept ETH refunds from XNS if excess payment is sent.
    /// Not needed if the correct price is sent, without any excess.
    receive() external payable {}
}

Deploy with the label, namespace, and required payment to register the name during contract creation.

See MockERC20A and the registerNameForERC20A.ts script for an example of how to register a name for an ERC20 token using the constructor method.

Notes:

  • Any excess payment is refunded by XNS to msg.sender, which will be the contract. Be sure to implement a receive() function to accept ETH payments, and provide a way to withdraw any refunded ETH if needed. To avoid receiving refunds altogether, send exactly the required payment when deploying the contract.
  • The registerName function only works for public namespaces after the exclusivity period (7 days) has ended. For private namespaces, contracts must use Option 3 (EIP-1271).

Option 2: Register via Separate Function

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IXNS} from "./interfaces/IXNS.sol";

contract MyProtocol {
    IXNS public immutable xns;

    constructor(address _xns) {
        xns = IXNS(_xns);
    }

    /// @notice Register an XNS name for this contract
    /// @param label The label to register (e.g., "myprotocol")
    /// @param namespace The namespace to register in (e.g., "xns")
    function registerName(string calldata label, string calldata namespace) external payable {
        xns.registerName{value: msg.value}(label, namespace);
    }

    /// @notice Optional: Accept ETH refunds from XNS if excess payment is sent.
    /// Not needed if the correct price is sent, without any excess.
    receive() external payable {}
}

Note: Add access control as needed.

After deployment, call registerName("myprotocol", "xns") with the required payment to register the name.

See MockERC20B and the registerNameForERC20B.ts script for an example of how to register a name for an ERC20 token using the separate registerName function approach.

Notes:

  • Any excess payment is refunded by XNS to msg.sender, which will be the contract. Be sure to implement a receive() function to accept ETH payments, and provide a way to withdraw any refunded ETH if needed. To avoid receiving refunds altogether, send exactly the required payment when calling registerName.
  • The registerName function only works for public namespaces after the exclusivity period (7 days) has ended. For private namespaces, contracts must use Option 3 (EIP-1271).

Option 3: Sponsored Registration via EIP-1271

For contracts that implement EIP-1271, someone else can sponsor the name registration. This is the only way for contracts to register names in private namespaces and public namespaces during the exclusivity period.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract MyContractWallet {
    using ECDSA for bytes32;
    
    address public owner;
    bytes4 public constant MAGIC_VALUE = bytes4(0x1626ba7e);
    bytes4 public constant INVALID_SIGNATURE = bytes4(0xffffffff);

    constructor(address _owner) {
        owner = _owner;
    }

    /// @notice EIP-1271 function to validate signatures
    /// @param hash The message hash that was signed
    /// @param signature The signature to validate
    /// @return magicValue Returns MAGIC_VALUE if signature is valid
    function isValidSignature(bytes32 hash, bytes memory signature) 
        external 
        view 
        returns (bytes4 magicValue) 
    {
        address signer = hash.recover(signature);
        if (signer == owner) {
            return MAGIC_VALUE;
        }
        return INVALID_SIGNATURE;
    }
}

How it works:

  1. The contract (or its owner) signs an EIP-712 message authorizing the name registration. The recipient in the authorization must be the contract's address itself (the address of the MyContractWallet contract in this example).
  2. A sponsor calls registerNameWithAuthorization on XNS, providing the contract as the recipient.
  3. XNS validates the signature via the contract's isValidSignature function (EIP-1271).
  4. The contract is assigned a name. The sponsor pays the registration fee.

Use cases:

  • Any smart contract that want to be named
  • Contracts that can't send transactions themselves
  • Contracts wanting to register names in private namespaces (required)
  • Allow others to pay for a contract's name registration

Note: The contract must implement EIP-1271's isValidSignature function. The sponsor pays all fees and gas costs. Unlike Options 1 and 2 where receive() is optional (needed only if excess payment is sent), Option 3 does not need a receive() function because any refunds go to the sponsor (the transaction sender), not to the contract.

See MockERC20C and the registerNameWithAuthorizationForERC20C.ts script for an example of how to register a name for an ERC20 token using the EIP-1271 method.

Using XNS Names with Multi-Chain Deployments

This section is intended for teams that:

  • Deploy the same contract to multiple chains
  • Ensure the contract has the same address across those chains (e.g. using CREATE2)
  • Deploy at least one instance on Ethereum mainnet
  • Want to use an XNS name as a human-readable identifier in documentation, dashboards, and address books instead of raw hexadecimal addresses

Ethereum is the source of truth for XNS names. Other chains do not resolve XNS names on-chain, but reference them off-chain for clarity.

Deployment Pattern

The recommended deployment pattern is to add a dedicated registerName function to the contract that performs XNS name registration on Ethereum mainnet (chainId = 1) and reverts on other chains. After deployment, invoke registerName on Ethereum mainnet to link the XNS name to the contract address.

Example:

contract YourContract {
    // ... Contract code ...
    
    function registerName(string calldata label, string calldata namespace) external payable {
        require(block.chainid == 1, "XNS only available on Ethereum mainnet");
        xns.registerName{value: msg.value}(label, namespace);
    }
}

Note: Add access control as needed.

Documentation and Address Books

When publishing contract addresses, use the XNS name (e.g., myprotocol.xns) if the contract address matches the Ethereum deployment. If the address is different on another chain, use the raw address instead.

Example:

Network XNS name / Address
Ethereum / Arbitrum / Optimism / Base myprotocol.xns
Avalanche 0x1234…5678

πŸ” Contract Ownership Transfer

The XNS contract uses OpenZeppelin's Ownable2Step for 2-step contract ownership transfers. The initial owner is set at deployment and can be transferred using the following process:

Ownership Transfer Process:

  1. Current owner calls transferOwnership(newOwner) to initiate transfer.
  2. Pending owner calls acceptOwnership() to complete transfer.
  3. Only after acceptance does the new owner gain control.

Cancellation:

  • The current owner can cancel a pending transfer by calling transferOwnership(address(0)).
  • Alternatively, the owner can overwrite a pending transfer by calling transferOwnership(differentAddress) again.

Fee Accounting: Ownership transfers do not migrate already-accrued _pendingFees. Any fees accumulated before acceptOwnership() remain claimable by the previous owner address. Only fees accrued after acceptance are credited to the new owner address.

Example scripts:

πŸ” Namespace Owner Transfer

Namespace owners can transfer their namespace (and future fee streams) using a 2-step process (transferNamespaceOwnership β†’ acceptNamespaceOwnership), following the same pattern as contract ownership transfer.

Namespace Owner Transfer Process:

  1. Current namespace owner calls transferNamespaceOwnership(namespace, newOwner) to initiate transfer.
  2. Pending namespace owner calls acceptNamespaceOwnership(namespace) to complete transfer.
  3. Only after acceptance does the new namespace owner gain control.

Cancellation:

  • The current namespace owner can cancel a pending transfer by calling transferNamespaceOwnership(namespace, address(0)).
  • Alternatively, the namespace owner can overwrite a pending transfer by calling transferNamespaceOwnership(namespace, differentAddress) again.

Fee Accounting: Namespace owner transfers do not migrate already-accrued _pendingFees. Any fees accumulated before acceptNamespaceOwnership() remain claimable by the previous namespace owner address. Only fees accrued after acceptance are credited to the new namespace owner address.

Example scripts:

πŸ”’ Privacy Considerations

XNS names can enhance privacy when used thoughtfully, but the privacy implications depend on your name choice and how you share it.

Off-Chain Communication Benefit

Traditional Ethereum addresses (e.g., 0x8AdEFeb576dcF52F5220709c1B267d89d5208E78) are long hexadecimal strings that are typically shared through digital channels like email, messaging apps, or social media. This creates a digital trail that links your identity to your address, which can be monitored, analyzed, and potentially used for surveillance or correlation attacks.

With XNS, you can share addresses off-chain (verbally or in person) using memorable names like alice.xns or 1x45.xns. The counterparty can easily remember and use the name without needing to copy-paste a long address, reducing digital traces that link your identity to your address.

Name Choice Matters

⚠️ Important: The privacy benefit is conditional and depends on your name choice:

  • βœ… Privacy-enhancing: Using pseudonymous names (e.g., 1x45.xns, alice.xns, crypto123.xns) that don't reveal your real identity, combined with off-chain sharing, can reduce identity-address correlation.
  • ❌ Privacy-reducing: Using identifiable names (e.g., frank-walter.xns, john-smith.xns) that reveal your real identity can actually worsen privacy compared to random addresses, as they create a direct, permanent link between your name and address on-chain.

Best Practices for Privacy-Conscious Users

  • Use pseudonymous or random-looking names that don't reveal your identity
  • Share names off-chain (verbally or in person) when possible
  • Avoid using your real name, email, social media handles (e.g., @yourhandle), or other identifiable information in your XNS name
  • Consider the privacy implications before choosing a name, as names are permanent and non-transferable

πŸ“„ License and Deployment Policy

XNS is licensed under the Business Source License 1.1 (BUSL-1.1).

This choice is intentional and motivated by technical and user-safety considerations, not by a desire to restrict innovation.

Why BUSL?

XNS is an identity and naming primitive. Names like alice.x or bankless are meant to be globally unique, permanent, and unambiguous.

Allowing unrestricted third-party deployments of the XNS registry on other chains would lead to:

  • the same name resolving to different addresses on different networks
  • phishing and social-engineering risks
  • user confusion about which contract deployment defines the canonical name-to-address mapping

For identity infrastructure, this is unacceptable.

The BUSL license ensures that:

  • there is a single canonical XNS registry on Ethereum
  • users can safely rely on name-address mappings
  • the mental model of XNS remains simple and trustworthy

What Is Allowed?

  • Reading the code
  • Auditing the code
  • Building tools, wallets, indexers, and integrations
  • Importing and using the public interfaces
  • Non-production and research use

Interfaces and auxiliary files are intentionally kept under permissive licenses (MIT) to enable ecosystem adoption.

Open Source Commitment

In line with BUSL-1.1, this codebase will automatically transition to an open-source license after the specified Change Date.

However, even after the Change Date, XNS remains Ethereum-canonical. The identity, meaning, and trust of XNS names derive from the original deployment on Ethereum mainnet and its immutable history.

Deployments of this code on other chains after the Change Date are not recognized as XNS and do not share any continuity, guarantees, or identity with the canonical registry.

XNS does not support cross-chain name equivalence.

πŸ“š API

See API.md for a complete documentation of all XNS contract functions, events, state variables, and types.

πŸ”§ Developer Notes

See the Developer Notes for design decisions, code style guidelines, governance considerations, and known limitations. This document is primarily intended for auditors and developers working on the XNS contract.

About

No description, website, or topics provided.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors