Web Application Integration
Learn how to integrate the Tap Ants Voucher System into your web application.
Overview
Integrating the Tap Ants Voucher System into your web application allows you to offer voucher-based rewards, loyalty programs, or other incentives to your users. This guide will walk you through the process of connecting your web application to the Tap Ants Voucher System using wagmi and viem.
Prerequisites
- Web Development Environment: A modern web development setup with Node.js and npm/yarn.
- Web3 Knowledge: Basic understanding of Ethereum and web3 concepts.
- Wallet Integration: A way for users to connect their Ethereum wallets (e.g., MetaMask).
Integration Steps
1. Install Dependencies
Install wagmi and related packages
Terminalnpm install wagmi viem @tanstack/react-query
2. Set Up wagmi Client
Configure wagmi
JavaScript// config.ts
import { createConfig, http } from 'wagmi'
import { sepolia } from 'wagmi/chains'
// Contract addresses
export const VOUCHER_ADDRESS = '0x4223f47b1EB3bDB97d0117Ae50e2cC65309c22AE'
export const REDEEM_ADDRESS = '0x6cD3B9C6a28851377FCf305D3C269C328797Cc5E'
export const TOKEN_ADDRESS = '0x8f71a7503284c69eb200605b5ab11fabc555c865'
// Create config
export const config = createConfig({
chains: [sepolia],
transports: {
[sepolia.id]: http(),
},
})
3. Set Up Contract ABIs
Create ABI files
JavaScript// abis.ts
export const voucherAbi = [
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ type: 'uint256' }]
},
{
name: 'approve',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'spender', type: 'address' },
{ name: 'amount', type: 'uint256' }
],
outputs: [{ type: 'bool' }]
},
{
name: 'allowance',
type: 'function',
stateMutability: 'view',
inputs: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' }
],
outputs: [{ type: 'uint256' }]
}
];
export const redeemAbi = [
{
name: 'redeem',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'voucherToken', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'data', type: 'bytes' }
],
outputs: []
},
{
name: 'selfRedeem',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'voucherToken', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'data', type: 'bytes' }
],
outputs: []
},
{
name: 'getSupportedVoucher',
type: 'function',
stateMutability: 'view',
inputs: [{ name: '_voucherAddress', type: 'address' }],
outputs: [
{ name: '', type: 'address' },
{ name: '', type: 'uint256' },
{ name: '', type: 'bool' }
]
}
];
export const tokenAbi = [
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'owner', type: 'address' }],
outputs: [{ type: 'uint256' }]
},
{
name: 'transfer',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' }
],
outputs: [{ type: 'bool' }]
}
];
4. Implement Voucher Balance Check
Check voucher balance
React Componentimport { useAccount, useReadContract } from 'wagmi'
import { formatUnits } from 'viem'
import { VOUCHER_ADDRESS, voucherAbi } from './config'
export function VoucherBalance() {
const { address } = useAccount()
const { data: balance, isLoading, isError } = useReadContract({
address: VOUCHER_ADDRESS,
abi: voucherAbi,
functionName: 'balanceOf',
args: [address],
enabled: !!address,
})
if (isLoading) return <div>Loading balance...</div>
if (isError) return <div>Error loading balance</div>
return (
<div className="p-4 border rounded-lg">
<h2 className="text-xl font-bold mb-2">Your Voucher Balance</h2>
<p className="text-2xl">{balance ? formatUnits(balance, 18) : '0'} TAV</p>
</div>
)
}
5. Implement Voucher Redemption
Redeem vouchers
React Componentimport { useState } from 'react'
import { useAccount, useReadContract, useWriteContract, useWaitForTransactionReceipt } from 'wagmi'
import { parseUnits, formatUnits } from 'viem'
import { VOUCHER_ADDRESS, REDEEM_ADDRESS, voucherAbi, redeemAbi } from './config'
export function RedeemVouchers() {
const { address } = useAccount()
const [amount, setAmount] = useState('')
const [status, setStatus] = useState('')
// Check allowance
const { data: allowance } = useReadContract({
address: VOUCHER_ADDRESS,
abi: voucherAbi,
functionName: 'allowance',
args: [address, REDEEM_ADDRESS],
enabled: !!address,
})
// Approve vouchers
const { data: approveHash, writeContract: approve } = useWriteContract()
// Wait for approval transaction
const { isLoading: isApproving, isSuccess: isApproved } = useWaitForTransactionReceipt({
hash: approveHash,
})
// Redeem vouchers
const { data: redeemHash, writeContract: redeem } = useWriteContract()
// Wait for redeem transaction
const { isLoading: isRedeeming, isSuccess: isRedeemed } = useWaitForTransactionReceipt({
hash: redeemHash,
})
const handleRedeem = async () => {
if (!amount) return
setStatus('Starting redemption process...')
try {
const amountInWei = parseUnits(amount, 18)
// Check if we need to approve first
if (!allowance || allowance < amountInWei) {
setStatus('Approving vouchers...')
await approve({
address: VOUCHER_ADDRESS,
abi: voucherAbi,
functionName: 'approve',
args: [REDEEM_ADDRESS, amountInWei],
})
setStatus('Waiting for approval confirmation...')
}
// Now redeem the vouchers
setStatus('Redeeming vouchers...')
await redeem({
address: REDEEM_ADDRESS,
abi: redeemAbi,
functionName: 'selfRedeem',
args: [VOUCHER_ADDRESS, amountInWei, '0x'],
})
setStatus('Waiting for redemption confirmation...')
if (isRedeemed) {
setStatus('Vouchers redeemed successfully!')
setAmount('')
}
} catch (error) {
console.error('Error redeeming vouchers:', error)
setStatus('Error: ' + (error.message || 'Failed to redeem vouchers'))
}
}
return (
<div className="p-4 border rounded-lg">
<h2 className="text-xl font-bold mb-4">Redeem Vouchers</h2>
<div className="mb-4">
<label className="block text-sm font-medium mb-1">Amount to Redeem</label>
<input
type="text"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter amount"
className="w-full p-2 border rounded"
disabled={isApproving || isRedeeming}
/>
</div>
<button
onClick={handleRedeem}
disabled={!amount || isApproving || isRedeeming}
className="w-full bg-blue-600 text-white py-2 px-4 rounded disabled:opacity-50"
>
{isApproving ? 'Approving...' : isRedeeming ? 'Redeeming...' : 'Redeem Vouchers'}
</button>
{status && (
<div className="mt-4 p-3 bg-gray-100 rounded text-sm">
{status}
</div>
)}
</div>
)
}
6. Create a Complete React Component
Voucher Dashboard Component
React Componentimport { useState } from 'react'
import { useAccount } from 'wagmi'
import { VoucherBalance } from './VoucherBalance'
import { RedeemVouchers } from './RedeemVouchers'
import { WagmiConfig } from 'wagmi'
import { config } from './config'
export function VoucherDashboard() {
const { isConnected } = useAccount()
return (
<WagmiConfig config={config}>
<div className="max-w-md mx-auto">
<h1 className="text-2xl font-bold mb-6">Tap Ants Voucher Dashboard</h1>
{!isConnected ? (
<div className="p-4 border rounded-lg text-center">
<p className="mb-4">Please connect your wallet to continue</p>
<ConnectButton />
</div>
) : (
<div className="space-y-6">
<VoucherBalance />
<RedeemVouchers />
</div>
)}
</div>
</WagmiConfig>
)
}
// Simple connect button component
function ConnectButton() {
const { connect } = useConnect({
connector: new InjectedConnector(),
})
return (
<button
onClick={() => connect()}
className="bg-blue-600 text-white py-2 px-4 rounded"
>
Connect Wallet
</button>
)
}
Best Practices
- Error Handling: Implement comprehensive error handling to provide clear feedback to users when transactions fail.
- Loading States: Show loading indicators during blockchain transactions to improve user experience.
- Transaction Confirmation: Wait for transaction confirmations before updating the UI to reflect changes.
- Gas Estimation: Estimate gas costs for transactions and inform users before they confirm.
- Network Detection: Detect the connected network and warn users if they're not on the correct network (Sepolia testnet).
Advanced Integration
Admin Dashboard
For administrators, you can create a dashboard to manage vouchers and redemption rules:
- Mint new vouchers to users
- Add or remove supported vouchers
- Update conversion rates
- View redemption history
User Dashboard
For users, you can create a dashboard to manage their vouchers:
- View voucher balances across different seasons
- Redeem vouchers for tokens
- View redemption history
- Transfer redemption tokens to other users