A simple namespace on Ethereum named after the smallest unit of ether.
Contract: 0x0000000000696760E15f265e828DB644A0c242EB (Ethereum Mainnet)
Gateway: wei.domains - resolves name.wei.domains to IPFS content
Dapp: wei.domains (hosted via IPFS)
WNS provides .wei names as NFTs (ERC-721). Names can:
- Resolve to an Ethereum address (receive payments)
- Host a website via IPFS contenthash
- Have unlimited free subdomains
- Display as your wallet's identity (reverse resolution)
WNS uses a commit-reveal pattern to prevent frontrunning (similar to ENS):
- Commit - Submit
keccak256(label, owner, secret)and wait 60 seconds - Reveal - Submit the actual name + secret + pay fee
- Commitment expires after 24 hours
Fee (per year by byte length):
1 byte: 0.5 ETH
2 bytes: 0.1 ETH
3 bytes: 0.05 ETH
4 bytes: 0.01 ETH
5+ bytes: 0.0005 ETH
Duration: 1 year, renewable
Token IDs use namehash, similar to ENS:
WEI_NODE = keccak256("wei")
= 0xa82820059d5df798546bcc2985157a77c3eef25eba9ba01899927333efacbd6f
tokenId = keccak256(WEI_NODE || keccak256(label))
For subdomains, recursively hash parent nodes.
Example (JavaScript):
const WEI_NODE = '0xa82820059d5df798546bcc2985157a77c3eef25eba9ba01899927333efacbd6f';
function computeTokenId(label) {
const labelHash = ethers.keccak256(ethers.toUtf8Bytes(label));
return BigInt(ethers.keccak256(ethers.concat([WEI_NODE, labelHash])));
}Unicode includes visually similar characters across scripts (e.g., Latin a vs Cyrillic а). This is a universal challenge for any naming system supporting international characters.
Like ENS and other naming systems, WNS stores raw bytes on-chain and delegates normalization to the client/frontend layer. This is the established pattern in the ecosystem.
-
Future-proof - Normalization standards evolve. ENSIP-15 replaced ENSIP-1, Unicode itself updates yearly. On-chain rules would be frozen forever or require expensive upgrades.
-
Ecosystem alignment - ENS, DNS, and other systems handle normalization at the application layer. Wallets and dapps already implement these checks.
-
International support - Overly restrictive on-chain validation could block legitimate international names. Better to let standards bodies (Unicode, ENSIP) define what's valid.
-
Simplicity - Contract stays minimal, gas-efficient, and auditable.
Frontends (dapps, wallets, explorers) SHOULD:
- Normalize input using ENSIP-15 via
@adraffy/ens-normalize - Warn users about non-normalized names
- Verify before purchase on secondary markets
Example:
import { ens_normalize } from '@adraffy/ens-normalize';
function normalizeLabel(label) {
try {
const normalized = ens_normalize(label);
if (normalized.includes('.')) return null; // No dots in labels
return normalized;
} catch (e) {
return null; // Invalid (confusables, invisible chars, etc.)
}
}The official dapp includes a "verify name" helper:
- Enter a token ID (from OpenSea URL, etc.)
- See the actual on-chain name and byte representation
- Check ENSIP-15 normalization status
- Compare against an expected name
Useful for secondary market purchases or inspecting unfamiliar names.
// Check availability
function isAvailable(string label, uint256 parentId) view returns (bool)
// Get registration fee (by byte length)
function getFee(uint256 length) view returns (uint256)
// Get premium for recently expired names
function getPremium(uint256 tokenId) view returns (uint256)
// Resolve name to address
function resolve(uint256 tokenId) view returns (address)
// Reverse resolve address to name
function reverseResolve(address addr) view returns (string)
// Get contenthash (IPFS, etc.)
function contenthash(uint256 tokenId) view returns (bytes)
// Get text record
function text(uint256 tokenId, string key) view returns (string)
// Get full name (e.g., "sub.name.wei")
function getFullName(uint256 tokenId) view returns (string)
// Compute token ID from name
function computeId(string fullName) pure returns (uint256)// Commit-reveal registration
function commit(bytes32 commitment)
function reveal(string label, bytes32 secret) payable returns (uint256)
// Set resolver address (where payments go)
function setAddr(uint256 tokenId, address addr)
// Set contenthash (for IPFS websites)
function setContenthash(uint256 tokenId, bytes hash)
// Set text record
function setText(uint256 tokenId, string key, string value)
// Set as primary name (reverse resolution)
function setPrimaryName(uint256 tokenId)
// Register subdomain (free, if you own parent)
function registerSubdomain(string label, uint256 parentId) returns (uint256)
// Renew registration
function renew(uint256 tokenId) payable
// Standard ERC-721 transfer
function transferFrom(address from, address to, uint256 tokenId)To host a website at name.wei.domains:
- Pin your site to IPFS (Pinata, web3.storage, etc.)
- Get the CID (
Qm...orbaf...) - Call
setContenthash(tokenId, encodedHash)
Encoding:
// Contenthash = 0xe3 (IPFS namespace) + CID bytes
function encodeContenthash(cid) {
let cidBytes;
if (cid.startsWith('Qm')) {
// CIDv0 -> CIDv1
cidBytes = new Uint8Array([0x01, 0x70, ...base58Decode(cid)]);
} else if (cid.startsWith('baf')) {
// CIDv1 base32
cidBytes = base32Decode(cid.slice(1));
}
return ethers.concat(['0xe3', cidBytes]);
}The Cloudflare Worker at wei.domains:
- Extracts name from subdomain (
name.wei.domains) - Queries contract for contenthash
- Decodes CID and fetches from IPFS
- Serves content with caching
Root domain (wei.domains) resolves to wns.wei (the official dapp).
For efficient batching, use Multicall3:
const MULTICALL3 = '0xcA11bde05977b3631167028862bE2a173976CA11';
const results = await multicall.aggregate3([
{ target: WNS, callData: encodeFunctionData('isAvailable', [name, 0]) },
{ target: WNS, callData: encodeFunctionData('getFee', [byteLength]) },
{ target: WNS, callData: encodeFunctionData('getPremium', [tokenId]) }
]);- Normalize input with ENSIP-15 before registration (same as ENS)
- Use the verification tool or compute expected token IDs when buying on secondary markets
- Display normalization warnings for names that don't pass ENSIP-15
- Link to the official dapp (
wei.domains/#name) for name lookups
- Dapp: https://wei.domains
- Contract: https://etherscan.io/address/0x0000000000696760E15f265e828DB644A0c242EB
- OpenSea: https://opensea.io/collection/wei-name-service
- ENSIP-15: https://docs.ens.domains/ensip/15/
- ens-normalize: https://github.com/adraffy/ens-normalize.js