Connect to Arc
Install viem and create a public client with the settings below. On Arc mainnet, send transaction value and pay gas in native USDC. Convert amounts using 18 decimals.
pnpm add viemimport { createPublicClient, defineChain, http } from 'viem'
export const arc = defineChain({
id: 5042,
name: 'Arc mainnet',
nativeCurrency: { name: 'USD Coin', symbol: 'USDC', decimals: 18 },
rpcUrls: { default: { http: ['https://ans.family/rpc/arc'] } },
blockExplorers: {
default: { name: 'Arc Explorer', url: 'https://arc.exploreme.pro' }
}
})
export const client = createPublicClient({
chain: arc,
transport: http()
})- Chain ID
5042- Native currency
- USDC, 18 decimals
- RPC
https://ans.family/rpc/arc
Address lookup
For input such as alice.arc, lowercase it and strip the suffix before validating the label. Put the suffix back when computing the namehash. Ask the controller for its resolver address rather than assuming that address will stay fixed.
import { namehash, parseAbi, zeroAddress } from 'viem'
import { client } from './arc'
const controller = '0x3Afe007AD24Ce90F17F24C8dC1E712E6bd6000AC'
const controllerAbi = parseAbi([
'function resolver() view returns (address)'
])
const resolverAbi = parseAbi([
'function addr(bytes32 node) view returns (address)'
])
const resolver = await client.readContract({
address: controller,
abi: controllerAbi,
functionName: 'resolver'
})
const address = await client.readContract({
address: resolver,
abi: resolverAbi,
functionName: 'addr',
args: [namehash('alice.arc')]
})
if (address === zeroAddress) throw new Error('Name does not resolve')Treat a zero-address response as a failed lookup: the registration may have expired or lack an address record. Block the send action in that case. Query ANS explicitly; an Ethereum ENS lookup will not find these records.
Registration flow
A purchase has two onchain steps. First publish a commitment that conceals the requested name, then reveal it and pay. This prevents observers from taking the name by copying a pending registration.
Commit the request
Create a random 32-byte secret and retain it locally for the reveal. Pass the label, owner, duration, and secret to
makeCommitment(name, owner, duration, secret). Send the resulting hash tocommit(bytes32).Observe the reveal window
Reveal no earlier than 60 seconds after the commitment. The window closes after 24 hours; after that, begin again with a fresh secret.
Reveal and pay
Submit
registerusing the original commitment inputs. Attach the amount returned byrentPriceas transaction value. Confirmation mints the registration NFT to the owner and sets that wallet as the name’s destination.
import { parseAbi } from 'viem'
import { client } from './arc'
const controller = '0x3Afe007AD24Ce90F17F24C8dC1E712E6bd6000AC'
const abi = parseAbi([
'function available(string name) view returns (bool)',
'function rentPrice(string name, uint256 duration) view returns (uint256)'
])
const oneYear = 365n * 24n * 60n * 60n
const [available, price] = await Promise.all([
client.readContract({
address: controller, abi, functionName: 'available', args: ['alice']
}),
client.readContract({
address: controller, abi, functionName: 'rentPrice', args: ['alice', oneYear]
})
])| Label length | Annual price | Minimum duration |
|---|---|---|
| 3 characters | 100 USDC | 1 year |
| 4 characters | 25 USDC | 1 year |
| 5 to 63 characters | 5 USDC | 1 year |
Change a destination
Address edits are authorized by the owner of the ERC-721 registration. Write the new destination to the resolver. After an NFT transfer, use reclaim when the registry ownership also needs to be updated.
import { namehash, parseAbi } from 'viem'
const resolverAbi = parseAbi([
'function setArcAddress(bytes32 node, address target)'
])
await walletClient.writeContract({
address: '0xCFaaBe54713131E988Eb76948aa6184210EB29dF',
abi: resolverAbi,
functionName: 'setArcAddress',
args: [namehash('alice.arc'), newAddress],
account
})Contract addresses
Begin with the controller address below. It reports the current registry, registrar, and resolver. These protocol contracts use transparent upgradeable proxies.
| Contract | Address | Role |
|---|---|---|
| Controller | 0x3Afe007AD24Ce90F17F24C8dC1E712E6bd6000AC | Entry point for quotes and name purchases |
| Registry | 0x1CB7B317BeCA5FE135A6f761AC9C14a6e9b6B1cd | Maps names to owners and resolvers |
| Registrar | 0xe2dc805E9D6C99CF7E8382eEFC48F71ECF5cAF16 | Holds registration NFTs and expiry dates |
| Resolver | 0xCFaaBe54713131E988Eb76948aa6184210EB29dF | Reads and writes each name’s records |
Rules and limitations
- Accepted names
- Labels must be 3 to 63 characters long and use lowercase ASCII letters, digits, or internal hyphens. Leading and trailing hyphens are rejected.
- After expiry
- Resolution returns zero as soon as registration expires. A renewal grace period follows before another wallet can register the label.
- Admin controls
- The configured ProxyAdmin can upgrade the controller, registry, registrar, and resolver. Fetch their active addresses through the controller when it offers a getter.
- Review status
- No independent contract audit has been published. Automated tests are available, but do not replace your own review.