@monadns/sdk 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -14
- package/dist/index.cjs +76 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -10
- package/dist/index.d.ts +63 -10
- package/dist/index.js +72 -6
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +146 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +55 -1
- package/dist/react.d.ts +55 -1
- package/dist/react.js +144 -1
- package/dist/react.js.map +1 -1
- package/package.json +3 -3
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.ts","../src/resolve.ts","../src/client.ts","../src/constants.ts","../src/react-write.ts","../src/write.ts"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport {\n resolveName,\n lookupAddress,\n getTextRecord,\n getAvatarUrl,\n} from './resolve';\nimport type { MNSClientConfig } from './client';\n\nexport type { MNSClientConfig };\n\n/**\n * Reverse resolution hook: address → .mon name\n *\n * @example\n * ```tsx\n * function Profile({ address }: { address: string }) {\n * const { name, loading } = useMNSName(address)\n * return <span>{loading ? '...' : name ?? address}</span>\n * }\n * ```\n */\nexport function useMNSName(\n address: string | undefined,\n config?: MNSClientConfig,\n) {\n const [name, setName] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!address || !address.startsWith('0x') || address.length !== 42) {\n setName(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n lookupAddress(address, config)\n .then((n) => {\n if (!cancelled) setName(n);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [address]);\n\n return { name, loading, error };\n}\n\n/**\n * Forward resolution hook: .mon name → address\n *\n * @example\n * ```tsx\n * function Lookup() {\n * const { address, loading } = useMNSAddress('alice.mon')\n * return <span>{loading ? 'Resolving...' : address}</span>\n * }\n * ```\n */\nexport function useMNSAddress(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [address, setAddress] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setAddress(null);\n return;\n }\n const fullName = name.endsWith('.mon') ? name : `${name}.mon`;\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n resolveName(fullName, config)\n .then((a) => {\n if (!cancelled) setAddress(a);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n return { address, loading, error };\n}\n\n/**\n * Display name hook: .mon name if available, otherwise truncated address\n *\n * @example\n * ```tsx\n * function Badge({ address }: { address: string }) {\n * const { displayName, monName } = useMNSDisplay(address)\n * return (\n * <span className={monName ? 'text-purple-400' : 'text-gray-500'}>\n * {displayName}\n * </span>\n * )\n * }\n * ```\n */\nexport function useMNSDisplay(\n address: string | undefined,\n config?: MNSClientConfig,\n) {\n const { name, loading, error } = useMNSName(address, config);\n const truncated = address\n ? `${address.slice(0, 6)}...${address.slice(-4)}`\n : '';\n\n return {\n displayName: name || truncated,\n monName: name,\n loading,\n error,\n };\n}\n\n/**\n * On-demand resolver hook: for input fields accepting names or addresses\n *\n * @example\n * ```tsx\n * function SendForm() {\n * const { resolve, address, name, loading, error } = useMNSResolve()\n * return (\n * <div>\n * <input placeholder=\"Address or .mon name\" onChange={(e) => resolve(e.target.value)} />\n * {loading && <span>Resolving...</span>}\n * {address && <span>→ {address}</span>}\n * </div>\n * )\n * }\n * ```\n */\nexport function useMNSResolve(config?: MNSClientConfig) {\n const [address, setAddress] = useState<string | null>(null);\n const [name, setName] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const resolve = useCallback(async (input: string) => {\n const trimmed = input.trim();\n setError(null);\n\n if (!trimmed) {\n setAddress(null);\n setName(null);\n return;\n }\n\n if (trimmed.startsWith('0x') && trimmed.length === 42) {\n setAddress(trimmed);\n setLoading(true);\n const n = await lookupAddress(trimmed, config);\n setName(n);\n setLoading(false);\n return;\n }\n\n const fullName = trimmed.endsWith('.mon') ? trimmed : `${trimmed}.mon`;\n setName(fullName);\n setLoading(true);\n\n try {\n const addr = await resolveName(fullName, config);\n setAddress(addr);\n if (!addr) setError(`${fullName} not found`);\n } catch (e: any) {\n setError(e.message);\n setAddress(null);\n } finally {\n setLoading(false);\n }\n }, []);\n\n return { resolve, address, name, loading, error };\n}\n\n/**\n * Text record hook: get metadata like avatar, URL, twitter handle\n *\n * @example\n * ```tsx\n * function Avatar({ name }: { name: string }) {\n * const { value } = useMNSText(name, 'avatar')\n * return value ? <img src={value} /> : null\n * }\n * ```\n */\nexport function useMNSText(\n name: string | undefined,\n key: string,\n config?: MNSClientConfig,\n) {\n const [value, setValue] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setValue(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getTextRecord(name, key, config)\n .then((v) => {\n if (!cancelled) setValue(v);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name, key]);\n\n return { value, loading, error };\n}\n\n/**\n * Avatar URL hook: resolves avatar from text record, handling IPFS and NFT formats\n *\n * @example\n * ```tsx\n * function Avatar({ name }: { name: string }) {\n * const { url, loading } = useMNSAvatar(name)\n * if (loading) return <div className=\"animate-pulse w-10 h-10 rounded-full bg-gray-700\" />\n * return url ? <img src={url} className=\"w-10 h-10 rounded-full\" /> : null\n * }\n * ```\n */\nexport function useMNSAvatar(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [url, setUrl] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setUrl(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getAvatarUrl(name, config)\n .then((u) => {\n if (!cancelled) setUrl(u);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n return { url, loading, error };\n}\n\n// Write hooks\nexport {\n useRegistrationInfo,\n useMNSRegister,\n useMNSTextRecords,\n useMNSAddr,\n} from './react-write';\n","import { namehash } from 'viem';\nimport { getMNSClient, type MNSClientConfig } from './client';\nimport {\n MNS_REGISTRY,\n ZERO_ADDRESS,\n registryAbi,\n resolverAbi,\n} from './constants';\n\n// ─── Cache ─────────────────────────────────────────────────────\n\nconst nameCache = new Map<string, { value: string | null; ts: number }>();\nconst addrCache = new Map<string, { value: string | null; ts: number }>();\n\nconst CACHE_TTL = 60_000; // 1 minute\n\nfunction getCached(\n cache: Map<string, { value: string | null; ts: number }>,\n key: string,\n) {\n const entry = cache.get(key);\n if (entry && Date.now() - entry.ts < CACHE_TTL) return entry.value;\n return undefined;\n}\n\n// ─── Forward Resolution ────────────────────────────────────────\n\n/**\n * Resolve a .mon name to an address.\n *\n * @param name - Full name including .mon (e.g. \"alice.mon\")\n * @param config - Optional client configuration\n * @returns The resolved address, or null if not found\n *\n * @example\n * ```ts\n * import { resolveName } from '@monadns/sdk'\n *\n * const address = await resolveName('alice.mon')\n * // '0xa05a8BF1eda5bbC2b3aCAF03D04f77bD7d66Cc47'\n * ```\n */\nexport async function resolveName(\n name: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const key = name.toLowerCase();\n const cached = getCached(addrCache, key);\n if (cached !== undefined) return cached;\n\n try {\n const client = getMNSClient(config);\n const node = namehash(key) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [node],\n });\n\n if (resolver === ZERO_ADDRESS) {\n addrCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n\n const addr = await client.readContract({\n address: resolver,\n abi: resolverAbi,\n functionName: 'addr',\n args: [node],\n });\n\n const result = addr === ZERO_ADDRESS ? null : addr;\n addrCache.set(key, { value: result, ts: Date.now() });\n return result;\n } catch {\n addrCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n}\n\n// ─── Reverse Resolution ────────────────────────────────────────\n\n/**\n * Look up the primary .mon name for an address.\n *\n * @param address - A 0x-prefixed Monad address\n * @param config - Optional client configuration\n * @returns The primary name (e.g. \"alice.mon\"), or null\n *\n * @example\n * ```ts\n * import { lookupAddress } from '@monadns/sdk'\n *\n * const name = await lookupAddress('0xa05a8BF1...')\n * // 'alice.mon'\n * ```\n */\nexport async function lookupAddress(\n address: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const key = address.toLowerCase();\n const cached = getCached(nameCache, key);\n if (cached !== undefined) return cached;\n\n try {\n const client = getMNSClient(config);\n const reverseNode = namehash(\n `${key.slice(2)}.addr.reverse`,\n ) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [reverseNode],\n });\n\n if (resolver === ZERO_ADDRESS) {\n nameCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n\n const name = await client.readContract({\n address: resolver,\n abi: resolverAbi,\n functionName: 'name',\n args: [reverseNode],\n });\n\n const result = name || null;\n nameCache.set(key, { value: result, ts: Date.now() });\n return result;\n } catch {\n nameCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n}\n\n// ─── Text Records ──────────────────────────────────────────────\n\n/**\n * Get a text record for a .mon name.\n *\n * @param name - Full name including .mon\n * @param key - The text record key (e.g. \"avatar\", \"url\", \"com.twitter\")\n * @param config - Optional client configuration\n *\n * @example\n * ```ts\n * const avatar = await getTextRecord('alice.mon', 'avatar')\n * const twitter = await getTextRecord('alice.mon', 'com.twitter')\n * ```\n */\nexport async function getTextRecord(\n name: string,\n key: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n try {\n const client = getMNSClient(config);\n const node = namehash(name.toLowerCase()) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [node],\n });\n\n if (resolver === ZERO_ADDRESS) return null;\n\n const value = await client.readContract({\n address: resolver,\n abi: resolverAbi,\n functionName: 'text',\n args: [node, key],\n });\n\n return value || null;\n } catch {\n return null;\n }\n}\n\n// ─── Helpers ───────────────────────────────────────────────────\n\n/**\n * Get a display-friendly name for an address.\n * Returns the .mon name if set, otherwise a truncated address.\n *\n * @example\n * ```ts\n * const display = await getDisplayName('0xa05a8BF1...')\n * // 'alice.mon' or '0xa05a...Cc47'\n * ```\n */\nexport async function getDisplayName(\n address: string,\n config?: MNSClientConfig,\n): Promise<string> {\n const name = await lookupAddress(address, config);\n if (name) return name;\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n\n/**\n * Smart resolver — accepts either a .mon name or a raw address.\n * Useful for input fields where users can type either.\n *\n * @returns The resolved address, or null if invalid/not found\n *\n * @example\n * ```ts\n * const addr = await resolveInput('alice.mon') // resolves name\n * const addr = await resolveInput('alice') // tries alice.mon\n * const addr = await resolveInput('0xa05a...') // passes through\n * ```\n */\nexport async function resolveInput(\n input: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const trimmed = input.trim();\n if (!trimmed) return null;\n\n if (trimmed.startsWith('0x') && trimmed.length === 42) return trimmed;\n if (trimmed.endsWith('.mon')) return resolveName(trimmed, config);\n\n // Try appending .mon\n return resolveName(`${trimmed}.mon`, config);\n}\n\n/**\n * Check if a .mon name is registered.\n *\n * @example\n * ```ts\n * const taken = await isRegistered('alice.mon')\n * ```\n */\nexport async function isRegistered(\n name: string,\n config?: MNSClientConfig,\n): Promise<boolean> {\n const addr = await resolveName(name, config);\n return addr !== null;\n}\n\n/**\n * Get a resolved avatar URL for a .mon name.\n *\n * Handles multiple avatar formats:\n * - Direct HTTPS URLs: returned as-is\n * - IPFS URIs (ipfs://...): resolved via public gateway\n * - NFT references (eip155:chainId/erc721:contract/tokenId): fetches tokenURI and extracts image\n *\n * @param name - Full name including .mon\n * @param config - Optional client configuration\n * @returns A usable HTTPS URL, or null\n *\n * @example\n * ```ts\n * const avatarUrl = await getAvatarUrl('alice.mon')\n * // 'https://example.com/avatar.png'\n * ```\n */\nexport async function getAvatarUrl(\n name: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const raw = await getTextRecord(name, 'avatar', config);\n if (!raw) return null;\n\n // Direct HTTP(S) URL\n if (raw.startsWith('http://') || raw.startsWith('https://')) {\n return raw;\n }\n\n // IPFS\n if (raw.startsWith('ipfs://')) {\n const hash = raw.slice(7);\n return `https://ipfs.io/ipfs/${hash}`;\n }\n\n // NFT reference: eip155:{chainId}/erc721:{contract}/{tokenId}\n // or eip155:{chainId}/erc1155:{contract}/{tokenId}\n const nftMatch = raw.match(\n /^eip155:(\\d+)\\/(erc721|erc1155):0x([a-fA-F0-9]{40})\\/(\\d+)$/,\n );\n if (nftMatch) {\n try {\n const client = getMNSClient(config);\n const contract = `0x${nftMatch[3]}` as `0x${string}`;\n const tokenId = BigInt(nftMatch[4]);\n\n const tokenUriAbi = [\n {\n name: nftMatch[2] === 'erc721' ? 'tokenURI' : 'uri',\n type: 'function',\n inputs: [{ name: 'tokenId', type: 'uint256' }],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n ] as const;\n\n let tokenUri = (await client.readContract({\n address: contract,\n abi: tokenUriAbi,\n functionName: nftMatch[2] === 'erc721' ? 'tokenURI' : 'uri',\n args: [tokenId],\n })) as string;\n\n // Resolve IPFS tokenURI\n if (tokenUri.startsWith('ipfs://')) {\n tokenUri = `https://ipfs.io/ipfs/${tokenUri.slice(7)}`;\n }\n\n // Fetch metadata JSON and extract image\n const res = await fetch(tokenUri);\n const metadata = await res.json();\n let image = metadata.image || metadata.image_url || null;\n\n if (image && image.startsWith('ipfs://')) {\n image = `https://ipfs.io/ipfs/${image.slice(7)}`;\n }\n\n return image;\n } catch {\n return null;\n }\n }\n\n // data: URIs\n if (raw.startsWith('data:')) {\n return raw;\n }\n\n return null;\n}\n\n/**\n * Clear the internal resolution cache.\n * Useful after a new registration.\n */\nexport function clearCache() {\n nameCache.clear();\n addrCache.clear();\n}\n","import {\n createPublicClient,\n http,\n type PublicClient,\n type Chain,\n type Transport,\n} from 'viem';\nimport { monad } from 'viem/chains';\n\nexport type MNSClientConfig = {\n /** Custom RPC URL. Defaults to the public Monad RPC. */\n rpcUrl?: string;\n /** Existing viem PublicClient to reuse instead of creating a new one. */\n client?: PublicClient<Transport, Chain>;\n};\n\nlet defaultClient: PublicClient<Transport, Chain> | null = null;\n\n/**\n * Get or create the MNS public client.\n * Reuses a singleton by default; pass config to override.\n */\nexport function getMNSClient(\n config?: MNSClientConfig,\n): PublicClient<Transport, Chain> {\n if (config?.client) return config.client;\n\n if (config?.rpcUrl) {\n return createPublicClient({\n chain: monad,\n transport: http(config.rpcUrl),\n });\n }\n\n if (!defaultClient) {\n defaultClient = createPublicClient({\n chain: monad,\n transport: http(),\n });\n }\n\n return defaultClient;\n}\n","export const MNS_REGISTRY =\n '0x13f963486e741c8d3fcdc0a34a910920339a19ce' as const;\nexport const MNS_PUBLIC_RESOLVER =\n '0xa2eb94c88e55d944aced2066c5cec9b759801f97' as const;\nexport const MNS_CONTROLLER =\n '0x98866c55adbc73ec6c272bb3604ddbdee3f282a8' as const;\n\nexport const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as const;\n\nexport const registryAbi = [\n {\n name: 'resolver',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n] as const;\n\nexport const resolverAbi = [\n {\n name: 'addr',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n name: 'name',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n {\n name: 'text',\n type: 'function',\n inputs: [\n { name: 'node', type: 'bytes32' },\n { name: 'key', type: 'string' },\n ],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n] as const;\n","'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport {\n getRegistrationInfo,\n getRegisterTx,\n getSetTextTx,\n getSetAddrTx,\n TEXT_RECORD_KEYS,\n type RegistrationInfo,\n} from './write';\nimport type { MNSClientConfig } from './client';\n\nexport { TEXT_RECORD_KEYS };\nexport type { RegistrationInfo };\n\n/**\n * Hook to get registration info (price, availability, freebie status).\n * Use this to build a registration UI before the user submits.\n *\n * @example\n * ```tsx\n * function RegisterPage() {\n * const [name, setName] = useState('')\n * const { address } = useAccount()\n * const { info, loading, error } = useRegistrationInfo(name, address)\n *\n * return (\n * <div>\n * <input value={name} onChange={(e) => setName(e.target.value)} />\n * {info?.available && (\n * <p>{info.isFreebie ? 'FREE!' : `${formatEther(info.price)} MON`}</p>\n * )}\n * </div>\n * )\n * }\n * ```\n */\nexport function useRegistrationInfo(\n label: string | undefined,\n userAddress: string | undefined,\n durationYears = 1,\n config?: MNSClientConfig,\n) {\n const [info, setInfo] = useState<RegistrationInfo | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!label || label.length < 3 || !userAddress) {\n setInfo(null);\n setError(\n label && label.length < 3 ? 'Name must be at least 3 characters' : null,\n );\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n const timer = setTimeout(() => {\n getRegistrationInfo(label, userAddress, durationYears, config)\n .then((i) => {\n if (!cancelled) setInfo(i);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n }, 300); // debounce\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [label, userAddress, durationYears]);\n\n return { info, loading, error };\n}\n\n/**\n * Hook to register a .mon name.\n * Returns a prepare function that gives you tx params for wagmi's writeContract.\n *\n * @example\n * ```tsx\n * const { prepare, loading, error } = useMNSRegister()\n * const { writeContract, data: hash } = useWriteContract()\n *\n * const handleRegister = async () => {\n * const tx = await prepare('alice', address)\n * if (tx) writeContract(tx)\n * }\n * ```\n */\nexport function useMNSRegister(config?: MNSClientConfig) {\n const [tx, setTx] = useState<Awaited<\n ReturnType<typeof getRegisterTx>\n > | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const prepare = useCallback(\n async (label: string, ownerAddress: string, durationYears = 1) => {\n setLoading(true);\n setError(null);\n setTx(null);\n\n try {\n const txParams = await getRegisterTx(\n label,\n ownerAddress,\n durationYears,\n config,\n );\n setTx(txParams);\n return txParams;\n } catch (e: any) {\n setError(e.message);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [],\n );\n\n return { prepare, tx, loading, error };\n}\n\n/**\n * Hook to set text records (avatar, url, twitter, etc.)\n *\n * @example\n * ```tsx\n * const { setAvatar, setTwitter } = useMNSTextRecords()\n * const { writeContract } = useWriteContract()\n *\n * writeContract(setAvatar('alice.mon', 'https://example.com/pic.png'))\n * ```\n */\nexport function useMNSTextRecords() {\n const setTextRecord = useCallback(\n (name: string, key: string, value: string) => {\n return getSetTextTx(name, key, value);\n },\n [],\n );\n\n const setAvatar = useCallback((name: string, url: string) => {\n return getSetTextTx(name, 'avatar', url);\n }, []);\n\n const setUrl = useCallback((name: string, url: string) => {\n return getSetTextTx(name, 'url', url);\n }, []);\n\n const setTwitter = useCallback((name: string, handle: string) => {\n return getSetTextTx(name, 'com.twitter', handle);\n }, []);\n\n const setGithub = useCallback((name: string, handle: string) => {\n return getSetTextTx(name, 'com.github', handle);\n }, []);\n\n const setDiscord = useCallback((name: string, handle: string) => {\n return getSetTextTx(name, 'com.discord', handle);\n }, []);\n\n const setDescription = useCallback((name: string, desc: string) => {\n return getSetTextTx(name, 'description', desc);\n }, []);\n\n return {\n setTextRecord,\n setAvatar,\n setUrl,\n setTwitter,\n setGithub,\n setDiscord,\n setDescription,\n textRecordKeys: TEXT_RECORD_KEYS,\n };\n}\n\n/**\n * Hook to update the address a name points to.\n *\n * @example\n * ```tsx\n * const { setAddr } = useMNSAddr()\n * const { writeContract } = useWriteContract()\n *\n * writeContract(setAddr('alice.mon', '0xnewaddress...'))\n * ```\n */\nexport function useMNSAddr() {\n const setAddr = useCallback((name: string, addr: string) => {\n return getSetAddrTx(name, addr);\n }, []);\n\n return { setAddr };\n}\n","import { namehash } from 'viem';\nimport { getMNSClient, type MNSClientConfig } from './client';\nimport { MNS_CONTROLLER, MNS_PUBLIC_RESOLVER } from './constants';\n\n/**\n * MNS Write Helpers\n *\n * These return transaction parameters ({ address, abi, functionName, args, value })\n * that you pass to wagmi's writeContract or any wallet client.\n * The user signs with their own wallet.\n */\n\n// ─── ABIs ──────────────────────────────────────────────────────\n\nexport const controllerReadAbi = [\n {\n name: 'available',\n type: 'function',\n inputs: [{ name: 'label', type: 'string' }],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n name: 'rentPrice',\n type: 'function',\n inputs: [\n { name: 'label', type: 'string' },\n { name: 'duration', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n name: 'hasClaimedFreebie',\n type: 'function',\n inputs: [{ name: 'user', type: 'address' }],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n] as const;\n\nexport const controllerWriteAbi = [\n {\n name: 'register',\n type: 'function',\n inputs: [\n { name: 'label', type: 'string' },\n { name: 'owner', type: 'address' },\n { name: 'duration', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'payable',\n },\n] as const;\n\nexport const resolverWriteAbi = [\n {\n name: 'setText',\n type: 'function',\n inputs: [\n { name: 'node', type: 'bytes32' },\n { name: 'key', type: 'string' },\n { name: 'value', type: 'string' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n {\n name: 'setAddr',\n type: 'function',\n inputs: [\n { name: 'node', type: 'bytes32' },\n { name: 'a', type: 'address' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n] as const;\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport type RegistrationInfo = {\n available: boolean;\n price: bigint;\n isFreebie: boolean;\n hasClaimed: boolean;\n duration: bigint;\n label: string;\n};\n\n// ─── Registration ──────────────────────────────────────────────\n\nconst ONE_YEAR = BigInt(365 * 24 * 60 * 60);\n\n/**\n * Get all info needed before registration.\n *\n * @example\n * ```ts\n * const info = await getRegistrationInfo('alice', userAddress)\n * // { available: true, price: 96831564n..., isFreebie: true, ... }\n * ```\n */\nexport async function getRegistrationInfo(\n label: string,\n userAddress: string,\n durationYears = 1,\n config?: MNSClientConfig,\n): Promise<RegistrationInfo> {\n const client = getMNSClient(config);\n const duration = ONE_YEAR * BigInt(durationYears);\n\n const [available, price, hasClaimed, balance] = await Promise.all([\n client.readContract({\n address: MNS_CONTROLLER,\n abi: controllerReadAbi,\n functionName: 'available',\n args: [label],\n }),\n client.readContract({\n address: MNS_CONTROLLER,\n abi: controllerReadAbi,\n functionName: 'rentPrice',\n args: [label, duration],\n }),\n client.readContract({\n address: MNS_CONTROLLER,\n abi: controllerReadAbi,\n functionName: 'hasClaimedFreebie',\n args: [userAddress as `0x${string}`],\n }),\n client.getBalance({ address: userAddress as `0x${string}` }),\n ]);\n\n const isFreebie = balance >= 10n * 10n ** 18n && !hasClaimed;\n\n return { available, price, isFreebie, hasClaimed, duration, label };\n}\n\n/**\n * Get transaction parameters for registering a .mon name.\n * Pass the result to wagmi's writeContract.\n *\n * @example\n * ```ts\n * const tx = await getRegisterTx('alice', userAddress)\n * writeContract(tx)\n * ```\n */\nexport async function getRegisterTx(\n label: string,\n ownerAddress: string,\n durationYears = 1,\n config?: MNSClientConfig,\n) {\n const info = await getRegistrationInfo(\n label,\n ownerAddress,\n durationYears,\n config,\n );\n\n if (!info.available) {\n throw new Error(`${label}.mon is not available`);\n }\n\n return {\n address: MNS_CONTROLLER,\n abi: controllerWriteAbi,\n functionName: 'register' as const,\n args: [label, ownerAddress as `0x${string}`, info.duration] as const,\n value: info.isFreebie ? 0n : info.price,\n gas: 3_000_000n,\n _meta: {\n label,\n isFreebie: info.isFreebie,\n price: info.price,\n duration: info.duration,\n },\n };\n}\n\n// ─── Text Records ──────────────────────────────────────────────\n\n/**\n * Get transaction parameters for setting a text record.\n * The connected user must own the name.\n *\n * @example\n * ```ts\n * const tx = getSetTextTx('alice.mon', 'avatar', 'https://example.com/pic.png')\n * writeContract(tx)\n * ```\n */\nexport function getSetTextTx(name: string, key: string, value: string) {\n const node = namehash(\n name.endsWith('.mon') ? name : `${name}.mon`,\n ) as `0x${string}`;\n\n return {\n address: MNS_PUBLIC_RESOLVER,\n abi: resolverWriteAbi,\n functionName: 'setText' as const,\n args: [node, key, value] as const,\n };\n}\n\n/**\n * Get transaction parameters for setting the address record.\n */\nexport function getSetAddrTx(name: string, addr: string) {\n const node = namehash(\n name.endsWith('.mon') ? name : `${name}.mon`,\n ) as `0x${string}`;\n\n return {\n address: MNS_PUBLIC_RESOLVER,\n abi: resolverWriteAbi,\n functionName: 'setAddr' as const,\n args: [node, addr as `0x${string}`] as const,\n };\n}\n\nexport const TEXT_RECORD_KEYS = {\n avatar: 'avatar',\n url: 'url',\n description: 'description',\n email: 'email',\n twitter: 'com.twitter',\n github: 'com.github',\n discord: 'com.discord',\n telegram: 'org.telegram',\n} as const;\n"],"mappings":"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","names":["import_react","import_viem","import_viem"]}
|
|
1
|
+
{"version":3,"sources":["../src/react.ts","../src/resolve.ts","../src/client.ts","../src/constants.ts","../src/react-write.ts","../src/write.ts"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport {\n resolveName,\n lookupAddress,\n getTextRecord,\n getAvatarUrl,\n getOwner,\n getResolver,\n getExpiry,\n} from './resolve';\nimport type { MNSClientConfig } from './client';\n\nexport type { MNSClientConfig };\n\n/**\n * Reverse resolution hook: address → .mon name\n *\n * @example\n * ```tsx\n * function Profile({ address }: { address: string }) {\n * const { name, loading } = useMNSName(address)\n * return <span>{loading ? '...' : name ?? address}</span>\n * }\n * ```\n */\nexport function useMNSName(\n address: string | undefined,\n config?: MNSClientConfig,\n) {\n const [name, setName] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!address || !address.startsWith('0x') || address.length !== 42) {\n setName(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n lookupAddress(address, config)\n .then((n) => {\n if (!cancelled) setName(n);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [address]);\n\n return { name, loading, error };\n}\n\n/**\n * Forward resolution hook: .mon name → address\n *\n * @example\n * ```tsx\n * function Lookup() {\n * const { address, loading } = useMNSAddress('alice.mon')\n * return <span>{loading ? 'Resolving...' : address}</span>\n * }\n * ```\n */\nexport function useMNSAddress(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [address, setAddress] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setAddress(null);\n return;\n }\n const fullName = name.endsWith('.mon') ? name : `${name}.mon`;\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n resolveName(fullName, config)\n .then((a) => {\n if (!cancelled) setAddress(a);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n return { address, loading, error };\n}\n\n/**\n * Display name hook: .mon name if available, otherwise truncated address\n *\n * @example\n * ```tsx\n * function Badge({ address }: { address: string }) {\n * const { displayName, monName } = useMNSDisplay(address)\n * return (\n * <span className={monName ? 'text-purple-400' : 'text-gray-500'}>\n * {displayName}\n * </span>\n * )\n * }\n * ```\n */\nexport function useMNSDisplay(\n address: string | undefined,\n config?: MNSClientConfig,\n) {\n const { name, loading, error } = useMNSName(address, config);\n const truncated = address\n ? `${address.slice(0, 6)}...${address.slice(-4)}`\n : '';\n\n return {\n displayName: name || truncated,\n monName: name,\n loading,\n error,\n };\n}\n\n/**\n * On-demand resolver hook: for input fields accepting names or addresses\n *\n * @example\n * ```tsx\n * function SendForm() {\n * const { resolve, address, name, loading, error } = useMNSResolve()\n * return (\n * <div>\n * <input placeholder=\"Address or .mon name\" onChange={(e) => resolve(e.target.value)} />\n * {loading && <span>Resolving...</span>}\n * {address && <span>→ {address}</span>}\n * </div>\n * )\n * }\n * ```\n */\nexport function useMNSResolve(config?: MNSClientConfig) {\n const [address, setAddress] = useState<string | null>(null);\n const [name, setName] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const resolve = useCallback(async (input: string) => {\n const trimmed = input.trim();\n setError(null);\n\n if (!trimmed) {\n setAddress(null);\n setName(null);\n return;\n }\n\n if (trimmed.startsWith('0x') && trimmed.length === 42) {\n setAddress(trimmed);\n setLoading(true);\n const n = await lookupAddress(trimmed, config);\n setName(n);\n setLoading(false);\n return;\n }\n\n const fullName = trimmed.endsWith('.mon') ? trimmed : `${trimmed}.mon`;\n setName(fullName);\n setLoading(true);\n\n try {\n const addr = await resolveName(fullName, config);\n setAddress(addr);\n if (!addr) setError(`${fullName} not found`);\n } catch (e: any) {\n setError(e.message);\n setAddress(null);\n } finally {\n setLoading(false);\n }\n }, []);\n\n return { resolve, address, name, loading, error };\n}\n\n/**\n * Text record hook: get metadata like avatar, URL, twitter handle\n *\n * @example\n * ```tsx\n * function Avatar({ name }: { name: string }) {\n * const { value } = useMNSText(name, 'avatar')\n * return value ? <img src={value} /> : null\n * }\n * ```\n */\nexport function useMNSText(\n name: string | undefined,\n key: string,\n config?: MNSClientConfig,\n) {\n const [value, setValue] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setValue(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getTextRecord(name, key, config)\n .then((v) => {\n if (!cancelled) setValue(v);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name, key]);\n\n return { value, loading, error };\n}\n\n/**\n * Avatar URL hook: resolves avatar from text record, handling IPFS and NFT formats\n *\n * @example\n * ```tsx\n * function Avatar({ name }: { name: string }) {\n * const { url, loading } = useMNSAvatar(name)\n * if (loading) return <div className=\"animate-pulse w-10 h-10 rounded-full bg-gray-700\" />\n * return url ? <img src={url} className=\"w-10 h-10 rounded-full\" /> : null\n * }\n * ```\n */\nexport function useMNSAvatar(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [url, setUrl] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setUrl(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getAvatarUrl(name, config)\n .then((u) => {\n if (!cancelled) setUrl(u);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n return { url, loading, error };\n}\n\n/**\n * Owner hook: get the owner address of a .mon name\n *\n * @example\n * ```tsx\n * function OwnerInfo({ name }: { name: string }) {\n * const { owner, loading } = useMNSOwner(name)\n * if (loading) return <div>Loading...</div>\n * return <div>Owner: {owner}</div>\n * }\n * ```\n */\nexport function useMNSOwner(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [owner, setOwner] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setOwner(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getOwner(name, config)\n .then((o) => {\n if (!cancelled) setOwner(o);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n return { owner, loading, error };\n}\n\n/**\n * Resolver hook: get the resolver contract address for a .mon name\n *\n * @example\n * ```tsx\n * function ResolverInfo({ name }: { name: string }) {\n * const { resolver, loading } = useMNSResolver(name)\n * return <div>Resolver: {resolver}</div>\n * }\n * ```\n */\nexport function useMNSResolver(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [resolver, setResolver] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setResolver(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getResolver(name, config)\n .then((r) => {\n if (!cancelled) setResolver(r);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n return { resolver, loading, error };\n}\n\n/**\n * Expiry hook: get expiration info for a .mon name\n *\n * @example\n * ```tsx\n * function ExpiryInfo({ name }: { name: string }) {\n * const { expiry, expiryDate, daysUntilExpiry, isExpired, loading } = useMNSExpiry(name)\n * if (loading) return <div>Loading...</div>\n * if (isExpired) return <div className=\"text-red-500\">Expired!</div>\n * return <div>Expires in {daysUntilExpiry} days</div>\n * }\n * ```\n */\nexport function useMNSExpiry(\n name: string | undefined,\n config?: MNSClientConfig,\n) {\n const [expiry, setExpiry] = useState<number | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!name) {\n setExpiry(null);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n getExpiry(name, config)\n .then((e) => {\n if (!cancelled) setExpiry(e);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [name]);\n\n const expiryDate = expiry ? new Date(expiry * 1000) : null;\n const daysUntilExpiry = expiry\n ? Math.floor((expiry * 1000 - Date.now()) / (1000 * 60 * 60 * 24))\n : null;\n const isExpired = expiry ? expiry * 1000 < Date.now() : null;\n\n return { expiry, expiryDate, daysUntilExpiry, isExpired, loading, error };\n}\n\n// Write hooks\nexport {\n useRegistrationInfo,\n useMNSRegister,\n useMNSTextRecords,\n useMNSAddr,\n} from './react-write';\n","import { namehash, keccak256, toBytes } from 'viem';\nimport { getMNSClient, type MNSClientConfig } from './client';\nimport {\n MNS_REGISTRY,\n MNS_BASE_REGISTRAR,\n ZERO_ADDRESS,\n registryAbi,\n resolverAbi,\n} from './constants';\n\n// ─── Cache ─────────────────────────────────────────────────────\n\nconst nameCache = new Map<string, { value: string | null; ts: number }>();\nconst addrCache = new Map<string, { value: string | null; ts: number }>();\n\nconst CACHE_TTL = 60_000; // 1 minute\n\nfunction getCached(\n cache: Map<string, { value: string | null; ts: number }>,\n key: string,\n) {\n const entry = cache.get(key);\n if (entry && Date.now() - entry.ts < CACHE_TTL) return entry.value;\n return undefined;\n}\n\n// ─── Forward Resolution ────────────────────────────────────────\n\n/**\n * Resolve a .mon name to an address.\n *\n * @param name - Full name including .mon (e.g. \"alice.mon\")\n * @param config - Optional client configuration\n * @returns The resolved address, or null if not found\n *\n * @example\n * ```ts\n * import { resolveName } from '@monadns/sdk'\n *\n * const address = await resolveName('alice.mon')\n * // '0xa05a8BF1eda5bbC2b3aCAF03D04f77bD7d66Cc47'\n * ```\n */\nexport async function resolveName(\n name: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const key = name.toLowerCase();\n const cached = getCached(addrCache, key);\n if (cached !== undefined) return cached;\n\n try {\n const client = getMNSClient(config);\n const node = namehash(key) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [node],\n });\n\n if (resolver === ZERO_ADDRESS) {\n addrCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n\n const addr = await client.readContract({\n address: resolver,\n abi: resolverAbi,\n functionName: 'addr',\n args: [node],\n });\n\n const result = addr === ZERO_ADDRESS ? null : addr;\n addrCache.set(key, { value: result, ts: Date.now() });\n return result;\n } catch {\n addrCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n}\n\n// ─── Reverse Resolution ────────────────────────────────────────\n\n/**\n * Look up the primary .mon name for an address.\n *\n * @param address - A 0x-prefixed Monad address\n * @param config - Optional client configuration\n * @returns The primary name (e.g. \"alice.mon\"), or null\n *\n * @example\n * ```ts\n * import { lookupAddress } from '@monadns/sdk'\n *\n * const name = await lookupAddress('0xa05a8BF1...')\n * // 'alice.mon'\n * ```\n */\nexport async function lookupAddress(\n address: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const key = address.toLowerCase();\n const cached = getCached(nameCache, key);\n if (cached !== undefined) return cached;\n\n try {\n const client = getMNSClient(config);\n const reverseNode = namehash(\n `${key.slice(2)}.addr.reverse`,\n ) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [reverseNode],\n });\n\n if (resolver === ZERO_ADDRESS) {\n nameCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n\n const name = await client.readContract({\n address: resolver,\n abi: resolverAbi,\n functionName: 'name',\n args: [reverseNode],\n });\n\n const result = name || null;\n nameCache.set(key, { value: result, ts: Date.now() });\n return result;\n } catch {\n nameCache.set(key, { value: null, ts: Date.now() });\n return null;\n }\n}\n\n// ─── Text Records ──────────────────────────────────────────────\n\n/**\n * Get a text record for a .mon name.\n *\n * @param name - Full name including .mon\n * @param key - The text record key (e.g. \"avatar\", \"url\", \"com.twitter\")\n * @param config - Optional client configuration\n *\n * @example\n * ```ts\n * const avatar = await getTextRecord('alice.mon', 'avatar')\n * const twitter = await getTextRecord('alice.mon', 'com.twitter')\n * ```\n */\nexport async function getTextRecord(\n name: string,\n key: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n try {\n const client = getMNSClient(config);\n const node = namehash(name.toLowerCase()) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [node],\n });\n\n if (resolver === ZERO_ADDRESS) return null;\n\n const value = await client.readContract({\n address: resolver,\n abi: resolverAbi,\n functionName: 'text',\n args: [node, key],\n });\n\n return value || null;\n } catch {\n return null;\n }\n}\n\n// ─── Ownership & Registry Info ─────────────────────────────────\n\n/**\n * Get the owner of a .mon name.\n *\n * @param name - Full name including .mon (e.g. \"alice.mon\")\n * @param config - Optional client configuration\n * @returns The owner address, or null if not registered\n *\n * @example\n * ```ts\n * const owner = await getOwner('alice.mon')\n * // '0xa05a8BF1eda5bbC2b3aCAF03D04f77bD7d66Cc47'\n * ```\n */\nexport async function getOwner(\n name: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n try {\n const client = getMNSClient(config);\n const node = namehash(name.toLowerCase()) as `0x${string}`;\n\n const owner = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'owner',\n args: [node],\n });\n\n return owner === ZERO_ADDRESS ? null : owner;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the resolver address for a .mon name.\n *\n * @param name - Full name including .mon\n * @param config - Optional client configuration\n * @returns The resolver contract address, or null if not set\n *\n * @example\n * ```ts\n * const resolver = await getResolver('alice.mon')\n * // '0xa2eb94c88e55d944aced2066c5cec9b759801f97'\n * ```\n */\nexport async function getResolver(\n name: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n try {\n const client = getMNSClient(config);\n const node = namehash(name.toLowerCase()) as `0x${string}`;\n\n const resolver = await client.readContract({\n address: MNS_REGISTRY,\n abi: registryAbi,\n functionName: 'resolver',\n args: [node],\n });\n\n return resolver === ZERO_ADDRESS ? null : resolver;\n } catch {\n return null;\n }\n}\n\n/**\n * Get expiry timestamp for a .mon name.\n *\n * @param name - Full name including .mon\n * @param config - Optional client configuration\n * @returns Unix timestamp (seconds) when the name expires, or null if not found\n *\n * @example\n * ```ts\n * const expiry = await getExpiry('alice.mon')\n * // 1735689600 (Unix timestamp)\n *\n * const expiryDate = new Date(expiry * 1000)\n * const daysLeft = Math.floor((expiry * 1000 - Date.now()) / (1000 * 60 * 60 * 24))\n * ```\n */\nexport async function getExpiry(\n name: string,\n config?: MNSClientConfig,\n): Promise<number | null> {\n try {\n const client = getMNSClient(config);\n const label = name.replace('.mon', '');\n const labelHash = keccak256(toBytes(label));\n\n const expiry = await client.readContract({\n address: MNS_BASE_REGISTRAR,\n abi: [\n {\n name: 'nameExpires',\n type: 'function',\n inputs: [{ name: 'id', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n ] as const,\n functionName: 'nameExpires',\n args: [BigInt(labelHash)],\n });\n\n return Number(expiry);\n } catch {\n return null;\n }\n}\n\n/**\n * Check if a .mon name is available for registration.\n *\n * @param name - Full name including .mon\n * @param config - Optional client configuration\n * @returns true if available (not registered), false if taken\n *\n * @example\n * ```ts\n * const available = await getAvailable('alice.mon')\n * if (available) {\n * console.log('alice.mon is available!')\n * }\n * ```\n */\nexport async function getAvailable(\n name: string,\n config?: MNSClientConfig,\n): Promise<boolean> {\n const addr = await resolveName(name, config);\n return addr === null;\n}\n\n// ─── Helpers ───────────────────────────────────────────────────\n\n/**\n * Get a display-friendly name for an address.\n * Returns the .mon name if set, otherwise a truncated address.\n *\n * @example\n * ```ts\n * const display = await getDisplayName('0xa05a8BF1...')\n * // 'alice.mon' or '0xa05a...Cc47'\n * ```\n */\nexport async function getDisplayName(\n address: string,\n config?: MNSClientConfig,\n): Promise<string> {\n const name = await lookupAddress(address, config);\n if (name) return name;\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n\n/**\n * Smart resolver — accepts either a .mon name or a raw address.\n * Useful for input fields where users can type either.\n *\n * @returns The resolved address, or null if invalid/not found\n *\n * @example\n * ```ts\n * const addr = await resolveInput('alice.mon') // resolves name\n * const addr = await resolveInput('alice') // tries alice.mon\n * const addr = await resolveInput('0xa05a...') // passes through\n * ```\n */\nexport async function resolveInput(\n input: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const trimmed = input.trim();\n if (!trimmed) return null;\n\n if (trimmed.startsWith('0x') && trimmed.length === 42) return trimmed;\n if (trimmed.endsWith('.mon')) return resolveName(trimmed, config);\n\n // Try appending .mon\n return resolveName(`${trimmed}.mon`, config);\n}\n\n/**\n * Get a resolved avatar URL for a .mon name.\n *\n * Handles multiple avatar formats:\n * - Direct HTTPS URLs: returned as-is\n * - IPFS URIs (ipfs://...): resolved via public gateway\n * - NFT references (eip155:chainId/erc721:contract/tokenId): fetches tokenURI and extracts image\n *\n * @param name - Full name including .mon\n * @param config - Optional client configuration\n * @returns A usable HTTPS URL, or null\n *\n * @example\n * ```ts\n * const avatarUrl = await getAvatarUrl('alice.mon')\n * // 'https://example.com/avatar.png'\n * ```\n */\nexport async function getAvatarUrl(\n name: string,\n config?: MNSClientConfig,\n): Promise<string | null> {\n const raw = await getTextRecord(name, 'avatar', config);\n if (!raw) return null;\n\n // Direct HTTP(S) URL\n if (raw.startsWith('http://') || raw.startsWith('https://')) {\n return raw;\n }\n\n // IPFS\n if (raw.startsWith('ipfs://')) {\n const hash = raw.slice(7);\n return `https://ipfs.io/ipfs/${hash}`;\n }\n\n // NFT reference: eip155:{chainId}/erc721:{contract}/{tokenId}\n // or eip155:{chainId}/erc1155:{contract}/{tokenId}\n const nftMatch = raw.match(\n /^eip155:(\\d+)\\/(erc721|erc1155):0x([a-fA-F0-9]{40})\\/(\\d+)$/,\n );\n if (nftMatch) {\n try {\n const client = getMNSClient(config);\n const contract = `0x${nftMatch[3]}` as `0x${string}`;\n const tokenId = BigInt(nftMatch[4]);\n\n const tokenUriAbi = [\n {\n name: nftMatch[2] === 'erc721' ? 'tokenURI' : 'uri',\n type: 'function',\n inputs: [{ name: 'tokenId', type: 'uint256' }],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n ] as const;\n\n let tokenUri = (await client.readContract({\n address: contract,\n abi: tokenUriAbi,\n functionName: nftMatch[2] === 'erc721' ? 'tokenURI' : 'uri',\n args: [tokenId],\n })) as string;\n\n // Resolve IPFS tokenURI\n if (tokenUri.startsWith('ipfs://')) {\n tokenUri = `https://ipfs.io/ipfs/${tokenUri.slice(7)}`;\n }\n\n // Fetch metadata JSON and extract image\n const res = await fetch(tokenUri);\n const metadata = await res.json();\n let image = metadata.image || metadata.image_url || null;\n\n if (image && image.startsWith('ipfs://')) {\n image = `https://ipfs.io/ipfs/${image.slice(7)}`;\n }\n\n return image;\n } catch {\n return null;\n }\n }\n\n // data: URIs\n if (raw.startsWith('data:')) {\n return raw;\n }\n\n return null;\n}\n\n/**\n * Clear the internal resolution cache.\n * Useful after a new registration.\n */\nexport function clearCache() {\n nameCache.clear();\n addrCache.clear();\n}\n","import {\n createPublicClient,\n http,\n type PublicClient,\n type Chain,\n type Transport,\n} from 'viem';\nimport { monad } from 'viem/chains';\n\nexport type MNSClientConfig = {\n /** Custom RPC URL. Defaults to the public Monad RPC. */\n rpcUrl?: string;\n /** Existing viem PublicClient to reuse instead of creating a new one. */\n client?: PublicClient<Transport, Chain>;\n};\n\nlet defaultClient: PublicClient<Transport, Chain> | null = null;\n\n/**\n * Get or create the MNS public client.\n * Reuses a singleton by default; pass config to override.\n */\nexport function getMNSClient(\n config?: MNSClientConfig,\n): PublicClient<Transport, Chain> {\n if (config?.client) return config.client;\n\n if (config?.rpcUrl) {\n return createPublicClient({\n chain: monad,\n transport: http(config.rpcUrl),\n });\n }\n\n if (!defaultClient) {\n defaultClient = createPublicClient({\n chain: monad,\n transport: http(),\n });\n }\n\n return defaultClient;\n}\n","export const MNS_REGISTRY =\n '0x13f963486e741c8d3fcdc0a34a910920339a19ce' as const;\nexport const MNS_PUBLIC_RESOLVER =\n '0xa2eb94c88e55d944aced2066c5cec9b759801f97' as const;\nexport const MNS_CONTROLLER =\n '0x98866c55adbc73ec6c272bb3604ddbdee3f282a8' as const;\nexport const MNS_BASE_REGISTRAR =\n '0x104a49db9318c284d462841b6940bdb46624ca55' as const;\n\nexport const ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as const;\n\nexport const registryAbi = [\n {\n name: 'resolver',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n name: 'owner',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n] as const;\n\nexport const resolverAbi = [\n {\n name: 'addr',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n name: 'name',\n type: 'function',\n inputs: [{ name: 'node', type: 'bytes32' }],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n {\n name: 'text',\n type: 'function',\n inputs: [\n { name: 'node', type: 'bytes32' },\n { name: 'key', type: 'string' },\n ],\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n },\n] as const;\n","'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport {\n getRegistrationInfo,\n getRegisterTx,\n getSetTextTx,\n getSetAddrTx,\n TEXT_RECORD_KEYS,\n type RegistrationInfo,\n} from './write';\nimport type { MNSClientConfig } from './client';\n\nexport { TEXT_RECORD_KEYS };\nexport type { RegistrationInfo };\n\n/**\n * Hook to get registration info (price, availability, freebie status).\n * Use this to build a registration UI before the user submits.\n *\n * @example\n * ```tsx\n * function RegisterPage() {\n * const [name, setName] = useState('')\n * const { address } = useAccount()\n * const { info, loading, error } = useRegistrationInfo(name, address)\n *\n * return (\n * <div>\n * <input value={name} onChange={(e) => setName(e.target.value)} />\n * {info?.available && (\n * <p>{info.isFreebie ? 'FREE!' : `${formatEther(info.price)} MON`}</p>\n * )}\n * </div>\n * )\n * }\n * ```\n */\nexport function useRegistrationInfo(\n label: string | undefined,\n userAddress: string | undefined,\n durationYears = 1,\n config?: MNSClientConfig,\n) {\n const [info, setInfo] = useState<RegistrationInfo | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!label || label.length < 3 || !userAddress) {\n setInfo(null);\n setError(\n label && label.length < 3 ? 'Name must be at least 3 characters' : null,\n );\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setError(null);\n\n const timer = setTimeout(() => {\n getRegistrationInfo(label, userAddress, durationYears, config)\n .then((i) => {\n if (!cancelled) setInfo(i);\n })\n .catch((e) => {\n if (!cancelled) setError(e.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n }, 300); // debounce\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [label, userAddress, durationYears]);\n\n return { info, loading, error };\n}\n\n/**\n * Hook to register a .mon name.\n * Returns a prepare function that gives you tx params for wagmi's writeContract.\n *\n * @example\n * ```tsx\n * const { prepare, loading, error } = useMNSRegister()\n * const { writeContract, data: hash } = useWriteContract()\n *\n * const handleRegister = async () => {\n * const tx = await prepare('alice', address)\n * if (tx) writeContract(tx)\n * }\n * ```\n */\nexport function useMNSRegister(config?: MNSClientConfig) {\n const [tx, setTx] = useState<Awaited<\n ReturnType<typeof getRegisterTx>\n > | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const prepare = useCallback(\n async (label: string, ownerAddress: string, durationYears = 1) => {\n setLoading(true);\n setError(null);\n setTx(null);\n\n try {\n const txParams = await getRegisterTx(\n label,\n ownerAddress,\n durationYears,\n config,\n );\n setTx(txParams);\n return txParams;\n } catch (e: any) {\n setError(e.message);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [],\n );\n\n return { prepare, tx, loading, error };\n}\n\n/**\n * Hook to set text records (avatar, url, twitter, etc.)\n *\n * @example\n * ```tsx\n * const { setAvatar, setTwitter } = useMNSTextRecords()\n * const { writeContract } = useWriteContract()\n *\n * writeContract(setAvatar('alice.mon', 'https://example.com/pic.png'))\n * ```\n */\nexport function useMNSTextRecords() {\n const setTextRecord = useCallback(\n (name: string, key: string, value: string) => {\n return getSetTextTx(name, key, value);\n },\n [],\n );\n\n const setAvatar = useCallback((name: string, url: string) => {\n return getSetTextTx(name, 'avatar', url);\n }, []);\n\n const setUrl = useCallback((name: string, url: string) => {\n return getSetTextTx(name, 'url', url);\n }, []);\n\n const setTwitter = useCallback((name: string, handle: string) => {\n return getSetTextTx(name, 'com.twitter', handle);\n }, []);\n\n const setGithub = useCallback((name: string, handle: string) => {\n return getSetTextTx(name, 'com.github', handle);\n }, []);\n\n const setDiscord = useCallback((name: string, handle: string) => {\n return getSetTextTx(name, 'com.discord', handle);\n }, []);\n\n const setDescription = useCallback((name: string, desc: string) => {\n return getSetTextTx(name, 'description', desc);\n }, []);\n\n return {\n setTextRecord,\n setAvatar,\n setUrl,\n setTwitter,\n setGithub,\n setDiscord,\n setDescription,\n textRecordKeys: TEXT_RECORD_KEYS,\n };\n}\n\n/**\n * Hook to update the address a name points to.\n *\n * @example\n * ```tsx\n * const { setAddr } = useMNSAddr()\n * const { writeContract } = useWriteContract()\n *\n * writeContract(setAddr('alice.mon', '0xnewaddress...'))\n * ```\n */\nexport function useMNSAddr() {\n const setAddr = useCallback((name: string, addr: string) => {\n return getSetAddrTx(name, addr);\n }, []);\n\n return { setAddr };\n}\n","import { namehash } from 'viem';\nimport { getMNSClient, type MNSClientConfig } from './client';\nimport { MNS_CONTROLLER, MNS_PUBLIC_RESOLVER } from './constants';\n\n/**\n * MNS Write Helpers\n *\n * These return transaction parameters ({ address, abi, functionName, args, value })\n * that you pass to wagmi's writeContract or any wallet client.\n * The user signs with their own wallet.\n */\n\n// ─── ABIs ──────────────────────────────────────────────────────\n\nexport const controllerReadAbi = [\n {\n name: 'available',\n type: 'function',\n inputs: [{ name: 'label', type: 'string' }],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n name: 'rentPrice',\n type: 'function',\n inputs: [\n { name: 'label', type: 'string' },\n { name: 'duration', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n name: 'hasClaimedFreebie',\n type: 'function',\n inputs: [{ name: 'user', type: 'address' }],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n] as const;\n\nexport const controllerWriteAbi = [\n {\n name: 'register',\n type: 'function',\n inputs: [\n { name: 'label', type: 'string' },\n { name: 'owner', type: 'address' },\n { name: 'duration', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'payable',\n },\n] as const;\n\nexport const resolverWriteAbi = [\n {\n name: 'setText',\n type: 'function',\n inputs: [\n { name: 'node', type: 'bytes32' },\n { name: 'key', type: 'string' },\n { name: 'value', type: 'string' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n {\n name: 'setAddr',\n type: 'function',\n inputs: [\n { name: 'node', type: 'bytes32' },\n { name: 'a', type: 'address' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n] as const;\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport type RegistrationInfo = {\n available: boolean;\n price: bigint;\n isFreebie: boolean;\n hasClaimed: boolean;\n duration: bigint;\n label: string;\n};\n\n// ─── Registration ──────────────────────────────────────────────\n\nconst ONE_YEAR = BigInt(365 * 24 * 60 * 60);\n\n/**\n * Get all info needed before registration.\n *\n * @example\n * ```ts\n * const info = await getRegistrationInfo('alice', userAddress)\n * // { available: true, price: 96831564n..., isFreebie: true, ... }\n * ```\n */\nexport async function getRegistrationInfo(\n label: string,\n userAddress: string,\n durationYears = 1,\n config?: MNSClientConfig,\n): Promise<RegistrationInfo> {\n const client = getMNSClient(config);\n const duration = ONE_YEAR * BigInt(durationYears);\n\n const [available, price, hasClaimed, balance] = await Promise.all([\n client.readContract({\n address: MNS_CONTROLLER,\n abi: controllerReadAbi,\n functionName: 'available',\n args: [label],\n }),\n client.readContract({\n address: MNS_CONTROLLER,\n abi: controllerReadAbi,\n functionName: 'rentPrice',\n args: [label, duration],\n }),\n client.readContract({\n address: MNS_CONTROLLER,\n abi: controllerReadAbi,\n functionName: 'hasClaimedFreebie',\n args: [userAddress as `0x${string}`],\n }),\n client.getBalance({ address: userAddress as `0x${string}` }),\n ]);\n\n const isFreebie = balance >= 10n * 10n ** 18n && !hasClaimed;\n\n return { available, price, isFreebie, hasClaimed, duration, label };\n}\n\n/**\n * Get transaction parameters for registering a .mon name.\n * Pass the result to wagmi's writeContract.\n *\n * @example\n * ```ts\n * const tx = await getRegisterTx('alice', userAddress)\n * writeContract(tx)\n * ```\n */\nexport async function getRegisterTx(\n label: string,\n ownerAddress: string,\n durationYears = 1,\n config?: MNSClientConfig,\n) {\n const info = await getRegistrationInfo(\n label,\n ownerAddress,\n durationYears,\n config,\n );\n\n if (!info.available) {\n throw new Error(`${label}.mon is not available`);\n }\n\n return {\n address: MNS_CONTROLLER,\n abi: controllerWriteAbi,\n functionName: 'register' as const,\n args: [label, ownerAddress as `0x${string}`, info.duration] as const,\n value: info.isFreebie ? 0n : info.price,\n gas: 3_000_000n,\n _meta: {\n label,\n isFreebie: info.isFreebie,\n price: info.price,\n duration: info.duration,\n },\n };\n}\n\n// ─── Text Records ──────────────────────────────────────────────\n\n/**\n * Get transaction parameters for setting a text record.\n * The connected user must own the name.\n *\n * @example\n * ```ts\n * const tx = getSetTextTx('alice.mon', 'avatar', 'https://example.com/pic.png')\n * writeContract(tx)\n * ```\n */\nexport function getSetTextTx(name: string, key: string, value: string) {\n const node = namehash(\n name.endsWith('.mon') ? name : `${name}.mon`,\n ) as `0x${string}`;\n\n return {\n address: MNS_PUBLIC_RESOLVER,\n abi: resolverWriteAbi,\n functionName: 'setText' as const,\n args: [node, key, value] as const,\n };\n}\n\n/**\n * Get transaction parameters for setting the address record.\n */\nexport function getSetAddrTx(name: string, addr: string) {\n const node = namehash(\n name.endsWith('.mon') ? name : `${name}.mon`,\n ) as `0x${string}`;\n\n return {\n address: MNS_PUBLIC_RESOLVER,\n abi: resolverWriteAbi,\n functionName: 'setAddr' as const,\n args: [node, addr as `0x${string}`] as const,\n };\n}\n\nexport const TEXT_RECORD_KEYS = {\n avatar: 'avatar',\n url: 'url',\n description: 'description',\n email: 'email',\n twitter: 'com.twitter',\n github: 'com.github',\n discord: 'com.discord',\n telegram: 'org.telegram',\n} as const;\n"],"mappings":"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","names":["import_react","import_viem","import_viem"]}
|
package/dist/react.d.cts
CHANGED
|
@@ -537,5 +537,59 @@ declare function useMNSAvatar(name: string | undefined, config?: MNSClientConfig
|
|
|
537
537
|
loading: boolean;
|
|
538
538
|
error: string | null;
|
|
539
539
|
};
|
|
540
|
+
/**
|
|
541
|
+
* Owner hook: get the owner address of a .mon name
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```tsx
|
|
545
|
+
* function OwnerInfo({ name }: { name: string }) {
|
|
546
|
+
* const { owner, loading } = useMNSOwner(name)
|
|
547
|
+
* if (loading) return <div>Loading...</div>
|
|
548
|
+
* return <div>Owner: {owner}</div>
|
|
549
|
+
* }
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
declare function useMNSOwner(name: string | undefined, config?: MNSClientConfig): {
|
|
553
|
+
owner: string | null;
|
|
554
|
+
loading: boolean;
|
|
555
|
+
error: string | null;
|
|
556
|
+
};
|
|
557
|
+
/**
|
|
558
|
+
* Resolver hook: get the resolver contract address for a .mon name
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```tsx
|
|
562
|
+
* function ResolverInfo({ name }: { name: string }) {
|
|
563
|
+
* const { resolver, loading } = useMNSResolver(name)
|
|
564
|
+
* return <div>Resolver: {resolver}</div>
|
|
565
|
+
* }
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare function useMNSResolver(name: string | undefined, config?: MNSClientConfig): {
|
|
569
|
+
resolver: string | null;
|
|
570
|
+
loading: boolean;
|
|
571
|
+
error: string | null;
|
|
572
|
+
};
|
|
573
|
+
/**
|
|
574
|
+
* Expiry hook: get expiration info for a .mon name
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```tsx
|
|
578
|
+
* function ExpiryInfo({ name }: { name: string }) {
|
|
579
|
+
* const { expiry, expiryDate, daysUntilExpiry, isExpired, loading } = useMNSExpiry(name)
|
|
580
|
+
* if (loading) return <div>Loading...</div>
|
|
581
|
+
* if (isExpired) return <div className="text-red-500">Expired!</div>
|
|
582
|
+
* return <div>Expires in {daysUntilExpiry} days</div>
|
|
583
|
+
* }
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
declare function useMNSExpiry(name: string | undefined, config?: MNSClientConfig): {
|
|
587
|
+
expiry: number | null;
|
|
588
|
+
expiryDate: Date | null;
|
|
589
|
+
daysUntilExpiry: number | null;
|
|
590
|
+
isExpired: boolean | null;
|
|
591
|
+
loading: boolean;
|
|
592
|
+
error: string | null;
|
|
593
|
+
};
|
|
540
594
|
|
|
541
|
-
export { type MNSClientConfig, useMNSAddr, useMNSAddress, useMNSAvatar, useMNSDisplay, useMNSName, useMNSRegister, useMNSResolve, useMNSText, useMNSTextRecords, useRegistrationInfo };
|
|
595
|
+
export { type MNSClientConfig, useMNSAddr, useMNSAddress, useMNSAvatar, useMNSDisplay, useMNSExpiry, useMNSName, useMNSOwner, useMNSRegister, useMNSResolve, useMNSResolver, useMNSText, useMNSTextRecords, useRegistrationInfo };
|
package/dist/react.d.ts
CHANGED
|
@@ -537,5 +537,59 @@ declare function useMNSAvatar(name: string | undefined, config?: MNSClientConfig
|
|
|
537
537
|
loading: boolean;
|
|
538
538
|
error: string | null;
|
|
539
539
|
};
|
|
540
|
+
/**
|
|
541
|
+
* Owner hook: get the owner address of a .mon name
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```tsx
|
|
545
|
+
* function OwnerInfo({ name }: { name: string }) {
|
|
546
|
+
* const { owner, loading } = useMNSOwner(name)
|
|
547
|
+
* if (loading) return <div>Loading...</div>
|
|
548
|
+
* return <div>Owner: {owner}</div>
|
|
549
|
+
* }
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
declare function useMNSOwner(name: string | undefined, config?: MNSClientConfig): {
|
|
553
|
+
owner: string | null;
|
|
554
|
+
loading: boolean;
|
|
555
|
+
error: string | null;
|
|
556
|
+
};
|
|
557
|
+
/**
|
|
558
|
+
* Resolver hook: get the resolver contract address for a .mon name
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```tsx
|
|
562
|
+
* function ResolverInfo({ name }: { name: string }) {
|
|
563
|
+
* const { resolver, loading } = useMNSResolver(name)
|
|
564
|
+
* return <div>Resolver: {resolver}</div>
|
|
565
|
+
* }
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare function useMNSResolver(name: string | undefined, config?: MNSClientConfig): {
|
|
569
|
+
resolver: string | null;
|
|
570
|
+
loading: boolean;
|
|
571
|
+
error: string | null;
|
|
572
|
+
};
|
|
573
|
+
/**
|
|
574
|
+
* Expiry hook: get expiration info for a .mon name
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```tsx
|
|
578
|
+
* function ExpiryInfo({ name }: { name: string }) {
|
|
579
|
+
* const { expiry, expiryDate, daysUntilExpiry, isExpired, loading } = useMNSExpiry(name)
|
|
580
|
+
* if (loading) return <div>Loading...</div>
|
|
581
|
+
* if (isExpired) return <div className="text-red-500">Expired!</div>
|
|
582
|
+
* return <div>Expires in {daysUntilExpiry} days</div>
|
|
583
|
+
* }
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
declare function useMNSExpiry(name: string | undefined, config?: MNSClientConfig): {
|
|
587
|
+
expiry: number | null;
|
|
588
|
+
expiryDate: Date | null;
|
|
589
|
+
daysUntilExpiry: number | null;
|
|
590
|
+
isExpired: boolean | null;
|
|
591
|
+
loading: boolean;
|
|
592
|
+
error: string | null;
|
|
593
|
+
};
|
|
540
594
|
|
|
541
|
-
export { type MNSClientConfig, useMNSAddr, useMNSAddress, useMNSAvatar, useMNSDisplay, useMNSName, useMNSRegister, useMNSResolve, useMNSText, useMNSTextRecords, useRegistrationInfo };
|
|
595
|
+
export { type MNSClientConfig, useMNSAddr, useMNSAddress, useMNSAvatar, useMNSDisplay, useMNSExpiry, useMNSName, useMNSOwner, useMNSRegister, useMNSResolve, useMNSResolver, useMNSText, useMNSTextRecords, useRegistrationInfo };
|
package/dist/react.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
6
6
|
|
|
7
7
|
// src/resolve.ts
|
|
8
|
-
import { namehash } from "viem";
|
|
8
|
+
import { namehash, keccak256, toBytes } from "viem";
|
|
9
9
|
|
|
10
10
|
// src/client.ts
|
|
11
11
|
import {
|
|
@@ -35,6 +35,7 @@ function getMNSClient(config) {
|
|
|
35
35
|
var MNS_REGISTRY = "0x13f963486e741c8d3fcdc0a34a910920339a19ce";
|
|
36
36
|
var MNS_PUBLIC_RESOLVER = "0xa2eb94c88e55d944aced2066c5cec9b759801f97";
|
|
37
37
|
var MNS_CONTROLLER = "0x98866c55adbc73ec6c272bb3604ddbdee3f282a8";
|
|
38
|
+
var MNS_BASE_REGISTRAR = "0x104a49db9318c284d462841b6940bdb46624ca55";
|
|
38
39
|
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
39
40
|
var registryAbi = [
|
|
40
41
|
{
|
|
@@ -43,6 +44,13 @@ var registryAbi = [
|
|
|
43
44
|
inputs: [{ name: "node", type: "bytes32" }],
|
|
44
45
|
outputs: [{ name: "", type: "address" }],
|
|
45
46
|
stateMutability: "view"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "owner",
|
|
50
|
+
type: "function",
|
|
51
|
+
inputs: [{ name: "node", type: "bytes32" }],
|
|
52
|
+
outputs: [{ name: "", type: "address" }],
|
|
53
|
+
stateMutability: "view"
|
|
46
54
|
}
|
|
47
55
|
];
|
|
48
56
|
var resolverAbi = [
|
|
@@ -167,6 +175,60 @@ async function getTextRecord(name, key, config) {
|
|
|
167
175
|
return null;
|
|
168
176
|
}
|
|
169
177
|
}
|
|
178
|
+
async function getOwner(name, config) {
|
|
179
|
+
try {
|
|
180
|
+
const client = getMNSClient(config);
|
|
181
|
+
const node = namehash(name.toLowerCase());
|
|
182
|
+
const owner = await client.readContract({
|
|
183
|
+
address: MNS_REGISTRY,
|
|
184
|
+
abi: registryAbi,
|
|
185
|
+
functionName: "owner",
|
|
186
|
+
args: [node]
|
|
187
|
+
});
|
|
188
|
+
return owner === ZERO_ADDRESS ? null : owner;
|
|
189
|
+
} catch {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function getResolver(name, config) {
|
|
194
|
+
try {
|
|
195
|
+
const client = getMNSClient(config);
|
|
196
|
+
const node = namehash(name.toLowerCase());
|
|
197
|
+
const resolver = await client.readContract({
|
|
198
|
+
address: MNS_REGISTRY,
|
|
199
|
+
abi: registryAbi,
|
|
200
|
+
functionName: "resolver",
|
|
201
|
+
args: [node]
|
|
202
|
+
});
|
|
203
|
+
return resolver === ZERO_ADDRESS ? null : resolver;
|
|
204
|
+
} catch {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async function getExpiry(name, config) {
|
|
209
|
+
try {
|
|
210
|
+
const client = getMNSClient(config);
|
|
211
|
+
const label = name.replace(".mon", "");
|
|
212
|
+
const labelHash = keccak256(toBytes(label));
|
|
213
|
+
const expiry = await client.readContract({
|
|
214
|
+
address: MNS_BASE_REGISTRAR,
|
|
215
|
+
abi: [
|
|
216
|
+
{
|
|
217
|
+
name: "nameExpires",
|
|
218
|
+
type: "function",
|
|
219
|
+
inputs: [{ name: "id", type: "uint256" }],
|
|
220
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
221
|
+
stateMutability: "view"
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
functionName: "nameExpires",
|
|
225
|
+
args: [BigInt(labelHash)]
|
|
226
|
+
});
|
|
227
|
+
return Number(expiry);
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
170
232
|
async function getAvatarUrl(name, config) {
|
|
171
233
|
const raw = await getTextRecord(name, "avatar", config);
|
|
172
234
|
if (!raw) return null;
|
|
@@ -626,14 +688,95 @@ function useMNSAvatar(name, config) {
|
|
|
626
688
|
}, [name]);
|
|
627
689
|
return { url, loading, error };
|
|
628
690
|
}
|
|
691
|
+
function useMNSOwner(name, config) {
|
|
692
|
+
const [owner, setOwner] = useState2(null);
|
|
693
|
+
const [loading, setLoading] = useState2(false);
|
|
694
|
+
const [error, setError] = useState2(null);
|
|
695
|
+
useEffect2(() => {
|
|
696
|
+
if (!name) {
|
|
697
|
+
setOwner(null);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
let cancelled = false;
|
|
701
|
+
setLoading(true);
|
|
702
|
+
setError(null);
|
|
703
|
+
getOwner(name, config).then((o) => {
|
|
704
|
+
if (!cancelled) setOwner(o);
|
|
705
|
+
}).catch((e) => {
|
|
706
|
+
if (!cancelled) setError(e.message);
|
|
707
|
+
}).finally(() => {
|
|
708
|
+
if (!cancelled) setLoading(false);
|
|
709
|
+
});
|
|
710
|
+
return () => {
|
|
711
|
+
cancelled = true;
|
|
712
|
+
};
|
|
713
|
+
}, [name]);
|
|
714
|
+
return { owner, loading, error };
|
|
715
|
+
}
|
|
716
|
+
function useMNSResolver(name, config) {
|
|
717
|
+
const [resolver, setResolver] = useState2(null);
|
|
718
|
+
const [loading, setLoading] = useState2(false);
|
|
719
|
+
const [error, setError] = useState2(null);
|
|
720
|
+
useEffect2(() => {
|
|
721
|
+
if (!name) {
|
|
722
|
+
setResolver(null);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
let cancelled = false;
|
|
726
|
+
setLoading(true);
|
|
727
|
+
setError(null);
|
|
728
|
+
getResolver(name, config).then((r) => {
|
|
729
|
+
if (!cancelled) setResolver(r);
|
|
730
|
+
}).catch((e) => {
|
|
731
|
+
if (!cancelled) setError(e.message);
|
|
732
|
+
}).finally(() => {
|
|
733
|
+
if (!cancelled) setLoading(false);
|
|
734
|
+
});
|
|
735
|
+
return () => {
|
|
736
|
+
cancelled = true;
|
|
737
|
+
};
|
|
738
|
+
}, [name]);
|
|
739
|
+
return { resolver, loading, error };
|
|
740
|
+
}
|
|
741
|
+
function useMNSExpiry(name, config) {
|
|
742
|
+
const [expiry, setExpiry] = useState2(null);
|
|
743
|
+
const [loading, setLoading] = useState2(false);
|
|
744
|
+
const [error, setError] = useState2(null);
|
|
745
|
+
useEffect2(() => {
|
|
746
|
+
if (!name) {
|
|
747
|
+
setExpiry(null);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
let cancelled = false;
|
|
751
|
+
setLoading(true);
|
|
752
|
+
setError(null);
|
|
753
|
+
getExpiry(name, config).then((e) => {
|
|
754
|
+
if (!cancelled) setExpiry(e);
|
|
755
|
+
}).catch((e) => {
|
|
756
|
+
if (!cancelled) setError(e.message);
|
|
757
|
+
}).finally(() => {
|
|
758
|
+
if (!cancelled) setLoading(false);
|
|
759
|
+
});
|
|
760
|
+
return () => {
|
|
761
|
+
cancelled = true;
|
|
762
|
+
};
|
|
763
|
+
}, [name]);
|
|
764
|
+
const expiryDate = expiry ? new Date(expiry * 1e3) : null;
|
|
765
|
+
const daysUntilExpiry = expiry ? Math.floor((expiry * 1e3 - Date.now()) / (1e3 * 60 * 60 * 24)) : null;
|
|
766
|
+
const isExpired = expiry ? expiry * 1e3 < Date.now() : null;
|
|
767
|
+
return { expiry, expiryDate, daysUntilExpiry, isExpired, loading, error };
|
|
768
|
+
}
|
|
629
769
|
export {
|
|
630
770
|
useMNSAddr,
|
|
631
771
|
useMNSAddress,
|
|
632
772
|
useMNSAvatar,
|
|
633
773
|
useMNSDisplay,
|
|
774
|
+
useMNSExpiry,
|
|
634
775
|
useMNSName,
|
|
776
|
+
useMNSOwner,
|
|
635
777
|
useMNSRegister,
|
|
636
778
|
useMNSResolve,
|
|
779
|
+
useMNSResolver,
|
|
637
780
|
useMNSText,
|
|
638
781
|
useMNSTextRecords,
|
|
639
782
|
useRegistrationInfo
|