Introduction
What is Rob Domains and how does it work?
Rob Domains is a decentralized name system built on Robinhood Chain. Every .rob domain is an ERC-721 NFT minted directly to your wallet. No central authority can revoke, reassign, or expire it.
ERC-721 NFT on Robinhood Chain. Yours forever.
Bio, links, and images stored permanently on-chain.
Forward and reverse resolution for wallets and dApps.
Non-custodial peer-to-peer domain trading.
Architecture
How the system components fit together
DomainMarketplace.solDeployedMarketplace Contract
Non-custodial offer/accept marketplace. Holds ETH escrow in-contract. No custody by Rob Domains team.
DomainNFT.solDeployedCore NFT Contract
ERC-721 contract that owns all domain data — name, profile, social links, custom links. Deployed and immutable.
DomainChat.solDeployedChat Contract
Decentralized messaging protocol for domain owners.
RobResolver.solDeployedResolver Contract
Independent resolver for forward/reverse resolution and primary domain registration. Reads DomainNFT via interface.
Design principle: The Resolver is completely independent from the DomainNFT. It interacts through the IDomainNFT interface and never modifies NFT storage. Future upgrades to resolution logic can be deployed as new Resolver contracts without touching the NFT contract.
Smart Contracts
Contract addresses and key interfaces
Robinhood Chain
Contract Addresses
DomainNFT0x37F7ba486afE8Be3C3C70A4FC3eCacC6DD51c6C8LiveDomainMarketplace0xAefec6e65ADE8D95c0Cf69D20e9254556f6cC637LiveDomainChat0xB96eCa3BE710aFC822e2342D0bCae7103371dE81LiveRobResolver0xeDe40500f6047F2Ef8d8F5dec12F096969A1bF47LiveKey DomainNFT Functions
// Minting function isAvailable(string memory domainName) view returns (bool) function mintDomain(string memory domainName) payable returns (uint256) function mintFee() view returns (uint256) // Resolution function getTokenIdByName(string memory domainName) view returns (uint256) function getNameByTokenId(uint256 tokenId) view returns (string) function getFullDomainName(uint256 tokenId) view returns (string) function getDomainsOfOwner(address owner) view returns (uint256[]) // Profile function getProfile(uint256 tokenId) view returns ( string domainName, address owner, string profilePicture, string coverImage, string bio, string background, SocialLink[] socialLinks, CustomLink[] customLinks ) function updateProfile(uint256 tokenId, string profilePicture, string coverImage, string bio, string background)
Key RobResolver Functions
// Primary domain — write (requires ownership) function setPrimaryDomain(uint256 tokenId) external function clearPrimaryDomain() external // Primary domain — read function getPrimaryToken(address wallet) view returns (uint256) function getPrimaryDomain(address wallet) view returns (string) function hasPrimaryDomain(address wallet) view returns (bool) function isPrimaryOwner(address wallet, uint256 tokenId) view returns (bool) // Resolution function reverseResolve(address wallet) view returns ( uint256 tokenId, string domainName, string fullDomain ) function resolve(string domain) view returns ( address owner, uint256 tokenId, string fullDomain ) // Future records (reserved — returns safe defaults now) function getTextRecord(uint256 tokenId, string key) view returns (string) function getAddressRecord(uint256 tokenId, uint256 coinType) view returns (address) function getContentHash(uint256 tokenId) view returns (bytes)
Resolver Standard
How resolution works in the .rob name system
Forward Resolution
Maps a human-readable .rob domain to its owner address and token ID. Delegates directly to the DomainNFT contract — always reflects current on-chain state.
alice.rob ──resolve()──► { owner: "0xAlice...", tokenId: 42, fullDomain: "alice.rob" }Reverse Resolution
Maps a wallet address to its self-designated primary .rob domain. Ownership is re-verified on every call — stale data is never returned.
0xAlice... ──reverseResolve()──► { tokenId: 42, domainName: "alice", fullDomain: "alice.rob" }
If ownership transferred since setPrimaryDomain() was called:
0xAlice... ──reverseResolve()──► { tokenId: 0, domainName: "", fullDomain: "" }Primary Domains
When a wallet owns multiple .rob domains it can designate one as its Primary Domain. This is the domain shown in wallets and block explorers via reverse resolution.
// Set primary — caller must own tokenId resolver.setPrimaryDomain(42); // Clear primary resolver.clearPrimaryDomain(); // Check primary resolver.hasPrimaryDomain(wallet); // → true/false resolver.getPrimaryDomain(wallet); // → "alice" resolver.getPrimaryToken(wallet); // → 42 resolver.isPrimaryOwner(wallet, 42); // → true
Future Record Types
The RobResolver storage layout reserves space for ENS-compatible record types. These are read-only stubs today — they return safe defaults without reverting.
| Record Type | Key / Coin Type | Example | Status |
|---|---|---|---|
| Text record | avatar | ipfs://Qm... | Reserved |
| Text record | description | On-chain identity | Reserved |
| Text record | com.twitter | @alice | Reserved |
| Text record | com.github | alice | Reserved |
| Address record | SLIP-44: 60 (ETH) | 0xAlice... | Reserved |
| Address record | SLIP-44: 0 (BTC) | bc1q... | Reserved |
| Address record | SLIP-44: 501 (SOL) | Gh7k... | Reserved |
| Content hash | IPFS CID / ENS encoding | ipfs://Qm... | Reserved |
| Avatar hash | avatarHash | Qm... | Reserved |
Resolution APIs
HTTP endpoints for resolution, profiles, and ownership
All endpoints are served from the Rob Domains Next.js application. Responses follow the standard envelope:
{
"ok": true,
"data": { ... },
"meta": { "chain": "Robinhood", "chainId": 4663, "timestamp": "2024-01-01T00:00:00Z" }
}
// Errors:
{ "ok": false, "error": "Domain not found or not yet minted", "code": 404 }/api/resolve/:domainForward resolution — maps a .rob domain name to its owner and token ID.
/api/reverse/:walletReverse resolution — maps a wallet address to its primary .rob domain (requires RobResolver).
/api/profile/:domainReturns the full on-chain profile: bio, social links, custom links, images.
/api/token/:tokenIdReturns profile data by ERC-721 token ID.
/api/owner/:walletReturns all .rob domains owned by a wallet.
/api/primary/:walletReturns the primary .rob domain for a wallet (requires RobResolver).
/api/records/:domainReturns all records for a domain: profile fields, social links, text records.
Example Responses
// GET /api/resolve/alice
{
"ok": true,
"data": {
"domain": "alice",
"owner": "0xAbCd...1234",
"tokenId": "42",
"fullDomain": "alice.rob"
},
"meta": { "chain": "Robinhood", "chainId": 4663, "timestamp": "..." }
}
// GET /api/profile/alice
{
"ok": true,
"data": {
"domain": "alice",
"owner": "0xAbCd...1234",
"tokenId": "42",
"fullDomain": "alice.rob",
"profile": {
"bio": "Building on Robinhood Chain",
"profilePicture": "https://...",
"socialLinks": [{ "platform": "twitter", "url": "https://twitter.com/alice", "icon": "twitter" }],
"customLinks": [{ "title": "My Website", "url": "https://alice.xyz" }]
}
}
}
// GET /api/owner/0xAbCd...1234
{
"ok": true,
"data": {
"wallet": "0xAbCd...1234",
"count": 3,
"domains": [
{ "tokenId": "42", "domain": "alice", "fullDomain": "alice.rob" },
{ "tokenId": "57", "domain": "alicedev", "fullDomain": "alicedev.rob" }
]
}
}Agent APIs
AI agent endpoints — status, OpenAPI spec, and unsigned transaction generation
The Agent API provides AI-agent-friendly endpoints for health checks, machine-readable spec discovery, and unsigned transaction payload generation. No authentication is required. Transaction endpoints return payloads only — the user's wallet must sign and broadcast independently.
AI plugin manifest: /.well-known/ai-plugin.json · OpenAPI spec: /agent/docs/openapi.yaml · MCP manifest: /mcp/robdomains-mcp.json
/agent/statusHealth check — returns API status, chain connectivity, and live contract addresses.
/agent/docs/openapi.yamlOpenAPI 3.1 specification (YAML). Import into ChatGPT, Cursor, or any OpenAPI-compatible tool.
/agent/tx/mintGenerate an unsigned mint transaction payload. Body: { domain: string }.
/agent/tx/set-primaryGenerate an unsigned set-primary-domain transaction. Body: { tokenId: number, wallet: string }.
/agent/tx/update-profileGenerate an unsigned update-profile transaction. Body: { tokenId, bio, profilePicture, coverImage, background }.
/agent/tx/transferGenerate an unsigned ERC-721 transfer transaction. Body: { tokenId: number, from: string, to: string }.
Example: Status Response
// GET /agent/status
{
"ok": true,
"status": "operational",
"chain": "Robinhood",
"chainId": 4663,
"contracts": {
"domainNFT": "0x37F7ba486afE8Be3C3C70A4FC3eCacC6DD51c6C8",
"marketplace": "0xAefec6e65ADE8D95c0Cf69D20e9254556f6cC637"
},
"timestamp": "2026-07-21T00:00:00Z"
}Example: Mint Transaction Payload
// POST /agent/tx/mint { "domain": "alice" }
{
"ok": true,
"transaction": {
"to": "0x37F7ba486afE8Be3C3C70A4FC3eCacC6DD51c6C8",
"data": "0x...",
"value": "500000000000000",
"chainId": 4663
},
"domain": "alice",
"fullDomain": "alice.rob",
"mintFee": "0.0005 ETH"
}Future APIs
Planned endpoints — documented now, arriving in upcoming releases
These endpoints are planned and documented here for integrators to prepare against. They will return 501 Not Implemented until the underlying contract or indexer infrastructure is ready.
/api/text/:domain/:keyReturns a text record by key (avatar, email, twitter…)
/api/address/:domain/:coinReturns the address record for a coin type (ETH, BTC, SOL)
/api/avatar/:domainReturns the resolved avatar URL for a domain
/api/contenthash/:domainReturns the IPFS / content hash for a domain
/api/multicallBatch multiple resolution calls in a single HTTP request
/api/batch-resolveResolve multiple domain names in one request
/api/searchFull-text search across registered domains
/api/metadata/:tokenIdERC-721 metadata JSON for OpenSea / wallets
/api/verify/:domain/:walletVerify that a wallet currently owns a domain
/api/statsProtocol statistics: total domains, daily mints, floor price
/api/market/history/:domainHistorical marketplace sales for a domain
/api/market/salesGlobal sales feed ordered by recency
/api/activity/:domainFull on-chain activity log for a domain
/api/qr/:domainReturns a QR code image for a profile URL
/api/og/:domainOpenGraph card image for social sharing
SDK & Examples
Code samples in JavaScript, TypeScript, ethers v6, and viem
Installation
npm install ethers viem @rainbow-me/rainbowkit wagmi
Forward Resolution — ethers v6
import { ethers } from "ethers";
const DOMAIN_NFT = "0x37F7ba486afE8Be3C3C70A4FC3eCacC6DD51c6C8";
const RPC = "https://rpc.mainnet.chain.robinhood.com";
const DOMAIN_NFT_ABI = [
"function getTokenIdByName(string) view returns (uint256)",
"function ownerOf(uint256) view returns (address)",
"function getFullDomainName(uint256) view returns (string)",
];
async function resolve(domain: string) {
const provider = new ethers.JsonRpcProvider(RPC);
const nft = new ethers.Contract(DOMAIN_NFT, DOMAIN_NFT_ABI, provider);
const tokenId = await nft.getTokenIdByName(domain.replace(/\.rob$/, ""));
if (tokenId === 0n) return null;
const owner = await nft.ownerOf(tokenId);
const fullDomain = await nft.getFullDomainName(tokenId);
return { owner, tokenId: tokenId.toString(), fullDomain };
}
const result = await resolve("alice");
console.log(result);
// → { owner: "0xAbCd…", tokenId: "42", fullDomain: "alice.rob" }Reverse Resolution — ethers v6
const RESOLVER_ABI = [
"function reverseResolve(address) view returns (uint256, string, string)",
"function hasPrimaryDomain(address) view returns (bool)",
];
async function reverseResolve(wallet: string) {
const provider = new ethers.JsonRpcProvider(RPC);
const resolver = new ethers.Contract(RESOLVER_ADDRESS, RESOLVER_ABI, provider);
const has = await resolver.hasPrimaryDomain(wallet);
if (!has) return null;
const [tokenId, domainName, fullDomain] = await resolver.reverseResolve(wallet);
return { tokenId: tokenId.toString(), domainName, fullDomain };
}Forward Resolution — viem
import { createPublicClient, http, defineChain } from "viem";
const robinhoodChain = defineChain({
id: 4663,
name: "Robinhood",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: { default: { http: ["https://rpc.mainnet.chain.robinhood.com"] } },
blockExplorers: { default: { name: "Blockscout", url: "https://robinhoodchain.blockscout.com" } },
});
const client = createPublicClient({
chain: robinhoodChain,
transport: http(),
});
const tokenId = await client.readContract({
address: "0x37F7ba486afE8Be3C3C70A4FC3eCacC6DD51c6C8",
abi: [{ name: "getTokenIdByName", type: "function",
inputs: [{ name: "domainName", type: "string" }],
outputs: [{ name: "", type: "uint256" }], stateMutability: "view" }],
functionName: "getTokenIdByName",
args: ["alice"],
});HTTP API — JavaScript fetch
// Forward resolve
const res = await fetch("/api/resolve/alice");
const { data } = await res.json();
console.log(data.owner, data.tokenId);
// Reverse resolve
const r2 = await fetch("/api/reverse/0xAbCd...1234");
const { data: d2 } = await r2.json();
console.log(d2.fullDomain); // "alice.rob"
// Full profile
const r3 = await fetch("/api/profile/alice");
const { data: d3 } = await r3.json();
console.log(d3.profile.bio, d3.profile.socialLinks);
// All domains for a wallet
const r4 = await fetch("/api/owner/0xAbCd...1234");
const { data: d4 } = await r4.json();
console.log(d4.count, d4.domains);Set Primary Domain — ethers v6
const RESOLVER_ABI = [
"function setPrimaryDomain(uint256 tokenId) external",
"function clearPrimaryDomain() external",
];
// Connect a signer (user wallet)
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const resolver = new ethers.Contract(RESOLVER_ADDRESS, RESOLVER_ABI, signer);
// Set token #42 as primary
const tx = await resolver.setPrimaryDomain(42);
await tx.wait();
console.log("Primary domain set on-chain");
// Clear primary domain
const tx2 = await resolver.clearPrimaryDomain();
await tx2.wait();Integration Guides
How to integrate Rob Domains into wallets, explorers, and dApps
Wallet Integration
Display a human-readable .rob name in place of raw wallet addresses using reverse resolution.
- 1.Call GET /api/reverse/{wallet} or reverseResolve() on the RobResolver contract
- 2.If the wallet has a primary domain, display it as "alice.rob" in place of "0xAbCd…"
- 3.Fall back to the shortened address when no primary domain is set
- 4.Cache results for 30–60 seconds; re-fetch on block confirmations
Block Explorer Integration
Show human-readable .rob names on address pages and transaction lists.
- 1.For each address, call GET /api/reverse/{address} to check for a primary domain
- 2.Display "alice.rob" as the label alongside the address
- 3.Link the name to the Rob Domains profile: robdn.com/alice
- 4.For domain pages, call GET /api/profile/{domain} to show profile details
dApp Integration
Resolve .rob names entered by users as recipients or identifiers.
- 1.When a user types a .rob name, call GET /api/resolve/{domain}
- 2.Use the returned owner address for the on-chain transaction
- 3.Display "alice.rob → 0xAbCd…" for transparency before signing
- 4.Always re-verify ownership immediately before sending funds
Profile Lookup
Fetch rich profile data (bio, avatar, social links) for any .rob domain.
- 1.Call GET /api/profile/{domain} to get the full profile
- 2.Render profilePicture as the avatar
- 3.Link socialLinks to their respective platforms
- 4.Use customLinks to build a link-in-bio style display
Payment Systems
Accept .rob domain names as payment destinations.
- 1.Allow users to enter a .rob name in the "Send to" field
- 2.Resolve the name to an address via GET /api/resolve/{domain}
- 3.Confirm the resolved address with the user before submitting
- 4.Re-verify ownership at transaction time to guard against transfers
OpenAPI
Machine-readable API specification
The full OpenAPI 3.1 specification is live and served at /agent/docs/openapi.yaml with Content-Type: application/yaml. Import it into ChatGPT, Cursor, Swagger UI, or any OpenAPI-compatible tool. Below is an abridged view of the Resolution API paths.
openapi: "3.1.0"
info:
title: Rob Domains Resolution API
version: "1.0.0"
description: HTTP API for resolving .rob domain names on Robinhood Chain
servers:
- url: https://robdn.com
description: Production
paths:
/api/resolve/{domain}:
get:
summary: Forward resolution
parameters:
- name: domain
in: path
required: true
schema: { type: string, example: "alice" }
responses:
"200":
description: Resolved domain
content:
application/json:
schema:
$ref: "#/components/schemas/ResolveResponse"
"404":
description: Domain not found
/api/reverse/{wallet}:
get:
summary: Reverse resolution
parameters:
- name: wallet
in: path
required: true
schema: { type: string, example: "0xAbCd...1234" }
responses:
"200":
description: Primary domain for wallet
components:
schemas:
ResolveResponse:
type: object
properties:
ok: { type: boolean }
data:
type: object
properties:
domain: { type: string }
owner: { type: string }
tokenId: { type: string }
fullDomain: { type: string }
meta:
type: object
properties:
chain: { type: string }
chainId: { type: integer }
timestamp: { type: string, format: date-time }Security
How Rob Domains protects user assets
Domain NFTs are held in user wallets. Rob Domains never has custody of your tokens or funds.
The Resolver re-verifies token ownership on every read — stale reverse-resolve data is never returned.
The RobResolver is deployed separately and cannot modify any DomainNFT state.
Offer amounts are held in the DomainMarketplace contract itself, not by any third party.
The Marketplace uses a reentrancy guard pattern. Profile-only functions in DomainNFT carry no ETH risk.
Contracts are deployed without proxy patterns. Code is immutable once deployed — no admin backdoor.
Roadmap
What's live today and what's coming next
Phase 1 — Core
Completed- ERC-721 domain NFT contract
- On-chain profile storage
- Domain minting at 0.0005 ETH
- Social & custom links
- Primary domain (localStorage)
- Animated profile backgrounds
Phase 2 — Marketplace
Completed- Non-custodial marketplace
- Peer-to-peer offers system
- Direct domain transfers
- IPFS metadata via Pinata
- NFT visibility on OpenSea
- QR code profile sharing
- Farcaster mini-app integration
Phase 3 — Resolver & Agent APIs
Completed- RobResolver smart contract
- On-chain primary domain registration
- Forward & reverse resolution
- Resolution HTTP API (/api/resolve, /api/reverse…)
- Developer documentation (this page)
- SDK examples (TypeScript, JavaScript, Python)
- Agent APIs with transaction generation
- OpenAPI 3.1 specification (live)
- AI plugin manifest (/.well-known/ai-plugin.json)
- MCP manifest (/mcp/robdomains-mcp.json)
Phase 4 — Records & Integrations
Planned- Text records (avatar, email, social handles)
- Multi-coin address records (ETH, BTC, SOL)
- Content hash / IPFS records
- ENS compatibility layer
- CCIP-Read support
- Wallet & explorer integrations
- Full OpenAPI spec
Phase 5 — Scale
Planned- Subdomain support
- Batch minting & batch resolution
- Cross-chain bridge support
- Domain portfolio analytics
- Mobile app
- On-chain verification badges