This guide will help you integrate resolution into your HyperEVM application using our contract, with a real-world example for customizing your wallet connect UI.
Use .hype Names in Your App
The dotHYPE resolver is fully ENS-compatible, making integration simple for developers already familiar with Ethereum naming systems. You can use standard addr(), getName(), and text() calls to resolve identity information from .hype domains. No proprietary logic required.
Basic Usage
To resolve .hype names, use the dotHYPEResolver contract and the following standard functions:
Function
Purpose
addr(bytes32 node)
Returns the address for a .hype name
getName(address)
Returns the primary .hype name for a wallet
text(bytes32 node, string key)
Returns a text record (e.g. twitter, avatar)
Note: The node refers to the ENS-compatible namehash of the .hype domain.
Custom Connect Button
Display .hype Names Instead of Wallet Addresses
This component enhances your RainbowKit wallet connection UX by displaying the user's primary .hype name (if set) instead of a truncated address. It works seamlessly across HyperEVM mainnet and testnet, supports loading states, and falls back to address when no name is set.
Step 1. Overview & Purpose
This custom component:
Replaces wallet addresses with .hype domains
Uses the DotHypeResolver.name(address) function
Falls back to the address if no primary name is set
Detects network automatically via chain ID
Supports full styling customization
⚠️ Important:
Replace the placeholder contract addresses in the code with your actual deployed resolver addresses (see /info page for details).
Step 2. CustomConnectButton.tsx
Full Code
import { useState, useEffect, useCallback } from"react";import { ConnectButton } from"@rainbow-me/rainbowkit";import { usePublicClient } from"wagmi";import { Address } from"viem";import { getCurrentNetworkAddresses } from"@/contracts/addresses";import { DOT_HYPE_RESOLVER_ABI } from"@/contracts/abis";/** * Custom ConnectButton that shows primary domain name instead of truncated address * when a primary domain is set for the connected wallet */exportfunctionCustomConnectButton() {return ( <ConnectButton.Custom> {({ account, chain, openAccountModal, openChainModal, openConnectModal, authenticationStatus, mounted, }) => {// Note: If your app doesn't use authentication, you// can remove all 'authenticationStatus' checksconstready= mounted && authenticationStatus !=="loading";constconnected= ready && account && chain && (!authenticationStatus || authenticationStatus ==="authenticated");return ( <div {...(!ready && {"aria-hidden":true, style: { opacity:0, pointerEvents:"none", userSelect:"none", }, })} > {(() => {if (!connected) {return ( <buttononClick={openConnectModal}type="button"className="bg-gradient-to-r from-hype-primary to-hype-secondary text-white px-6 py-3 rounded-lg font-medium hover:from-hype-secondary hover:to-hype-primary transition-all duration-200 shadow-lg hover:shadow-xl" > Connect Wallet </button> ); }if (chain.unsupported) {return ( <buttononClick={openChainModal}type="button"className="bg-red-500 text-white px-4 py-2 rounded-lg font-medium hover:bg-red-600 transition-colors" > Wrong network </button> ); }return ( <divclassName="flex items-center gap-3"> <buttononClick={openChainModal}className="flex items-center gap-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-3 rounded-lg transition-colors"type="button" > {chain.hasIcon && ( <divstyle={{ background:chain.iconBackground, width:20, height:20, borderRadius:999, overflow:"hidden", marginRight:4, }} > {chain.iconUrl && ( <imgalt={chain.name ??"Chain icon"}src={chain.iconUrl}style={{ width:20, height:20 }} /> )} </div> )} <spanclassName="text-sm font-medium text-gray-700 dark:text-gray-300"> {chain.name} </span> </button> <AccountButtonaccount={account}openAccountModal={openAccountModal} /> </div> ); })()} </div> ); }} </ConnectButton.Custom> );}/** * Account button component that shows primary domain or truncated address */interfaceAccountButtonProps { account: { address:string; displayBalance?:string; };openAccountModal: () =>void;}functionAccountButton({ account, openAccountModal }:AccountButtonProps) {const { primaryDomain, isLoading: primaryDomainLoading } =usePrimaryDomain(account?.address asAddress );const { avatar, isLoading: avatarLoading } =useUserAvatar(account?.address asAddress );constdisplayText= primaryDomain ||`${account.address.slice(0,6)}...${account.address.slice(-4)}`;constshowBalance=account.displayBalance?` (${account.displayBalance})`:"";constisLoading= primaryDomainLoading || avatarLoading;return ( <buttononClick={openAccountModal}type="button"className="flex items-center gap-3 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 transition-colors shadow-sm" > {/* Avatar or Status Indicator */} <divclassName="flex-shrink-0"> {isLoading ? ( <divclassName="animate-spin rounded-full h-8 w-8 border-b-2 border-hype-primary"></div> ) : avatar ? ( <AvatarImagesrc={avatar} /> ) : ( <divclassName="w-8 h-8 bg-gradient-to-br from-hype-primary to-hype-secondary rounded-full flex items-center justify-center"> <divclassName="w-2 h-2 bg-white rounded-full"></div> </div> )} </div> {/* Account Info */} <divclassName="flex items-center gap-2"> <spanclassName="text-sm font-medium text-gray-900 dark:text-white"> {displayText} </span> {showBalance && ( <spanclassName="text-sm text-gray-600 dark:text-gray-400"> {showBalance} </span> )} </div> </button> );}/** * Avatar image component with fallback */interfaceAvatarImageProps { src:string;}functionAvatarImage({ src }:AvatarImageProps) {const [hasError,setHasError] =useState(false);if (hasError) {return ( <divclassName="w-8 h-8 bg-gradient-to-br from-hype-primary to-hype-secondary rounded-full flex items-center justify-center"> <divclassName="w-2 h-2 bg-white rounded-full"></div> </div> ); }return ( <imgsrc={src}alt="User avatar"className="w-8 h-8 rounded-full object-cover border-2 border-green-500"onError={() =>setHasError(true)} /> );}// Hook implementations used in the CustomConnectButton above/** * Hook to fetch the primary domain name for an address using the getName function * @param address - The Hyperliquid address to get the primary domain for */exportfunctionusePrimaryDomain(address?:Address): { primaryDomain:string|null; isLoading:boolean; error:string|null;refetch: () =>Promise<void>;} {const [primaryDomain,setPrimaryDomain] =useState<string|null>(null);const [isLoading,setIsLoading] =useState(false);const [error,setError] =useState<string|null>(null);constpublicClient=usePublicClient();constaddresses=getCurrentNetworkAddresses();constresolverAddress=addresses.DOT_HYPE_RESOLVERasAddress;constfetchPrimaryDomain=useCallback(async () => {if (!publicClient ||!address) {setPrimaryDomain(null);setIsLoading(false);setError(null);return; }setIsLoading(true);setError(null);try {// Call getName function on the resolverconstdomainName=awaitpublicClient.readContract({ address: resolverAddress, abi:DOT_HYPE_RESOLVER_ABI, functionName:"getName", args: [address], });// Check if we got a valid domain nameif ( domainName &&typeof domainName ==="string"&&domainName.trim() !=="" ) {setPrimaryDomain(domainName); } else {setPrimaryDomain(null); } } catch (err) {console.error("Error fetching primary domain:", err);// Handle specific error caseslet errorMessage ="Failed to fetch primary domain";if (err instanceofError) {if (err.message.includes("execution reverted")) { errorMessage ="No primary domain set for this address"; } elseif (err.message.includes("OpcodeNotFound")) { errorMessage ="Resolver contract does not support getName function"; } else { errorMessage =err.message; } }setError(errorMessage);setPrimaryDomain(null); } finally {setIsLoading(false); } }, [address, publicClient, resolverAddress]);useEffect(() => {fetchPrimaryDomain(); }, [fetchPrimaryDomain]);return { primaryDomain, isLoading, error, refetch: fetchPrimaryDomain, };}/** * Hook to fetch the user's avatar from their primary domain's text records * Uses the resolver's getValue function to get the avatar directly by address */exportfunctionuseUserAvatar(address?:Address): { avatar:string|null; isLoading:boolean; error:string|null;} {const [avatar,setAvatar] =useState<string|null>(null);const [isLoading,setIsLoading] =useState(false);const [error,setError] =useState<string|null>(null);constpublicClient=usePublicClient();useEffect(() => {if (!address ||!publicClient) {setAvatar(null);setIsLoading(false);setError(null);return; }constfetchAvatar=async () => {setIsLoading(true);setError(null);try {const { DOT_HYPE_RESOLVER } =getCurrentNetworkAddresses();// Use getValue to get the avatar text record directly by addressconstavatarValue= (awaitpublicClient.readContract({ address:DOT_HYPE_RESOLVERas`0x${string}`, abi:DOT_HYPE_RESOLVER_ABI, functionName:"getValue", args: [address,"avatar"], })) asstring;// Only set avatar if it's a valid non-empty stringif (avatarValue &&avatarValue.trim() !=="") {setAvatar(avatarValue.trim()); } else {setAvatar(null); } } catch (err) {console.warn("Error fetching user avatar:", err);setAvatar(null);setError(err instanceofError?err.message :"Failed to fetch avatar"); } finally {setIsLoading(false); } };fetchAvatar(); }, [address, publicClient]);return { avatar, isLoading, error, };}
import { CustomConnectButton } from './CustomConnectButton';
import { useChainId } from 'wagmi';
function App() {
const chainId = useChainId();
return (
<div>
<CustomConnectButton chainId={chainId} />
</div>
);
}
⚠️Pro Tip
The component automatically detects the network based on the chain Id prop. Chain ID 999 is used for HyperEVM mainnet, while any other value defaults to testnet.
Build with dotHYPE
Integrate Identity. Resolve with Confidence.
Whether you're building a wallet, dashboard, or on-chain application, integrating .hype domains helps your users move from raw addresses to structured, readable identity.
Our resolver is fully on-chain, ENS-compatible, and designed without centralized gatekeepers so you can plug-in with confidence. Everything is modular and upgrade-ready, giving us a stable foundation today and flexibility for tomorrow.
What You Can Do
Resolve Names to Addresses
Read On-chain Text Records (e.g. Twitter, avatar)
Support Reverse Resolution
Query Ownership via ERC721
Start Integrating
→ Resolver Reference
Includes ABI, contract address, and example calls (addr(), text(), name()).