A production-ready Next.js template for building decentralized applications on Hathor Network. Features seamless wallet integration with WalletConnect (Reown) and MetaMask Snaps, nano contract interaction, and a clean TypeScript architecture.
- Multi-Wallet Support: Built-in integration with WalletConnect (Reown) and MetaMask Snaps
- Unified Adapter Pattern: Abstract wallet implementation for easy extension
- Network Switching: Seamless testnet/mainnet switching with configuration
- Nano Contract Integration: Generic transaction interface for any Hathor contract
- Balance Management: Automatic balance caching with 15-minute TTL
- Mock Mode: Full development environment without wallet connection
- TypeScript: Complete type safety throughout the application
- Modern Stack: Next.js 14 App Router, React 18, Tailwind CSS
- Toast Notifications: Built-in user feedback system
- Node.js 18 or higher
- npm or yarn
- A WalletConnect (Reown) Project ID (get one free)
- Basic understanding of Hathor Network and nano contracts
-
Clone and Install
git clone <your-repo-url> cd hathor-dapp-template npm install
-
Configure Environment
cp .env.example .env.local
Edit
.env.localand add your WalletConnect Project ID:NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id_here
-
Start Development Server
npm run dev
-
Open Browser
Navigate to http://localhost:3000
hathor-dapp-template/
├── app/
│ ├── layout.tsx # Root layout with provider hierarchy
│ ├── page.tsx # Main landing page
│ └── globals.css # Global styles and Tailwind
├── components/
│ ├── Header.tsx # Navigation with wallet connection
│ ├── GettingStartedGuide.tsx # Template documentation
│ ├── ContractExample.tsx # Example contract interaction
│ ├── NetworkSelector.tsx # Network switching UI
│ └── WalletConnectionModal.tsx # Wallet selection modal
├── contexts/
│ ├── HathorContext.tsx # Hathor network and contract state
│ ├── WalletContext.tsx # Wallet connection and transactions
│ ├── UnifiedWalletContext.tsx # Wallet adapter pattern
│ ├── WalletConnectContext.tsx # WalletConnect implementation
│ └── MetaMaskContext.tsx # MetaMask Snaps implementation
├── lib/
│ ├── config.ts # Environment configuration
│ ├── hathorRPC.ts # Wallet RPC service
│ ├── hathorCoreAPI.ts # Blockchain API service
│ ├── utils.ts # Utility functions
│ └── toast.tsx # Toast notification system
├── types/
│ ├── index.ts # Shared TypeScript types
│ └── hathor.ts # Hathor-specific types
└── .env.local # Your local configuration
See .env.example for basic configuration and .env.local.example for advanced options.
Required:
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: Your WalletConnect project ID
Optional:
NEXT_PUBLIC_USE_MOCK_WALLET: Enable mock wallet mode (default: false)NEXT_PUBLIC_DEFAULT_NETWORK: Default network (testnet | mainnet)NEXT_PUBLIC_CONTRACT_IDS: Array of your deployed contract IDs
The template supports testnet and mainnet. Configure node URLs in lib/config.ts or via environment variables. Network switching is available in the UI.
The template uses a unified adapter pattern for wallet integration:
UnifiedWalletContext (Adapter Pattern)
├── WalletConnectContext (WalletConnect v2/Reown)
└── MetaMaskContext (MetaMask Snaps)
- Create a new context implementing the wallet adapter interface
- Add it to
UnifiedWalletContext.tsx - Update
WalletConnectionModal.tsxwith the new option
See existing implementations in contexts/ for reference.
The template provides a generic sendContractTx method in WalletContext:
import { useWallet } from '@/contexts/WalletContext';
function YourComponent() {
const { sendContractTx } = useWallet();
const callContract = async () => {
const result = await sendContractTx({
contractId: 'your_contract_id',
method: 'your_method',
args: [arg1, arg2],
actions: [{
type: 'deposit',
amount: '1000', // Amount in cents
token: '00', // HTR token UID
}],
});
};
}Fetch current contract state using HathorContext:
import { useHathor } from '@/contexts/HathorContext';
function YourComponent() {
const { getContractState } = useHathor();
const fetchState = async () => {
const state = await getContractState('your_contract_id');
console.log(state);
};
}See components/ContractExample.tsx for a complete working example of contract interaction.
Test your dApp without connecting a wallet:
NEXT_PUBLIC_USE_MOCK_WALLET=trueMock mode simulates:
- Wallet connection
- Balance queries (100,000 HTR mock balance)
- Transaction submissions
- Network information
The template uses TypeScript throughout. Key types are defined in:
types/index.ts: Shared application typestypes/hathor.ts: Hathor Network types- Context files: Context-specific interfaces
Uses Tailwind CSS with a dark theme. Customize colors and styles in:
app/globals.css: Global stylestailwind.config.ts: Tailwind configuration
-
Build the Application
npm run build
-
Test Production Build Locally
npm start
-
Deploy
The template works with any Next.js hosting provider:
- Vercel (recommended)
- Netlify
- AWS
- Your own infrastructure
Problem: Wallet not connecting
Solutions:
- Verify your WalletConnect Project ID is correct
- Check that the wallet extension is installed and unlocked
- Try refreshing the page
- Check browser console for errors
- Ensure you're on a supported browser (Chrome, Firefox, Brave)
Problem: Transactions failing or timing out
Solutions:
- Verify sufficient balance
- Check network connectivity
- Confirm contract ID is correct
- Review transaction parameters in browser console
- Try switching networks and back
Problem: Balance shows as 0 or won't load
Solutions:
- Click the refresh button to force balance update
- Grant wallet permissions when prompted
- Clear localStorage and reconnect
- Check if mock mode is accidentally enabled
Problem: TypeScript errors during development
Solutions:
- Run
npm installto ensure all dependencies are installed - Check that TypeScript version is 5.x or higher
- Restart your IDE/editor
- Run
npx tsc --noEmitto check for type errors
interface WalletContextType {
connected: boolean;
address: string | null;
balance: bigint;
walletBalance: number;
connectWallet: () => void;
disconnectWallet: () => void;
setBalance: (balance: bigint) => void;
sendContractTx: (params: ContractTxParams) => Promise<any>;
refreshBalance: () => Promise<void>;
}interface HathorContextType {
isConnected: boolean;
address: string | null;
network: Network;
contractStates: Record<string, ContractState>;
getContractState: (contractId: string) => Promise<ContractState>;
coreAPI: HathorCoreAPI;
connectWallet: () => Promise<void>;
disconnectWallet: () => Promise<void>;
switchNetwork: (network: Network) => Promise<void>;
}- QUICKSTART.md: Step-by-step guide to get started quickly
- CONTRACT_INTEGRATION.md: Detailed guide for integrating your contracts
- CLAUDE.md: Architecture documentation for AI assistance
- Issues: GitHub Issues
- Discord: Hathor Network Discord
- Documentation: Hathor Docs
MIT License - see LICENSE file for details
Ready to build? Check out QUICKSTART.md to get your first contract integration working in minutes.