For the complete documentation index, see llms.txt. This page is also available as Markdown.

Build an App on KUB

This guide walks you through building an on-chain demo Tally app on the KUB Testnet: connecting wallets, reading and writing to a deployed counter contract, and understanding when to reach for the KUB SDK instead of standard wallet connectors.

What you will build

  • A Next.js app that connects EVM wallets (MetaMask and other injected wallets)

  • Contract reads and writes

  • An understanding of the two wallets on KUB: standard Web3 wallets and KUB Wallet

Start Building

Set up your project

npx create-next-app@latest my-kub-app --typescript --tailwind --app
cd my-kub-app
npm install wagmi viem @tanstack/react-query

Define the KUB networks and configure Wagmi

viem ships chain definitions for KUB (exported as bitkub / bitkubTestnet in viem/chainsCheck your installed version. Defining the chains explicitly with defineChain also works on any version and makes the config self-documenting:

// config/chains.ts
import { defineChain } from 'viem'

export const kubTestnet = defineChain({
  id: 25925,
  name: 'KUB Testnet',
  nativeCurrency: { name: 'tKUB', symbol: 'tKUB', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://rpc-testnet.kubchain.io'] },
  },
  blockExplorers: {
    default: { name: 'KUB Scan Testnet', url: 'https://testnet.kubscan.com' },
  },
  testnet: true,
})

export const kubMainnet = defineChain({
  id: 96,
  name: 'KUB Mainnet',
  nativeCurrency: { name: 'KUB', symbol: 'KUB', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://rpc.kubchain.io'] },
  },
  blockExplorers: {
    default: { name: 'KUB Scan', url: 'https://kubscan.com' },
  },
})

ssr: true combined with cookieStorage prevents Next.js hydration mismatches. This pairs with the cookieToInitialState call in the root layout below, which restores the connection state on the server so it does not flash on load. The injected connector handles browser extension wallets like MetaMask, which connect to KUB as a custom network.

Wrap your app in the providers

The providers component accepts an initialState prop so the layout can pass in the connection state recovered from cookies:

Wire the providers into the root layout

Wrap {children} with Providers in app/layout.tsx. This step is required: any component calling a wagmi hook outside WagmiProvider crashes at runtime with useConfig must be used within WagmiProvider. Reading the cookie here and converting it with cookieToInitialState completes the SSR setup, so a returning user's connection state is already correct on first render instead of flashing through Reconnecting...:

headers() is asynchronous in recent Next.js versions, so the root layout is declared async and the call is awaited. If you are on an older Next.js where headers() is synchronous, drop the await.

Connect wallets

useAccount exposes four states: isConnecting, isReconnecting, isConnected, and isDisconnected. Checking only isConnected causes UI flashes on page load. Ensure you handle all four states.

Deploy the contract

Follow this guide to deploy Counter.sol to KUB Testnet with Foundry, funded by the KUB Faucet. Please take note of the deployed address.

Read contract data

as const is required. Without it, wagmi cannot infer function names, argument types, or return types from the ABI.

Write to the contract

Without useSwitchChain, calling writeContract while the wallet is on the wrong network causes wagmi to attempt a background chain switch. If the user misses the wallet popup, the button stays at "Confirm in Wallet..." indefinitely with no error and no recovery path. Since KUB is a custom network in MetaMask, users landing on your app for the first time are very often on the wrong chain; handle this state.

Assemble the page

Optional: Reach KUB Wallet users with the NEXT SDK

The integration differs from the wagmi flow in two important ways:

  1. Install @bitkub-chain/sdk.js, initialize it with a Client ID and Project ID (from the KUB Playground for KUB Testnet), and authenticate users via OAuth rather than a wallet popup

  1. KUB Wallet users transact through the CallHelper router, so any write function they call needs an extra trailing address _bitkubNext parameter and a guard restricting the caller to the SDK CallHelper Router

Transactions then go through sdk.sendCustomTx(toAddress, functionReadableABI, methodParams) rather than writeContract. A production KUB app typically supports both paths: wagmi/injected for MetaMask users, NEXT SDK for KUB Wallet users. See the NEXT SDK and the Code Cookbook for working examples.

Next Steps

  • Go to KUB Mainnet: add kubMainnet to your chains array and transports, redeploy your contract, and update COUNTER_ADDRESS.

  • Scale on KUB Layer 2: the rollup-based L2 (chain ID 9601 mainnet / 259251 testnet) offers lower costs for high-frequency apps; bridge tKUB from the faucet flow to the L2 testnet to experiment.

  • Bridge assets in: KUB Bridge supports Ethereum, BNB Smart Chain, and JFIN Chain, so users can bring assets to your app.

  • Get listed: submit your dApp via the KUB Developer Center to appear in the KUB Ecosystem directory.

Last updated