Skip to content
ArcNS docs
DocsVerified records

Verified records

What the verified flag on an ArcNS address record means, how an owner proves control of an address for a coin type, and the arcns:v1 challenge format.

Every address record ArcNS returns carries a verification flag. This page says exactly what it means, so a wallet or explorer can decide what to show and what to warn about.

What verified means

ValueMeaningWhat to do
verifiedThe owner proved control of this address for this coin type on chain (verified(node, coinType) on the resolver).Show it plainly.
unverifiedA record exists but ownership was never proved for it. It may still be correct; nobody has shown that it is.Show a warning and make the user look twice before sending.

The flag is per coin type. alice.arc can have a verified Arc record and an unverified Bitcoin record at the same time. In the SDK it is Resolved.verification and AddressRecord.verification; in the API it is the boolean addr.verified.

Two things the flag never does:

  • It never turns a controller into a payment address. controller (the SDK) or owner (the API) is who holds the name; the resolvers never fall back to it, verified or not.
  • It never survives an ownership change. Records are keyed by the name's epoch, which bumps on every transfer, so a proof made by a previous owner is unreachable by construction.

Answers read from the pinned peer registry are always unverified: verified is an ArcNS resolver extension, and the peer resolver only exposes the legacy addr(bytes32) record.

How a record becomes verified

For the Arc address itself, the simplest proof is a transaction from that address: buildVerifyAddrSelf proves msg.sender.

await wallet.sendTransaction(buildVerifyAddrSelf({ deployment, name: "alice.arc" }));   // proves the Arc address (msg.sender)

For another chain's address the owner signs a challenge with the wallet that holds that address, then submits the signature on Arc:

import { buildChallenge, generateNonce, encodeProof, buildVerifyAddr } from "@arcns/resolve";
const challenge = buildChallenge({ purpose: "rec", namespace: "arc", label: "alice", coinType: COIN_TYPE.ETH, epoch, chainId: 5042002, registry, nonce: generateNonce() });
// arcns:v1:rec:arc:alice:60:3:5042002:0x…:9f3c…
// the ETH wallet signs `challenge` (EIP-191); then:
buildVerifyAddr({ deployment, name: "alice.arc", chain: "ETH", proof: { signature } });

The challenge format

arcns:v1:rec:arc:alice:60:3:5042002:0x…:nonce
FieldExampleMeaning
arcns:v1scheme and version
purposereca record proof
namespacearchandle, arc or circle
labelalicethe name's label
coin type60ENSIP-9 / ENSIP-11 coin type being proved (BTC 0, ETH 60, SOL 501, ARC 2152525650)
epoch3the name's current epoch; the proof dies with it
chain id5042002Arc testnet
registry0x…the registry the name lives in
nonce9f3c…from generateNonce(); one use

Binding the name, coin type, epoch, chain id and registry into the signed string is what stops a signature from being replayed for a different name, a different chain, or the same name after it changes hands.

Signature forms by chain:

  • ETH (and other EVM coin types): EIP-191 signature over the challenge.
  • BTC: a BIP-137 signature plus the 64-byte uncompressed public key.
  • SOL / X1 (ed25519): signature followed by the public key.

Local pre-checks (verifyEthProofLocal, verifyEthTypedProofLocal, verifyControlProofLocal) let a wallet refuse a doomed transaction before it is sent. Both the EIP-191 and the EIP-712 forms exist while the contracts lane finalises which one the resolver verifies; one is removed before the first tagged release.

Showing it

  • Wallets: verified next to the address, nothing more; unverified as a warning that the user must pass through before "Send" is enabled. See Wallets.
  • Explorers: show the flag per record on the name page and never render an unverified record as if it were confirmed. See Explorers.
  • Agents and machine consumers: treat verification !== "verified" as "do not pay without a human".

Questions

Questions: [email protected].