This guide explains how to use the Stellar network switching feature in Hunty, allowing users and developers to toggle between testnet and mainnet.
Hunty now supports seamless switching between Stellar's testnet and mainnet networks. This enables:
- Development & Testing: Use testnet for safe development with test XLM
- Production Deployment: Switch to mainnet for real transactions with actual assets
- Network Awareness: Visual indicators showing which network you're using
- Contract Separation: Different smart contract addresses per network
Visual badges show the current network throughout the app:
- Header Badge: Small pill indicator in the top navigation bar
- Testnet Warning Banner: Dismissible banner when on testnet
- Corner Badge: Fixed position indicator (optional)
Components:
NetworkIndicator.tsx- Displays current network with visual stylesTestnetWarning.tsx- Warning banner for testnet usage
Access network settings via the Settings page (/settings):
- Navigate to Settings from the header menu
- Find the Network Settings card
- Choose between Testnet or Mainnet
- Confirm the switch (page will reload)
Components:
NetworkSwitcher.tsx- Interactive network selection UIapp/settings/page.tsx- Settings page with network controls
The app attempts to detect the wallet's network configuration:
- Checks Freighter and Rabet wallet network settings
- Displays warnings if wallet network doesn't match app network
- Prevents transaction failures due to network mismatches
Implementation:
lib/wallets/networkDetection.ts- Wallet network detection utilitiesNetworkMismatchWarning.tsx- Warning UI for network mismatches
Multiple warning mechanisms ensure users know they're on testnet:
- Top Banner: Persistent banner with dismiss option
- Network Badge: Yellow badge indicating testnet
- Settings Page: Clear visual distinction in network switcher
Smart contracts use network-specific addresses:
# Testnet Contracts
NEXT_PUBLIC_HUNTY_CORE_ADDRESS_TESTNET=CA...
NEXT_PUBLIC_REWARD_MANAGER_ADDRESS_TESTNET=CA...
NEXT_PUBLIC_NFT_REWARD_ADDRESS_TESTNET=CA...
# Mainnet Contracts
NEXT_PUBLIC_HUNTY_CORE_ADDRESS_MAINNET=CA...
NEXT_PUBLIC_REWARD_MANAGER_ADDRESS_MAINNET=CA...
NEXT_PUBLIC_NFT_REWARD_ADDRESS_MAINNET=CA...The app automatically uses the correct contract addresses based on the active network.
Update your .env.local or deployment environment variables:
# Network Configuration (default: testnet)
NEXT_PUBLIC_SOROBAN_NETWORK_TYPE=testnet
# Testnet Configuration
NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
NEXT_PUBLIC_SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
# Mainnet Configuration (for production)
# NEXT_PUBLIC_SOROBAN_RPC_URL=https://soroban-mainnet.stellar.org
# NEXT_PUBLIC_SOROBAN_NETWORK_PASSPHRASE=Public Global Stellar Network ; September 2015
# Contract Addresses - Testnet
NEXT_PUBLIC_HUNTY_CORE_ADDRESS_TESTNET=
NEXT_PUBLIC_REWARD_MANAGER_ADDRESS_TESTNET=
NEXT_PUBLIC_NFT_REWARD_ADDRESS_TESTNET=
# Contract Addresses - Mainnet
NEXT_PUBLIC_HUNTY_CORE_ADDRESS_MAINNET=
NEXT_PUBLIC_REWARD_MANAGER_ADDRESS_MAINNET=
NEXT_PUBLIC_NFT_REWARD_ADDRESS_MAINNET=The app determines the active network in this order:
- User Preference (localStorage): User's manual network selection from settings
- Environment Variable:
NEXT_PUBLIC_SOROBAN_NETWORK_TYPE - Default: Falls back to
testnetif neither is set
- Click Settings in the header navigation
- Locate the Network Settings section
- Click on your desired network (Testnet or Mainnet)
- Confirm the switch in the modal
- The page will reload with the new network active
- Yellow Badge = Testnet (test XLM, safe for testing)
- Green Badge = Mainnet (real XLM, production environment)
- If your wallet network doesn't match the app network, you'll see an orange warning banner
- Click "Go to Settings" to switch networks or dismiss the warning
import { useNetwork } from "@/hooks/useNetwork"
function MyComponent() {
const {
networkType, // "testnet" | "mainnet"
isTestnet, // boolean
isMainnet, // boolean
rpcUrl, // Current RPC URL
networkPassphrase,// Current network passphrase
switchNetwork, // Function to switch networks
config // Full network config
} = useNetwork()
return (
<div>
<p>Current Network: {networkType}</p>
{isTestnet && <p>Using test XLM</p>}
<button onClick={() => switchNetwork("mainnet")}>
Switch to Mainnet
</button>
</div>
)
}import { getContracts, getRequiredAddress } from "@/lib/contracts/config"
// Get all contracts for current network
const contracts = getContracts()
console.log(contracts.HUNTY_CORE)
console.log(contracts.REWARD_MANAGER)
console.log(contracts.NFT_REWARD)
// Get a specific required address (throws if not set)
const rewardManager = getRequiredAddress("REWARD_MANAGER")import {
getSorobanNetworkType,
setSorobanNetworkType,
getCurrentNetworkConfig
} from "@/lib/soroban/client"
// Get current network
const network = getSorobanNetworkType() // "testnet" | "mainnet"
// Switch network programmatically
setSorobanNetworkType("mainnet")
// Get full network config
const config = getCurrentNetworkConfig()
// { rpcUrl, networkPassphrase, networkType }import {
checkWalletNetworkMatch,
validateNetworkBeforeTransaction
} from "@/lib/wallets/networkDetection"
// Check for network mismatch
const mismatch = await checkWalletNetworkMatch("freighter")
if (mismatch) {
console.warn(mismatch.message)
// Show warning to user
}
// Validate before transaction
const { valid, error } = await validateNetworkBeforeTransaction("freighter")
if (!valid) {
alert(`Network mismatch: ${error?.message}`)
return
}
// Proceed with transaction
await signTransaction(...)lib/
├── soroban/
│ └── client.ts # Network config & RPC client
├── contracts/
│ └── config.ts # Contract addresses per network
├── wallets/
│ └── networkDetection.ts # Wallet network detection
├── walletConnect.ts # WalletConnect with network support
└── config/
└── environment.ts # Environment configuration
components/
├── NetworkIndicator.tsx # Network badge components
├── NetworkSwitcher.tsx # Network selection UI
├── NetworkMismatchWarning.tsx # Warning for network mismatches
└── Header.tsx # Updated with network badge
hooks/
└── useNetwork.ts # Network management hook
app/
├── layout.tsx # TestnetWarning added
├── providers.tsx # NetworkMismatchWarning added
└── settings/
└── page.tsx # Settings page with NetworkSwitcher
- User selects network →
NetworkSwitchercomponent - Saves to localStorage →
stellar_network_preference - Calls
setSorobanNetworkType()→ Updates network state - Page reloads → Reinitializes with new network
- All components read network → Via
useNetwork()hook - Contracts load correct addresses → Via
getContracts() - Wallet detection validates → Via
checkWalletNetworkMatch()
- Switch from testnet to mainnet in settings
- Verify page reloads after switch
- Check network badge updates in header
- Confirm testnet warning appears on testnet
- Verify testnet warning dismisses
- Test network mismatch warning appears
- Connect wallet and verify network detection
- Check contract addresses change per network
- Verify WalletConnect uses correct chain ID
- Test in different browsers (localStorage is per-origin)
// Test network switching
import { getSorobanNetworkType, setSorobanNetworkType } from "@/lib/soroban/client"
// Mock localStorage
const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
}
global.localStorage = localStorageMock as any
// Test setting network
setSorobanNetworkType("mainnet")
expect(localStorageMock.setItem).toHaveBeenCalledWith(
"stellar_network_preference",
"mainnet"
)# .env.production
NEXT_PUBLIC_SOROBAN_NETWORK_TYPE=testnet
NEXT_PUBLIC_HUNTY_CORE_ADDRESS_TESTNET=CABC...
NEXT_PUBLIC_REWARD_MANAGER_ADDRESS_TESTNET=CDEF...
NEXT_PUBLIC_NFT_REWARD_ADDRESS_TESTNET=CGHI...# .env.production
NEXT_PUBLIC_SOROBAN_NETWORK_TYPE=mainnet
NEXT_PUBLIC_HUNTY_CORE_ADDRESS_MAINNET=CJKL...
NEXT_PUBLIC_REWARD_MANAGER_ADDRESS_MAINNET=CMNO...
NEXT_PUBLIC_NFT_REWARD_ADDRESS_MAINNET=CPQR...For production apps, consider:
-
Separate Deployments: Deploy testnet and mainnet versions separately
testnet.hunty.app→ Testnet onlyhunty.app→ Mainnet only
-
Single Deployment with Toggle: Allow runtime switching (current implementation)
- Users can toggle between networks in settings
- Useful for developers and power users
-
Environment-Locked: Lock network per environment
- Staging → Always testnet
- Production → Always mainnet
- Disable network switcher in UI
- Contract Address Validation: Always validate contract addresses are set before use
- Network Mismatch Prevention: App warns users about wallet/app network mismatches
- Transaction Confirmation: Show network type in transaction confirmation modals
- Clear Visual Indicators: Users always know which network they're using
- Mainnet Warnings: Consider additional warnings for mainnet transactions
- Check browser console for errors
- Verify localStorage is enabled
- Try clearing browser cache and localStorage
- Ensure environment variables are set correctly
- Ensure your wallet (Freighter, etc.) is on the correct network
- Check wallet settings/preferences
- Reconnect wallet after switching networks
- Verify contract addresses are set for the active network
- Check environment variables in deployment
- Ensure contracts are deployed to the correct network
- Check for JavaScript errors preventing reload
- Manually refresh the page
- Clear browser cache
- Auto-detect wallet network on connection and auto-switch app
- Network history/switching analytics
- More granular network indicators per transaction
- Network-specific theming
- Testnet faucet integration
- Network-specific feature flags
- Multi-signature network switching (for teams)
For issues or questions:
- Open an issue on GitHub
- Check existing documentation
- Review Stellar network documentation: https://developers.stellar.org/docs
Last Updated: January 2025 Version: 1.0.0