When working with tokens that use bonding curves (like pump.fun on Solana or clanker on Base), you often need to find the bonding curve contract address to interact with the pool before it migrates to a traditional AMM. This cookbook shows you two methods to retrieve bonding curve addresses using Mobula’s API.
Two Methods to Find Bonding Curves
Method 1: Using token/details (Recommended)
The simplest way - directly get the bondingCurveAddress field:
curl -X GET "https://api.mobula.io/api/2/token/details?address=TOKEN_ADDRESS" \
-H "Authorization: YOUR_API_KEY"
Method 2: Using token/markets
List ALL pools/markets for a token, then find the bonding curve by matching the pool type with the token’s source:
curl -X GET "https://api.mobula.io/api/2/token/markets?address=TOKEN_ADDRESS" \
-H "Authorization: YOUR_API_KEY"
Understanding Bonding Curves
A bonding curve is a pricing mechanism where token price increases as more tokens are purchased. Many protocols use bonding curves to bootstrap liquidity for new tokens before eventually migrating to traditional AMM pools once a threshold is reached.
Key Concepts
source: The protocol that launched the token (e.g., “pumpfun”, “clanker”, “moonshot”)
type: The pool type identifier (e.g., “pumpfun”, “clanker”, “uniswap-v2”)
Bonding Curve Pool: When a token’s source matches a pool’s type, that pool is the bonding curve. For example:
- Token source: “pumpfun” → Pool type: “pumpfun” = Bonding curve
- Token source: “clanker” → Pool type: “clanker” = Bonding curve
Key Response Fields
| Field | Type | Description |
|---|
source | string | Protocol that launched the token |
type | string | Pool type identifier |
bondingCurveAddress | string | null | Contract address of the bonding curve pool |
bonded | boolean | Whether token completed bonding and migrated |
bondingPercentage | number | Progress towards bonding completion (0-100%) |
Method 1: Using token/details (Simplest)
TypeScript
import { MobulaClient } from '@mobula/sdk';
const client = new MobulaClient({
apiKey: process.env.MOBULA_API_KEY
});
async function getBondingCurveFromDetails(
tokenAddress: string,
blockchain?: string
) {
const response = await client.fetchTokenDetails({
address: tokenAddress,
blockchain: blockchain
});
const token = response.data;
return {
bondingCurveAddress: token.bondingCurveAddress,
bonded: token.bonded,
bondingPercentage: token.bondingPercentage,
source: token.source,
poolAddress: token.poolAddress
};
}
// Example: pump.fun token on Solana
const result = await getBondingCurveFromDetails(
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump',
'solana'
);
console.log(result);
// {
// bondingCurveAddress: "7xKp...abc123",
// bonded: false,
// bondingPercentage: 67.5,
// source: "pumpfun",
// poolAddress: "7xKp...abc123"
// }
Python
import requests
API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.mobula.io/api/2'
def get_bonding_curve_from_details(token_address: str, blockchain: str = None) -> dict:
params = {'address': token_address}
if blockchain:
params['blockchain'] = blockchain
response = requests.get(
f'{BASE_URL}/token/details',
params=params,
headers={'Authorization': API_KEY}
)
response.raise_for_status()
token = response.json().get('data', {})
return {
'bonding_curve_address': token.get('bondingCurveAddress'),
'bonded': token.get('bonded'),
'bonding_percentage': token.get('bondingPercentage'),
'source': token.get('source'),
'pool_address': token.get('poolAddress')
}
# Example
result = get_bonding_curve_from_details(
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump',
'solana'
)
print(result)
Method 2: Using token/markets (Advanced)
This method lists ALL pools and finds the bonding curve by matching pool type with token source.
TypeScript
async function getBondingCurveFromMarkets(
tokenAddress: string,
blockchain?: string
) {
const response = await client.fetchTokenMarkets({
address: tokenAddress,
blockchain: blockchain,
limit: 25
});
const markets = response.data;
if (markets.length === 0) {
return { error: 'No markets found' };
}
// Get token source from any market (all markets have same base token)
const tokenSource = markets[0].base.source;
// Find bonding curve: pool type matches token source
const bondingCurve = markets.find(m => m.type === tokenSource);
if (!bondingCurve) {
return {
status: 'no-bonding-curve',
message: `No bonding curve found (source: ${tokenSource})`
};
}
return {
bondingCurveAddress: bondingCurve.address,
bondingPercentage: bondingCurve.bondingPercentage,
bonded: bondingCurve.bonded,
source: tokenSource,
poolType: bondingCurve.type,
liquidityUSD: bondingCurve.liquidityUSD,
exchange: bondingCurve.exchange.name
};
}
// Example: pump.fun token
const result = await getBondingCurveFromMarkets(
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump',
'solana'
);
console.log(result);
// {
// bondingCurveAddress: "7xKp...abc123",
// bondingPercentage: 67.5,
// bonded: false,
// source: "pumpfun",
// poolType: "pumpfun",
// liquidityUSD: 45000.50,
// exchange: "Pump.fun"
// }
Python
def get_bonding_curve_from_markets(token_address: str, blockchain: str = None) -> dict:
params = {'address': token_address, 'limit': 25}
if blockchain:
params['blockchain'] = blockchain
response = requests.get(
f'{BASE_URL}/token/markets',
params=params,
headers={'Authorization': API_KEY}
)
response.raise_for_status()
markets = response.json().get('data', [])
if not markets:
return {'error': 'No markets found'}
# Get token source from first market
token_source = markets[0]['base'].get('source')
# Find bonding curve: pool type matches token source
bonding_curve = next((m for m in markets if m.get('type') == token_source), None)
if not bonding_curve:
return {
'status': 'no-bonding-curve',
'message': f'No bonding curve found (source: {token_source})'
}
return {
'bonding_curve_address': bonding_curve['address'],
'bonding_percentage': bonding_curve.get('bondingPercentage'),
'bonded': bonding_curve.get('bonded'),
'source': token_source,
'pool_type': bonding_curve.get('type'),
'liquidity_usd': bonding_curve.get('liquidityUSD'),
'exchange': bonding_curve['exchange']['name']
}
# Example
result = get_bonding_curve_from_markets(
'HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump',
'solana'
)
print(result)
How It Works
Understanding the Matching Logic
When you query token/markets, you get ALL pools for a token:
{
"data": [
{
"address": "7xKp...abc123",
"type": "pumpfun", // Pool type
"bonded": false,
"bondingPercentage": 67.5,
"base": {
"source": "pumpfun", // Token source
"address": "HLwEJQ...",
"symbol": "MYTOKEN"
}
},
{
"address": "8yBp...def456",
"type": "raydium-v4", // Different pool type
"bonded": true,
"base": {
"source": "pumpfun", // Same token source
"address": "HLwEJQ...",
"symbol": "MYTOKEN"
}
}
]
}
The bonding curve pool is where type matches source:
- Pool 1:
type: "pumpfun" = source: "pumpfun" ✅ This is the bonding curve!
- Pool 2:
type: "raydium-v4" ≠ source: "pumpfun" ❌ This is a migrated pool
Response Structure (token/details)
{
"data": {
"address": "HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump",
"symbol": "MYTOKEN",
"source": "pumpfun",
"bondingCurveAddress": "7xKp...abc123",
"bonded": false,
"bondingPercentage": 67.5,
"poolAddress": "7xKp...abc123",
"priceUSD": 0.000123
}
}
Response Structure (token/markets)
{
"data": [
{
"address": "7xKp...abc123",
"type": "pumpfun",
"blockchain": "Solana",
"bonded": false,
"bondingPercentage": 67.5,
"exchange": {
"name": "Pump.fun"
},
"liquidityUSD": 45000.50,
"volume24hUSD": 125000.00,
"base": {
"address": "HLwEJQVCQMVdRhFg1YKKgNAnCwUk4eboMTtdBtpump",
"symbol": "MYTOKEN",
"source": "pumpfun"
}
}
]
}
Protocol-Specific Examples
Pump.fun (Solana)
async function getPumpfunBondingCurve(mintAddress: string) {
const response = await client.fetchTokenMarkets({
address: mintAddress,
blockchain: 'solana'
});
// Find pool where type matches source "pumpfun"
const pumpfunMarket = response.data.find(m => m.type === 'pumpfun');
return pumpfunMarket ? {
bondingCurveAddress: pumpfunMarket.address,
progress: pumpfunMarket.bondingPercentage,
bonded: pumpfunMarket.bonded,
liquiditySOL: pumpfunMarket.liquidityUSD / 150
} : null;
}
Clanker (Base)
async function getClankerBondingCurve(tokenAddress: string) {
const response = await client.fetchTokenMarkets({
address: tokenAddress,
blockchain: 'base'
});
// Find pool where type matches source "clanker"
const clankerMarket = response.data.find(m => m.type === 'clanker');
return clankerMarket ? {
bondingCurveAddress: clankerMarket.address,
progress: clankerMarket.bondingPercentage,
bonded: clankerMarket.bonded
} : null;
}
Moonshot (Solana)
async function getMoonshotBondingCurve(mintAddress: string) {
const response = await client.fetchTokenMarkets({
address: mintAddress,
blockchain: 'solana'
});
// Find pool where type matches source "moonshot"
const moonshotMarket = response.data.find(m => m.type === 'moonshot');
return moonshotMarket ? {
bondingCurveAddress: moonshotMarket.address,
progress: moonshotMarket.bondingPercentage,
bonded: moonshotMarket.bonded
} : null;
}
Generic Function for Any Protocol
async function getBondingCurveBySource(
tokenAddress: string,
blockchain?: string
) {
const response = await client.fetchTokenMarkets({
address: tokenAddress,
blockchain: blockchain
});
const markets = response.data;
if (markets.length === 0) return null;
// Get token source
const source = markets[0].base.source;
// Find pool matching the source
const bondingCurve = markets.find(m => m.type === source);
return bondingCurve ? {
bondingCurveAddress: bondingCurve.address,
source: source,
poolType: bondingCurve.type,
bonded: bondingCurve.bonded,
bondingPercentage: bondingCurve.bondingPercentage,
exchange: bondingCurve.exchange.name
} : null;
}
Advanced: Monitor Bonding Progress
async function monitorBondingProgress(tokenAddress: string, blockchain: string) {
setInterval(async () => {
const response = await client.fetchTokenDetails({
address: tokenAddress,
blockchain: blockchain
});
const token = response.data;
if (token.bonded) {
console.log('Token has completed bonding!');
console.log(`Migrated from ${token.source} to new pool`);
return;
}
console.log(`Source: ${token.source}`);
console.log(`Progress: ${token.bondingPercentage?.toFixed(2)}%`);
console.log(`Bonding curve: ${token.bondingCurveAddress}`);
if (token.bondingPercentage && token.bondingPercentage > 95) {
console.log('Warning: Bonding almost complete!');
}
}, 10000);
}
Source to Pool Type Mapping
Common bonding curve protocols and their identifiers:
| Protocol | Source Value | Pool Type Value | Chains |
|---|
| Pump.fun | pumpfun | pumpfun | Solana |
| Moonshot | moonshot | moonshot | Solana |
| Clanker | clanker | clanker | Base |
| Flap | flap | flap | Base, BNB |
| Nadfun | nadfun | nadfun | Base |
| Mana | mana | mana | Base |
| Raydium Launchlab | raydium-launchlab | raydium-launchlab | Solana |
| Boop | boop | boop | Solana |
Best Practices
Use token/details for simplicity: If you only need the bonding curve address, use token/details which directly returns bondingCurveAddress.
Match source with type: When using token/markets, find the pool where type matches the token’s source - that’s your bonding curve.
Bonding curve addresses become inactive: Once bonded: true, the bonding curve pool is no longer active. Token has migrated to a new pool.
Multiple pools are normal: token/markets returns ALL pools for a token (bonding curve + migrated pools). The bonding curve is just one of them.
Troubleshooting
Issue: No pool matches token source
Problem: No pool where type equals token source
Solutions:
- Token may have completed bonding (check
bonded: true)
- Token may not have originated from a bonding curve
- Use
token/details to check bondingCurveAddress directly
- Verify token address is correct
Example:
// Token source: "pumpfun" but no pool with type: "pumpfun"
// This means token has completed bonding
const markets = response.data;
const source = markets[0].base.source; // "pumpfun"
const bondingCurve = markets.find(m => m.type === source); // null
// Check markets[0].bonded === true
Issue: bondingCurveAddress is null
Problem: token/details returns bondingCurveAddress: null
Solutions:
- Token has completed bonding - check
bonded: true
- Token didn’t launch via bonding curve
- Check
poolAddress for current active pool
Issue: Multiple pools with same type
Problem: Multiple pools found with matching type
Solution: This is unusual but possible. Choose based on:
- Pool with
bonded: false (active bonding curve)
- Highest
liquidityUSD
- Most recent
createdAt date
Comparison: token/details vs token/markets
| Feature | token/details | token/markets |
|---|
| Simplicity | ✅ Direct bondingCurveAddress field | Requires finding pool where type matches source |
| Data Returned | Single token info | All pools/markets for token |
| Use Case | Quick bonding curve lookup | Need all pool details, volumes, liquidity |
| Performance | Faster (single token) | Slower (lists all pools) |
| Best For | Simple bonding curve address lookup | Market analysis, comparing pools |
Get Started
Create a free Mobula API key and start finding bonding curve addresses today!
Need Help?