//////////////////////////////
// //
// __ ___ _ _____ //
// \ \ / / \ | |/ ____| //
// \ V /| \| | (___ //
// > < | . ` |\___ \ //
// / . \| |\ |____) | //
// /_/ \_\_| \_|_____/ //
// //
//////////////////////////////
- Overview
- How It Works
2.1 Name Registration
2.2 Name Registration With Authorization
2.3 Name Resolution
2.4 Namespace Registration - How Is XNS Different from ENS?
- XNS Price list
- Contract Address
- Integration Guide for Contract Developers
- Contract Ownership Transfer
- Namespace Owner Transfer
- Privacy Considerations
- License and Deployment Policy
- API
- Developer Notes
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
getNameandgetAddressfunction. - 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.
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.
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,vitalikandvitalik.xare the same and resolve to the same address.
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.
- 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.
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.
Registering an XNS name in a public namespace is straightforward:
- Check Available Namespaces: Browse the XNS price list to find available namespaces and their registration fees (e.g., names within the
xnsnamespace cost 0.001 ETH). - Choose a Name: e.g.,
alice.xns(must not be registered yet). - Register Name: Send a transaction with the required ETH amount to register a name (see
registerNamein API docs). Any excess will be refunded. - Verify Resolution: Wait a few blocks, then verify the name is registered (see
getAddressandgetNamein 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 for EOA
- Name registration for ERC20 token (via constructor)
- Name registration for ERC20 token (via separate
registerNamefunction)
Names can be registered for EOAs directly via Etherscan.
β οΈ Important: Ensure the connected wallet address is the one to be named.
Example 1: Registering bob.xns in the xns namespace (costs 0.001 ETH):

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

Note: As mentioned earlier, bare names are internally mapped to the special namespace
"x". When registering a bare name likevitalik, specify"x"as the namespace.vitalikandvitalik.xare equivalent and resolve to the same address.
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:
- The recipient signs an EIP-712 message authorizing a specific name registration (label, namespace, and recipient address).
- The sponsor calls
registerNameWithAuthorizationwith the recipient's signature and pays the registration fee. - 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
batchRegisterNameWithAuthorizationto register multiple names within the same namespace in a single transaction. See the API documentation for details.
Example scripts:
- Name registration with authorization for EOA
- Name registration with authorization for ERC20 token
- Batch name registration with authorization
XNS provides simple on-chain resolution for names and addresses.
Look up Address from Name: getAddress
- Resolve a name like
vitalik.001orbobto 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.001or justvitalikfor bare names). - Returns an empty string if the address has no name.
Example scripts:
How to register a public namespace:
- 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).
- Register Namespace: Submit a transaction with the required ETH to register the namespace (see
registerPublicNamespacein 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:
- 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).
- Register Namespace: Submit a transaction with the required ETH to register the namespace (see
registerPrivateNamespacein 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:
-
Regular users always pay the standard fees when registering namespaces via
registerPublicNamespaceorregisterPrivateNamespace. -
During the onboarding period (first year after contract deployment), the XNS contract owner can register public and private namespaces at no cost using
registerPublicNamespaceForandregisterPrivateNamespaceFor, respectively, to foster adoption. These are OWNER-only functions that allow registering namespaces for other addresses during the onboarding period. -
Security recommendation: Namespace owners should consider using multisig wallets to reduce the risk of wallet access loss or compromise. This is especially important for public namespace owners who receive ongoing fee rewards, and for private namespace owners who maintain exclusive control over their namespace.
Example scripts:
Namespaces can be registered directly via Etherscan.
π‘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:
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:
Fees earned by namespace owners and the XNS contract owner accumulate within the XNS contract and must be claimed to be withdrawn. Available actions:
- Check pending fees for any address (
getPendingFees) - Claim fees to caller (
claimFeesToSelf) - Claim fees to a different recipient (
claimFees)
Example scripts:
| 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
getNamespaceInfoorgetNamespacePricefunctions.
The official XNS contract is live on Ethereum mainnet at: 0x648E4F05aF2b7eB85109A8dc8AE81D8E006457D8
This contract also owns the XNS "bare name": xns.
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)
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.
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.
// 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 areceive()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
registerNamefunction only works for public namespaces after the exclusivity period (7 days) has ended. For private namespaces, contracts must use Option 3 (EIP-1271).
// 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 areceive()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 callingregisterName. - The
registerNamefunction only works for public namespaces after the exclusivity period (7 days) has ended. For private namespaces, contracts must use Option 3 (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:
- 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
MyContractWalletcontract in this example). - A sponsor calls
registerNameWithAuthorizationon XNS, providing the contract as the recipient. - XNS validates the signature via the contract's
isValidSignaturefunction (EIP-1271). - 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.
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.
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.
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 |
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:
- Current owner calls
transferOwnership(newOwner)to initiate transfer. - Pending owner calls
acceptOwnership()to complete transfer. - 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 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:
- Current namespace owner calls
transferNamespaceOwnership(namespace, newOwner)to initiate transfer. - Pending namespace owner calls
acceptNamespaceOwnership(namespace)to complete transfer. - 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:
- Query pending namespace owner
- Initiate namespace ownership transfer
- Accept namespace ownership transfer
XNS names can enhance privacy when used thoughtfully, but the privacy implications depend on your name choice and how you share it.
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.
- β
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.
- 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
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.
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
- 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.
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.
See API.md for a complete documentation of all XNS contract functions, events, state variables, and types.
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.