@notdotmarket/dbc-hooks
v0.7.9
Published
React hooks for Dynamic Bonding Curve SDK with React Query integration and Reown AppKit support
Maintainers
Readme
@notdotmarket/dbc-hooks
React hooks for the Dynamic Bonding Curve SDK, built with React Query and fully integrated with Reown AppKit for seamless wallet management.
Features
- ✅ Reown AppKit Integration - Built-in support for Reown AppKit at the provider level
- ✅ Universal Wallet Support - Works with any Solana wallet (Phantom, Solflare, Backpack, etc.)
- ✅ Plug and Play - No manual wallet adapter management needed
- ✅ React Query Powered - Automatic caching, refetching, and state management
- ✅ Complete SDK Coverage - 16 hooks covering all Dynamic Bonding Curve operations
- ✅ TypeScript First - Full type safety and IntelliSense support
- ✅ Multiple Swap Modes - ExactIn, ExactOut, and PartialFill support
Installation
# Install the hooks package
npm install @notdotmarket/dbc-hooks @tanstack/react-query
# Install Reown AppKit (recommended)
npm install @reown/appkit @reown/appkit-adapter-solana
# Or use with standard wallet adapter
npm install @solana/wallet-adapter-react @solana/wallet-adapter-walletsQuick Start with Reown AppKit
1. Setup Reown AppKit + DBC Provider
import { createAppKit } from '@reown/appkit/react'
import { SolanaAdapter } from '@reown/appkit-adapter-solana'
import { DbcAppKitProvider } from '@notdotmarket/dbc-hooks'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { Connection } from '@solana/web3.js'
import { solanaDevnet } from '@reown/appkit/networks'
// 1. Setup React Query
const queryClient = new QueryClient()
// 2. Setup Reown AppKit
const projectId = 'YOUR_PROJECT_ID' // Get from https://dashboard.reown.com
const solanaAdapter = new SolanaAdapter({
networks: [solanaDevnet]
})
createAppKit({
adapters: [solanaAdapter],
networks: [solanaDevnet],
projectId,
metadata: {
name: 'Your DApp',
description: 'Your DApp Description',
url: 'https://yourdapp.com',
icons: ['https://yourdapp.com/icon.png']
},
features: {
analytics: true
}
})
// 3. Setup DBC with Solana connection
const connection = new Connection('https://api.devnet.solana.com')
function App() {
return (
<QueryClientProvider client={queryClient}>
<DbcAppKitProvider connection={connection}>
<YourApp />
</DbcAppKitProvider>
</QueryClientProvider>
)
}2. Use in Your Components
import { useAppKitAccount, useAppKitProvider } from '@reown/appkit/react'
import { useSwap, usePoolInfo } from '@notdotmarket/dbc-hooks'
import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
function TradingComponent() {
// Get wallet state from Reown AppKit
const { address, isConnected } = useAppKitAccount()
const { walletProvider } = useAppKitProvider('solana')
// Get pool info
const { data: poolInfo } = usePoolInfo(poolAddress)
// Setup swap mutation
const swap = useSwap()
const handleSwap = async () => {
if (!isConnected || !walletProvider || !address) {
alert('Please connect your wallet')
return
}
try {
const result = await swap.mutateAsync({
wallet: walletProvider, // Pass Reown wallet provider directly
pool: new PublicKey(poolAddress),
owner: new PublicKey(address),
amountIn: new BN(1000000),
minimumAmountOut: new BN(900000),
swapBaseForQuote: false,
referralTokenAccount: null,
})
console.log('Swap successful!', result.signature)
} catch (error) {
console.error('Swap failed:', error)
}
}
return (
<div>
<appkit-button />
{isConnected && (
<button onClick={handleSwap} disabled={swap.isPending}>
{swap.isPending ? 'Swapping...' : 'Swap Tokens'}
</button>
)}
</div>
)
}Complete Trading Example
import { useAppKitAccount, useAppKitProvider } from '@reown/appkit/react'
import {
useSwap,
useSwapQuote,
usePoolInfo,
useFeeBreakdown,
useWithdraw
} from '@notdotmarket/dbc-hooks'
import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
function CompleteTrading() {
const { address, isConnected } = useAppKitAccount()
const { walletProvider } = useAppKitProvider('solana')
const poolAddress = new PublicKey('YOUR_POOL_ADDRESS')
// Fetch pool data
const { data: poolInfo, isLoading } = usePoolInfo(poolAddress)
const { data: fees } = useFeeBreakdown(poolAddress)
// Get swap quote
const { data: quote } = useSwapQuote({
poolAddress,
amountIn: new BN(1000000),
swapBaseForQuote: false,
slippageBps: 100,
hasReferral: false,
})
// Mutations
const swap = useSwap()
const withdraw = useWithdraw()
const handleSwap = async () => {
if (!walletProvider || !address) return
await swap.mutateAsync({
wallet: walletProvider,
pool: poolAddress,
owner: new PublicKey(address),
amountIn: new BN(1000000),
minimumAmountOut: quote?.minimumAmountOut || new BN(0),
swapBaseForQuote: false,
referralTokenAccount: null,
})
}
const handleWithdrawFees = async () => {
if (!walletProvider || !address) return
await withdraw.mutateAsync({
wallet: walletProvider,
pool: poolAddress,
owner: new PublicKey(address),
type: 'creatorTradingFee',
})
}
if (isLoading) return <div>Loading pool data...</div>
return (
<div>
<h2>Pool Trading</h2>
{/* Wallet Connection */}
<appkit-button />
{/* Pool Info */}
{poolInfo && (
<div>
<p>Base Reserve: {poolInfo.pool.baseReserve.toString()}</p>
<p>Quote Reserve: {poolInfo.pool.quoteReserve.toString()}</p>
</div>
)}
{/* Swap Quote */}
{quote && (
<div>
<p>You will receive: {quote.outputAmount.toString()}</p>
<p>Trading fee: {quote.tradingFee.toString()}</p>
</div>
)}
{/* Trading Actions */}
{isConnected && (
<>
<button onClick={handleSwap} disabled={swap.isPending}>
{swap.isPending ? 'Swapping...' : 'Swap'}
</button>
<button onClick={handleWithdrawFees} disabled={withdraw.isPending}>
Withdraw Fees
</button>
</>
)}
{/* Fee Breakdown */}
{fees && (
<div>
<h3>Unclaimed Fees</h3>
<p>Creator Quote: {fees.creator.unclaimedQuoteFee.toString()}</p>
<p>Partner Quote: {fees.partner.unclaimedQuoteFee.toString()}</p>
</div>
)}
</div>
)
}Alternative: Standard Wallet Adapter
If you prefer using standard Solana wallet adapters instead of Reown AppKit:
import { WalletProvider, ConnectionProvider } from '@solana/wallet-adapter-react'
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'
import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'
import { DbcProvider } from '@notdotmarket/dbc-hooks'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { Connection } from '@solana/web3.js'
const queryClient = new QueryClient()
const connection = new Connection('https://api.devnet.solana.com')
const wallets = [
new PhantomWalletAdapter(),
new SolflareWalletAdapter(),
]
function App() {
return (
<QueryClientProvider client={queryClient}>
<ConnectionProvider endpoint="https://api.devnet.solana.com">
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
<DbcProvider connection={connection}>
<YourApp />
</DbcProvider>
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
</QueryClientProvider>
)
}
// Then use with useWallet hook
import { useWallet } from '@solana/wallet-adapter-react'
function TradingComponent() {
const wallet = useWallet()
const swap = useSwap()
const handleSwap = async () => {
if (!wallet.publicKey) return
await swap.mutateAsync({
wallet, // Pass wallet adapter directly
pool: poolAddress,
owner: wallet.publicKey,
// ...
})
}
}Available Hooks
Query Hooks (Read-only)
Pool Information
usePoolInfo(poolAddress)- Fetch pool and config datausePoolConfig(configAddress)- Fetch pool configurationusePools()- Fetch all poolsusePoolsByConfig(configAddress)- Pools by configusePoolsByCreator(creatorAddress)- Pools by creatorusePoolByBaseMint(mintAddress)- Pool by base token
Pool State & Metrics
usePoolCurveProgress(poolAddress)- Bonding curve progress (0-1)usePoolMetadata(poolAddress)- Pool metadatausePoolExpiryDays(poolAddress)- Days remaining until curve expires (null if no expiry)usePoolStats(poolAddress)- Pool statistics (tokens sold, amount raised, percent sold)useTokensSold(poolAddress)- Number of tokens solduseAmountRaised(poolAddress)- Amount of quote tokens (SOL) raisedusePoolMigrationQuoteThreshold(poolAddress)- Migration threshold
Pool Configurations
usePoolConfigs()- All pool configurationsusePoolConfigsByOwner(ownerAddress)- Configs by owner
Fee Information
useFeeBreakdown(poolAddress)- Detailed fee breakdownusePoolFeeMetrics(poolAddress)- Current fee metricsusePoolsFeesByConfig(configAddress)- Fees for config poolsusePoolsFeesByCreator(creatorAddress)- Fees for creator poolsuseSaleTax(params)- Check if sale tax is enabled and calculate tax amount
Partner & Migration
usePartnerMetadata(partnerAddress)- Partner metadatauseDammV1MigrationMetadata(poolAddress)- DAMM V1 migration datauseDammV1LockEscrow(poolAddress)- DAMM V1 lock escrow
Token Information
useTokenDetails(tokenMint, fetchMetadata?)- Comprehensive token details including metadata, decimals, supply, and logo
Trade Event Monitoring (Real-time)
useTradeEventListener(params)- Listen for real-time trade events and store in Redis for chartsuseTradeHistory(params)- Fetch historical trade events from Redis
Note: Trade event monitoring requires backend API implementation. See TRADE_EVENT_LISTENER.md for setup guide.
Swap Quotes
useSwapQuote(params)- Calculate swap quote (v1, exact input)useSwapQuote2(params)- Calculate swap quote (v2, multiple modes)
Note: Both swap quote hooks return a price field (number) which is the actual token price calculated from the sqrtPrice. This makes it easier to display human-readable prices without manual conversion.
Mutation Hooks (Write operations)
useSwap()- Execute swap transactionsuseWithdraw()- Withdraw fees and surplus
Swap Modes
enum SwapMode {
ExactIn = 0, // Specify exact input amount
PartialFill = 1, // Allow partial fills if liquidity insufficient
ExactOut = 2, // Specify exact output amount (calculates required input)
}Example usage:
// ExactIn: Specify how much to swap in
const { data } = useSwapQuote2({
poolAddress,
swapBaseForQuote: false,
swapMode: SwapMode.ExactIn,
amountIn: new BN(1000000),
slippageBps: 100,
})
// Access the actual price
if (data) {
console.log('Token Price:', data.price) // Human-readable price
console.log('Output Amount:', data.outputAmount.toString())
console.log('Trading Fee:', data.tradingFee.toString())
}
// ExactOut: Specify desired output
const { data } = useSwapQuote2({
poolAddress,
swapBaseForQuote: false,
swapMode: SwapMode.ExactOut,
amountOut: new BN(900000),
slippageBps: 100,
})Withdrawal Types
type WithdrawType =
| 'creatorSurplusQuote' // Creator withdraws surplus quote tokens
| 'partnerSurplusQuote' // Partner withdraws surplus quote tokens
| 'partnerSurplusBase' // Partner withdraws surplus base tokens (NoMigration pools)
| 'creatorTradingFee' // Creator withdraws trading fees
| 'partnerTradingFee' // Partner withdraws trading feesExample usage:
const { address } = useAppKitAccount()
const { walletProvider } = useAppKitProvider('solana')
const withdraw = useWithdraw()
await withdraw.mutateAsync({
wallet: walletProvider,
pool: poolAddress,
owner: new PublicKey(address),
type: 'creatorTradingFee',
})Pool Expiry Tracking
Track when a bonding curve expires with usePoolExpiryDays:
import { usePoolExpiryDays } from '@notdotmarket/dbc-hooks'
function PoolExpiryDisplay({ poolAddress }) {
const { data: daysLeft, isLoading } = usePoolExpiryDays(poolAddress)
if (isLoading) return <div>Loading...</div>
// null = no expiry set
if (daysLeft === null) {
return <div>⏰ No expiration</div>
}
// Expired
if (daysLeft <= 0) {
return <div className="text-red-500">🔒 Curve Expired</div>
}
// Active with expiry
const isExpiringSoon = daysLeft < 7
return (
<div className={isExpiringSoon ? 'text-yellow-500' : 'text-green-500'}>
⏱️ Expires in {daysLeft.toFixed(1)} days
{isExpiringSoon && ' ⚠️'}
</div>
)
}Token Details & Metadata
Fetch comprehensive token information including on-chain metadata, logo, symbol, decimals, and supply:
import { useTokenDetails } from '@notdotmarket/dbc-hooks'
import { PublicKey } from '@solana/web3.js'
function TokenDisplay({ tokenMint }) {
// fetchMetadata=true (default) will also fetch the JSON metadata from URI
const { data: token, isLoading } = useTokenDetails(tokenMint, true)
if (isLoading) return <div>Loading token info...</div>
if (!token) return <div>Token not found</div>
return (
<div className="token-card">
{/* Token Logo */}
{token.metadata?.logo && (
<img
src={token.metadata.logo}
alt={token.metadata.name}
className="token-logo"
/>
)}
{/* Token Identity */}
<div className="token-info">
<h3>{token.metadata?.name || 'Unknown Token'}</h3>
<p className="symbol">{token.metadata?.symbol || 'N/A'}</p>
{token.metadata?.description && (
<p className="description">{token.metadata.description}</p>
)}
</div>
{/* Token Stats */}
<div className="token-stats">
<div>
<label>Mint Address:</label>
<p>{token.mint.toString()}</p>
</div>
<div>
<label>Decimals:</label>
<p>{token.decimals}</p>
</div>
<div>
<label>Total Supply:</label>
<p>{(Number(token.supply) / Math.pow(10, token.decimals)).toLocaleString()}</p>
</div>
<div>
<label>Token Type:</label>
<p>{token.isToken2022 ? 'Token-2022' : 'SPL Token'}</p>
</div>
<div>
<label>Mint Authority:</label>
<p>{token.mintAuthority ? token.mintAuthority.toString() : 'Revoked ✓'}</p>
</div>
<div>
<label>Freeze Authority:</label>
<p>{token.freezeAuthority ? token.freezeAuthority.toString() : 'None'}</p>
</div>
{/* Metadata URI */}
{token.metadata?.uri && (
<div>
<label>Metadata:</label>
<a href={token.metadata.uri} target="_blank" rel="noopener noreferrer">
View Metadata
</a>
</div>
)}
</div>
</div>
)
}
// Example: Fetch metadata but skip JSON fetch for faster loading
function QuickTokenInfo({ tokenMint }) {
const { data: token } = useTokenDetails(tokenMint, false)
return (
<div>
<p>{token?.metadata?.symbol || 'Loading...'}</p>
<p>{token?.decimals} decimals</p>
</div>
)
}
// Example: Display token in a pool interface
function PoolTokenInfo({ poolAddress }) {
const { data: poolInfo } = usePoolInfo(poolAddress)
const { data: baseToken } = useTokenDetails(poolInfo?.baseMint)
const { data: quoteToken } = useTokenDetails(poolInfo?.quoteMint)
return (
<div className="pool-tokens">
<div className="base-token">
{baseToken?.metadata?.logo && (
<img src={baseToken.metadata.logo} alt="Base token" />
)}
<span>{baseToken?.metadata?.symbol}</span>
</div>
<span className="pair-separator">/</span>
<div className="quote-token">
{quoteToken?.metadata?.logo && (
<img src={quoteToken.metadata.logo} alt="Quote token" />
)}
<span>{quoteToken?.metadata?.symbol}</span>
</div>
</div>
)
}Return Type:
interface TokenDetails {
mint: PublicKey // Token mint address
decimals: number // Number of decimals
supply: string // Total supply in smallest units
mintAuthority: PublicKey | null // Null if revoked (fixed supply)
freezeAuthority: PublicKey | null // Null if no freeze authority
metadata?: TokenMetadata // On-chain metadata (if exists)
isToken2022: boolean // True for Token-2022, false for SPL
}
interface TokenMetadata {
name: string // Token name from on-chain metadata
symbol: string // Token symbol from on-chain metadata
uri: string // Metadata JSON URI
logo?: string // Logo/image URL from JSON metadata
image?: string // Image URL from JSON metadata
description?: string // Description from JSON metadata
}Pool Statistics (Tokens Sold & Amount Raised)
Track pool performance metrics:
import { usePoolStats, useTokensSold, useAmountRaised } from '@notdotmarket/dbc-hooks'
import { LAMPORTS_PER_SOL } from '@solana/web3.js'
// Option 1: Get all stats at once (recommended)
function PoolStatsDisplay({ poolAddress }) {
const { data: stats, isLoading } = usePoolStats(poolAddress)
if (isLoading) return <div>Loading stats...</div>
if (!stats) return null
return (
<div>
<h3>Pool Performance</h3>
{/* Tokens Sold */}
<p>Tokens Sold: {(stats.tokensSold.toNumber() / 1e6).toFixed(2)}</p>
<p>Remaining: {(stats.baseReserve.toNumber() / 1e6).toFixed(2)}</p>
{/* Amount Raised */}
<p>SOL Raised: {(stats.amountRaised.toNumber() / LAMPORTS_PER_SOL).toFixed(4)} SOL</p>
{/* Progress */}
<p>Progress: {stats.percentSold.toFixed(2)}%</p>
{/* Progress Bar */}
<div className="progress-bar">
<div style={{ width: `${stats.percentSold}%` }} />
</div>
</div>
)
}
// Option 2: Get individual metrics
function SimplePoolMetrics({ poolAddress }) {
const { data: tokensSold } = useTokensSold(poolAddress)
const { data: amountRaised } = useAmountRaised(poolAddress)
return (
<div>
{tokensSold && <p>Sold: {tokensSold.toString()}</p>}
{amountRaised && <p>Raised: {amountRaised.toString()} lamports</p>}
</div>
)
}
// Real-world example with formatting
function TokenSaleProgress({ poolAddress }) {
const { data: stats } = usePoolStats(poolAddress, {
refetchInterval: 10000, // Update every 10 seconds
})
if (!stats) return null
const tokenDecimals = 6 // Adjust based on your token
const tokensSoldFormatted = stats.tokensSold.toNumber() / Math.pow(10, tokenDecimals)
const solRaised = stats.amountRaised.toNumber() / LAMPORTS_PER_SOL
return (
<div className="sale-stats">
<div className="stat-card">
<h4>Tokens Sold</h4>
<p className="big-number">{tokensSoldFormatted.toLocaleString()}</p>
<p className="subtitle">{stats.percentSold.toFixed(1)}% of supply</p>
</div>
<div className="stat-card">
<h4>Amount Raised</h4>
<p className="big-number">{solRaised.toFixed(2)} SOL</p>
<p className="subtitle">${(solRaised * 200).toFixed(2)} USD</p>
</div>
<div className="stat-card">
<h4>Remaining</h4>
<p className="big-number">
{(stats.baseReserve.toNumber() / Math.pow(10, tokenDecimals)).toLocaleString()}
</p>
<p className="subtitle">{(100 - stats.percentSold).toFixed(1)}% left</p>
</div>
</div>
)
}
## TypeScript Support
Full TypeScript support with exported types:
```typescript
import type {
WalletAdapter,
ReownWalletProvider,
AnyWalletProvider,
SwapMutationParams,
WithdrawMutationParams,
SwapParams,
SwapQuoteParams,
SwapQuote2Params,
WithdrawParams,
PoolInfoResult,
FeeBreakdownResult,
DbcContextValue,
} from '@notdotmarket/dbc-hooks'Migration Guide
From 0.2.0 to 0.3.0
What's New:
- ✅ Reown AppKit integration at provider level
- ✅
DbcAppKitProviderfor simplified setup - ✅ Automatic wallet adapter detection (Reown vs. standard)
- ✅ Support for Reown's
sendTransactionmethod
No Breaking Changes! Version 0.3.0 is fully backward compatible with 0.2.0. You can continue using standard wallet adapters or upgrade to Reown AppKit.
To use Reown AppKit:
// Old way (still works)
import { DbcProvider } from '@notdotmarket/dbc-hooks'
import { useWallet } from '@solana/wallet-adapter-react'
// New way (recommended)
import { DbcAppKitProvider } from '@notdotmarket/dbc-hooks'
import { useAppKitAccount, useAppKitProvider } from '@reown/appkit/react'From 0.1.x to 0.2.0+
Breaking Change: Mutation hooks now require a wallet adapter instead of Keypair.
Before:
import { Keypair } from '@solana/web3.js'
const wallet = Keypair.fromSecretKey(...)After:
// With Reown AppKit
import { useAppKitProvider } from '@reown/appkit/react'
const { walletProvider } = useAppKitProvider('solana')
// Or with standard adapter
import { useWallet } from '@solana/wallet-adapter-react'
const wallet = useWallet()Sale Tax Hook
The useSaleTax hook checks if a pool has sale tax enabled and calculates the tax amount for selling transactions.
When enabled, a 10% tax is applied when selling base tokens (swapBaseForQuote = true).
import { useSaleTax } from '@notdotmarket/dbc-hooks'
import { PublicKey } from '@solana/web3.js'
import BN from 'bn.js'
function SwapWithSaleTax() {
const poolAddress = new PublicKey('YOUR_POOL_ADDRESS')
const amountIn = new BN(1000000) // 1 TOKEN (6 decimals)
// Check sale tax info
const { data: saleTaxInfo, isLoading } = useSaleTax({
poolAddress,
amountIn,
swapBaseForQuote: true, // true when selling, false when buying
})
if (isLoading) return <div>Loading...</div>
return (
<div>
<h3>Sale Tax Information</h3>
<p>Sale Tax Enabled: {saleTaxInfo?.isSaleTaxEnabled ? 'Yes' : 'No'}</p>
{saleTaxInfo?.isSaleTaxEnabled && (
<>
<p>Tax Rate: {saleTaxInfo.saleTaxPercentage}%</p>
{saleTaxInfo.saleTaxFee && (
<p>Tax Amount: {saleTaxInfo.saleTaxFee.toString()} lamports</p>
)}
<p className="warning">
⚠️ Selling will incur a {saleTaxInfo.saleTaxPercentage}% tax
</p>
</>
)}
</div>
)
}Integration with Swap Quote:
import { useSwapQuote2, useSaleTax } from '@notdotmarket/dbc-hooks'
function SwapQuoteWithSaleTax() {
const poolAddress = new PublicKey('YOUR_POOL_ADDRESS')
const amountIn = new BN(1000000)
const isSelling = true // swapBaseForQuote
// Get swap quote (includes saleTaxFee in the result)
const { data: quote } = useSwapQuote2({
poolAddress,
swapMode: SwapMode.ExactIn,
amountIn,
swapBaseForQuote: isSelling,
slippageBps: 100,
hasReferral: false,
})
// Get sale tax info for display
const { data: saleTaxInfo } = useSaleTax({
poolAddress,
amountIn,
swapBaseForQuote: isSelling,
})
return (
<div>
<h3>Swap Details</h3>
<p>Output Amount: {quote?.outputAmount.toString()}</p>
<p>Trading Fee: {quote?.tradingFee.toString()}</p>
<p>Protocol Fee: {quote?.protocolFee.toString()}</p>
{quote?.saleTaxFee && !quote.saleTaxFee.isZero() && (
<p className="warning">
Sale Tax Fee: {quote.saleTaxFee.toString()}
{saleTaxInfo?.isSaleTaxEnabled &&
` (${saleTaxInfo.saleTaxPercentage}% tax on sells)`
}
</p>
)}
</div>
)
}Real-Time Trade Monitoring & Chart Integration
The useTradeEventListener hook enables real-time monitoring of trades on your bonding curve pools, automatically storing price data in Redis for chart integration.
Quick Example
import { useTradeEventListener } from '@notdotmarket/dbc-hooks'
import { PublicKey } from '@solana/web3.js'
function PriceChart({ poolAddress }) {
const [trades, setTrades] = useState([])
// Listen for real-time trades
const { isListening } = useTradeEventListener({
poolAddress: new PublicKey(poolAddress),
redisConfig: {
url: process.env.NEXT_PUBLIC_REDIS_URL!,
keyPrefix: 'dbc:trades',
ttl: 2592000, // 30 days
},
enabled: true,
onEvent: (event) => {
// Add to chart data
setTrades(prev => [event, ...prev].slice(0, 100))
// Show notification
console.log('New trade:', {
direction: event.tradeDirection === 1 ? 'Buy' : 'Sell',
price: calculatePrice(event.nextSqrtPrice),
timestamp: new Date(event.timestamp)
})
},
onError: (error) => {
console.error('Event listener error:', error)
}
})
return (
<div>
<div>Status: {isListening ? '🟢 Live' : '🔴 Offline'}</div>
{/* Render your chart with trades data */}
</div>
)
}
function calculatePrice(sqrtPrice: string): number {
const sqrt = BigInt(sqrtPrice)
const price = (sqrt * sqrt) / (BigInt(2) ** BigInt(64))
return Number(price) / 1e9
}Features
- ✅ Real-time event listening for swap transactions
- ✅ Automatic price quote extraction after each trade
- ✅ Redis storage with configurable TTL
- ✅ Timestamp management for time-series data
- ✅ Historical data fetching with
useTradeHistory - ✅ Perfect for building live trading charts
Setup Required
This hook requires backend API endpoints to interact with Redis. See the complete setup guide:
📖 Trade Event Listener Documentation
📖 Redis Backend Implementation Guide
Why Reown AppKit?
- Universal Wallet Support - One integration for all Solana wallets
- Social Logins - Google, Twitter, Discord, etc.
- Email Authentication - Passwordless email login
- Better UX - Beautiful, customizable modal
- Multi-Chain Ready - Easy to add EVM, Bitcoin support later
- Built-in Wallet Detection - Automatic wallet discovery
- Mobile Optimized - WalletConnect integration
License
MIT
