Quickstart Guide
Integrate KhipuVault into your app in 5 minutes. Make your first deposit using Wagmi and Viem.
Quickstart Guide
Get your first KhipuVault integration running in under 5 minutes. This guide shows you how to read pool data and make a deposit using React, Wagmi, and Viem.
Prerequisites
Before you start:
- Node.js 18+ installed
- Basic understanding of React and TypeScript
- MetaMask or another Web3 wallet
- MUSD tokens on Mezo testnet (Get MUSD →)
Step 1: Install Dependencies
npm install wagmi viem @tanstack/react-queryOr with pnpm:
pnpm add wagmi viem @tanstack/react-queryStep 2: Configure Mezo Testnet
Create a chains.ts file:
import { defineChain } from 'viem'
export const mezoTestnet = defineChain({
id: 31611,
name: 'Mezo Testnet',
network: 'mezo-testnet',
nativeCurrency: {
decimals: 18,
name: 'Bitcoin',
symbol: 'BTC',
},
rpcUrls: {
default: {
http: ['https://rpc.test.mezo.org'],
},
public: {
http: ['https://rpc.test.mezo.org'],
},
},
blockExplorers: {
default: {
name: 'Mezo Explorer',
url: 'https://explorer.test.mezo.org'
},
},
testnet: true,
})Step 3: Set Up Wagmi Config
Create a wagmi.config.ts file:
import { http, createConfig } from 'wagmi'
import { mezoTestnet } from './chains'
import { injected, metaMask } from 'wagmi/connectors'
export const config = createConfig({
chains: [mezoTestnet],
connectors: [
injected(),
metaMask(),
],
transports: {
[mezoTestnet.id]: http(),
},
})Step 4: Wrap Your App with Providers
Update your App.tsx or layout.tsx:
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { config } from './wagmi.config'
const queryClient = new QueryClient()
function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{/* Your app components */}
<YourApp />
</QueryClientProvider>
</WagmiProvider>
)
}Step 5: Add Contract Constants
Create a contracts.ts file:
export const INDIVIDUAL_POOL_ADDRESS = '0xdfBEd2D3efBD2071fD407bF169b5e5533eA90393' as const
export const MUSD_ADDRESS = '0x118917a40FAF1CD7a13dB0Ef56C86De7973Ac503' as const
// Minimal ABI - just the functions we need
export const INDIVIDUAL_POOL_ABI = [
{
name: 'deposit',
type: 'function',
stateMutability: 'nonpayable',
inputs: [{ name: 'amount', type: 'uint256' }],
outputs: [],
},
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
},
{
name: 'totalDeposits',
type: 'function',
stateMutability: 'view',
inputs: [],
outputs: [{ name: '', type: 'uint256' }],
},
] as const
export const MUSD_ABI = [
{
name: 'approve',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'spender', type: 'address' },
{ name: 'amount', type: 'uint256' }
],
outputs: [{ name: '', type: 'bool' }],
},
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
},
] as constStep 6: Read Pool Data
Create a component to display pool information:
import { useReadContract, useAccount } from 'wagmi'
import { formatUnits } from 'viem'
import { INDIVIDUAL_POOL_ADDRESS, INDIVIDUAL_POOL_ABI } from './contracts'
export function PoolStats() {
const { address } = useAccount()
// Read total deposits
const { data: totalDeposits } = useReadContract({
address: INDIVIDUAL_POOL_ADDRESS,
abi: INDIVIDUAL_POOL_ABI,
functionName: 'totalDeposits',
})
// Read user balance
const { data: userBalance } = useReadContract({
address: INDIVIDUAL_POOL_ADDRESS,
abi: INDIVIDUAL_POOL_ABI,
functionName: 'balanceOf',
args: address ? [address] : undefined,
})
return (
<div>
<h2>Pool Statistics</h2>
<p>Total Deposits: {totalDeposits ? formatUnits(totalDeposits, 18) : '0'} MUSD</p>
<p>Your Balance: {userBalance ? formatUnits(userBalance, 18) : '0'} MUSD</p>
</div>
)
}Step 7: Make Your First Deposit
Create a deposit component:
import { useState } from 'react'
import { useAccount, useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
import { parseUnits } from 'viem'
import {
INDIVIDUAL_POOL_ADDRESS,
INDIVIDUAL_POOL_ABI,
MUSD_ADDRESS,
MUSD_ABI
} from './contracts'
export function DepositForm() {
const [amount, setAmount] = useState('')
const { address } = useAccount()
const { writeContract, data: hash, isPending } = useWriteContract()
// Wait for transaction confirmation
const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
hash,
})
const handleApprove = async () => {
if (!amount) return
// First, approve MUSD spending
writeContract({
address: MUSD_ADDRESS,
abi: MUSD_ABI,
functionName: 'approve',
args: [INDIVIDUAL_POOL_ADDRESS, parseUnits(amount, 18)],
})
}
const handleDeposit = async () => {
if (!amount) return
// Then deposit
writeContract({
address: INDIVIDUAL_POOL_ADDRESS,
abi: INDIVIDUAL_POOL_ABI,
functionName: 'deposit',
args: [parseUnits(amount, 18)],
})
}
return (
<div>
<h2>Deposit MUSD</h2>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount (MUSD)"
/>
<button
onClick={handleApprove}
disabled={!address || isPending || !amount}
>
1. Approve
</button>
<button
onClick={handleDeposit}
disabled={!address || isPending || !amount}
>
2. Deposit
</button>
{isPending && <p>Check your wallet...</p>}
{isConfirming && <p>Waiting for confirmation...</p>}
{isSuccess && <p>Deposit successful! 🎉</p>}
</div>
)
}Step 8: Put It All Together
Final App.tsx:
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useConnect, useAccount, useDisconnect } from 'wagmi'
import { config } from './wagmi.config'
import { PoolStats } from './PoolStats'
import { DepositForm } from './DepositForm'
const queryClient = new QueryClient()
function ConnectWallet() {
const { connectors, connect } = useConnect()
const { address, isConnected } = useAccount()
const { disconnect } = useDisconnect()
if (isConnected) {
return (
<div>
<p>Connected: {address}</p>
<button onClick={() => disconnect()}>Disconnect</button>
</div>
)
}
return (
<div>
{connectors.map((connector) => (
<button key={connector.id} onClick={() => connect({ connector })}>
Connect {connector.name}
</button>
))}
</div>
)
}
function KhipuVaultApp() {
const { isConnected } = useAccount()
return (
<div>
<h1>KhipuVault Quickstart</h1>
<ConnectWallet />
{isConnected && (
<>
<PoolStats />
<DepositForm />
</>
)}
</div>
)
}
export default function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<KhipuVaultApp />
</QueryClientProvider>
</WagmiProvider>
)
}Run Your App
npm run dev
# or
pnpm devVisit http://localhost:3000, connect your wallet, and make your first deposit!
What's Next?
Complete ABIs
Full contract interfaces and methods
More Examples
Withdrawals, pool creation, yield tracking
API Integration
Backend API for analytics and user data
Event Indexing
Listen to blockchain events in real-time
Common Issues
Transaction Fails: "Insufficient Allowance"
You need to approve MUSD spending before depositing. Always call approve() on the MUSD contract first.
// Step 1: Approve
await writeContract({
address: MUSD_ADDRESS,
abi: MUSD_ABI,
functionName: 'approve',
args: [INDIVIDUAL_POOL_ADDRESS, parseUnits('100', 18)]
})
// Step 2: Deposit (after approval confirms)
await writeContract({
address: INDIVIDUAL_POOL_ADDRESS,
abi: INDIVIDUAL_POOL_ABI,
functionName: 'deposit',
args: [parseUnits('100', 18)]
})Network Mismatch
Make sure MetaMask is connected to Mezo Testnet (Chain ID 31611). Add it manually:
No MUSD Balance
Get free test tokens from the faucet:
Full Source Code
Complete working example on GitHub:
github.com/khipuvault/examples/quickstart
Next Steps
Explore Other Contracts
Learn about CooperativePool, LotteryPool, and more.
Integrate Backend API
Use our REST API for user profiles, analytics, and notifications.
Set Up Event Indexing
Index blockchain events to your database.
Questions? Join our Discord #developers channel or email dev@khipuvault.com