React hooks for Dynamic Bonding Curve SDK with React Query integration and Reown AppKit support
npm install @notdotmarket/dbc-hooksReact hooks for the Dynamic Bonding Curve SDK, built with React Query and fully integrated with Reown AppKit for seamless wallet management.
- ✅ 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
``bashInstall the hooks package
npm install @notdotmarket/dbc-hooks @tanstack/react-query
Quick Start with Reown AppKit
$3
`tsx
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 (
)
}
`$3
`tsx
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 (
{isConnected && (
)}
)
}
`Complete Trading Example
`tsx
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
Loading pool data...
return (
Pool Trading
{/ Wallet Connection /}
{/ Pool Info /}
{poolInfo && (
Base Reserve: {poolInfo.pool.baseReserve.toString()}
Quote Reserve: {poolInfo.pool.quoteReserve.toString()}
)}
{/ Swap Quote /}
{quote && (
You will receive: {quote.outputAmount.toString()}
Trading fee: {quote.tradingFee.toString()}
)}
{/ Trading Actions /}
{isConnected && (
<>
>
)}
{/ Fee Breakdown /}
{fees && (
Unclaimed Fees
Creator Quote: {fees.creator.unclaimedQuoteFee.toString()}
Partner Quote: {fees.partner.unclaimedQuoteFee.toString()}
)}
)
}
`Alternative: Standard Wallet Adapter
If you prefer using standard Solana wallet adapters instead of Reown AppKit:
`tsx
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 (
)
}
// 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
$3
#### Pool Information
-
usePoolInfo(poolAddress) - Fetch pool and config data
- usePoolConfig(configAddress) - Fetch pool configuration
- usePools() - Fetch all pools
- usePoolsByConfig(configAddress) - Pools by config
- usePoolsByCreator(creatorAddress) - Pools by creator
- usePoolByBaseMint(mintAddress) - Pool by base token#### Pool State & Metrics
-
usePoolCurveProgress(poolAddress) - Bonding curve progress (0-1)
- usePoolMetadata(poolAddress) - Pool metadata
- usePoolExpiryDays(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 sold
- useAmountRaised(poolAddress) - Amount of quote tokens (SOL) raised
- usePoolMigrationQuoteThreshold(poolAddress) - Migration threshold#### Pool Configurations
-
usePoolConfigs() - All pool configurations
- usePoolConfigsByOwner(ownerAddress) - Configs by owner#### Fee Information
-
useFeeBreakdown(poolAddress) - Detailed fee breakdown
- usePoolFeeMetrics(poolAddress) - Current fee metrics
- usePoolsFeesByConfig(configAddress) - Fees for config pools
- usePoolsFeesByCreator(creatorAddress) - Fees for creator pools
- useSaleTax(params) - Check if sale tax is enabled and calculate tax amount#### Partner & Migration
-
usePartnerMetadata(partnerAddress) - Partner metadata
- useDammV1MigrationMetadata(poolAddress) - DAMM V1 migration data
- useDammV1LockEscrow(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 charts
- useTradeHistory(params) - Fetch historical trade events from RedisNote: 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.$3
- useSwap() - Execute swap transactions
- useWithdraw() - Withdraw fees and surplusSwap Modes
`typescript
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:
`tsx
// 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
`typescript
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 fees
`Example usage:
`tsx
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:`tsx
import { usePoolExpiryDays } from '@notdotmarket/dbc-hooks'function PoolExpiryDisplay({ poolAddress }) {
const { data: daysLeft, isLoading } = usePoolExpiryDays(poolAddress)
if (isLoading) return
Loading...
// null = no expiry set
if (daysLeft === null) {
return ⏰ No expiration
}
// Expired
if (daysLeft <= 0) {
return 🔒 Curve Expired
}
// Active with expiry
const isExpiringSoon = daysLeft < 7
return (
⏱️ Expires in {daysLeft.toFixed(1)} days
{isExpiringSoon && ' ⚠️'}
)
}
`Token Details & Metadata
Fetch comprehensive token information including on-chain metadata, logo, symbol, decimals, and supply:
`tsx
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
Loading token info...
if (!token) return Token not found
return (
{/ Token Logo /}
{token.metadata?.logo && (
src={token.metadata.logo}
alt={token.metadata.name}
className="token-logo"
/>
)}
{/ Token Identity /}
{token.metadata?.name || 'Unknown Token'}
{token.metadata?.symbol || 'N/A'}
{token.metadata?.description && (
{token.metadata.description}
)}
{/ Token Stats /}
{token.mint.toString()}
{token.decimals}
{(Number(token.supply) / Math.pow(10, token.decimals)).toLocaleString()}
{token.isToken2022 ? 'Token-2022' : 'SPL Token'}
{token.mintAuthority ? token.mintAuthority.toString() : 'Revoked ✓'}
{token.freezeAuthority ? token.freezeAuthority.toString() : 'None'}
{/ Metadata URI /}
{token.metadata?.uri && (
)}
)
}// Example: Fetch metadata but skip JSON fetch for faster loading
function QuickTokenInfo({ tokenMint }) {
const { data: token } = useTokenDetails(tokenMint, false)
return (
{token?.metadata?.symbol || 'Loading...'}
{token?.decimals} decimals
)
}// 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 (
{baseToken?.metadata?.logo && (

)}
{baseToken?.metadata?.symbol}
/
{quoteToken?.metadata?.logo && (

)}
{quoteToken?.metadata?.symbol}
)
}
`Return Type:
`typescript
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:
`tsx
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
Loading stats...
if (!stats) return null
return (
Pool Performance
{/ Tokens Sold /}
Tokens Sold: {(stats.tokensSold.toNumber() / 1e6).toFixed(2)}
Remaining: {(stats.baseReserve.toNumber() / 1e6).toFixed(2)}
{/ Amount Raised /}
SOL Raised: {(stats.amountRaised.toNumber() / LAMPORTS_PER_SOL).toFixed(4)} SOL
{/ Progress /}
Progress: {stats.percentSold.toFixed(2)}%
{/ Progress Bar /}
${stats.percentSold}% }} />
)
}// Option 2: Get individual metrics
function SimplePoolMetrics({ poolAddress }) {
const { data: tokensSold } = useTokensSold(poolAddress)
const { data: amountRaised } = useAmountRaised(poolAddress)
return (
{tokensSold && Sold: {tokensSold.toString()}
}
{amountRaised && Raised: {amountRaised.toString()} lamports
}
)
}// 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 (
Tokens Sold
{tokensSoldFormatted.toLocaleString()}
{stats.percentSold.toFixed(1)}% of supply
Amount Raised
{solRaised.toFixed(2)} SOL
${(solRaised * 200).toFixed(2)} USD
Remaining
{(stats.baseReserve.toNumber() / Math.pow(10, tokenDecimals)).toLocaleString()}
{(100 - stats.percentSold).toFixed(1)}% left
)
}
`
`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
$3
What's New:
- ✅ Reown AppKit integration at provider level
- ✅
DbcAppKitProvider for simplified setup
- ✅ Automatic wallet adapter detection (Reown vs. standard)
- ✅ Support for Reown's sendTransaction methodNo 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:
`tsx
// 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'
`$3
Breaking Change: Mutation hooks now require a wallet adapter instead of Keypair.
Before:
`tsx
import { Keypair } from '@solana/web3.js'
const wallet = Keypair.fromSecretKey(...)
`After:
`tsx
// 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).
`tsx
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
Loading...
return (
Sale Tax Information
Sale Tax Enabled: {saleTaxInfo?.isSaleTaxEnabled ? 'Yes' : 'No'}
{saleTaxInfo?.isSaleTaxEnabled && (
<>
Tax Rate: {saleTaxInfo.saleTaxPercentage}%
{saleTaxInfo.saleTaxFee && (
Tax Amount: {saleTaxInfo.saleTaxFee.toString()} lamports
)}
⚠️ Selling will incur a {saleTaxInfo.saleTaxPercentage}% tax
>
)}
)
}
`Integration with Swap Quote:
`tsx
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 (
Swap Details
Output Amount: {quote?.outputAmount.toString()}
Trading Fee: {quote?.tradingFee.toString()}
Protocol Fee: {quote?.protocolFee.toString()}
{quote?.saleTaxFee && !quote.saleTaxFee.isZero() && (
Sale Tax Fee: {quote.saleTaxFee.toString()}
{saleTaxInfo?.isSaleTaxEnabled &&
(${saleTaxInfo.saleTaxPercentage}% tax on sells)
}
)}
)
}
`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.$3
`tsx
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 (
Status: {isListening ? '🟢 Live' : '🔴 Offline'}
{/ Render your chart with trades data /}
)
}function calculatePrice(sqrtPrice: string): number {
const sqrt = BigInt(sqrtPrice)
const price = (sqrt sqrt) / (BigInt(2) * BigInt(64))
return Number(price) / 1e9
}
`$3
- ✅ 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$3
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
Links
- NPM Package
- GitHub Repository
- Reown AppKit Docs
- Dynamic Bonding Curve SDK