pump.fun → PumpSwap migrations in real time
When a pump.fun bonding curve fills, two things happen on chain: the curve completes, then its
liquidity migrates into a new PumpSwap pool. Our feed turns those into two decoded messages,
curve_complete and migration, so you don't have to parse the program's events yourself.
Market data only. A migration is an on-chain fact, not a signal to buy or sell.
Subscribe
import asyncio, json, os, websockets # pip install websockets
URL = "wss://feed.lunarshadowlabs.com/ws?kinds=curve_complete,migration&venues=pump,launchlab,meteora_dbc"
HEADERS = {"Authorization": f"Bearer {os.environ['LSL_KEY']}"}
async def main():
async with websockets.connect(URL, additional_headers=HEADERS, max_size=None) as ws:
async for raw in ws:
m = json.loads(raw)
if m["kind"] == "curve_complete":
print("curve complete", m["venue"], m["mint"])
elif m["kind"] == "migration":
print("migrated", m["mint"], m["venue"], "->", m["to_venue"], m["to_pool"])
asyncio.run(main())
For production use, add the resume and reconnect loop from the docs.
The curve completes
{
"v": 1,
"seq": 39388,
"kind": "curve_complete",
"venue": "pump",
"keys": [
"32NtSoRKFXupR75EM3mPJZ2CLgdRwem37ChcnogRpump",
"So11111111111111111111111111111111111111112",
"AYuNPrKAvAPr7hxhddYkxFp1cwh2n7wkbL56p25nFw5C",
"BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s"
],
"stage": "executed",
"source": "geyser",
"commitment": "processed",
"slot": 454291875,
"sig": "E7SRPj62nRg7xnB5FmhnseaweMJsHo9j2HNqojJ9HXKY7jVxnhRob43hLaEk2FoeKoa4VYSipniKkUgesx5KJhj",
"ix": 2,
"inner": 5,
"t_ingest_us": 1791394632043530,
"t_emit_us": 1791394632043578,
"via": "MAyhSmzXzV1pTf7LsNkrNwkWKTo4ougAJ1PPg47MD4e",
"mint": "32NtSoRKFXupR75EM3mPJZ2CLgdRwem37ChcnogRpump",
"curve": "AYuNPrKAvAPr7hxhddYkxFp1cwh2n7wkbL56p25nFw5C",
"user": "BwWK17cbHxwWBKZkUYvzxLcNQ1YVyaFezduWbtm2de6s",
"quote_mint": "So11111111111111111111111111111111111111112"
}
Captured from our live feed on 2026-10-07.
curve is the bonding curve account and user the wallet whose trade completed it.
The migration
{
"v": 1,
"seq": 39860,
"kind": "migration",
"venue": "pump",
"keys": [
"32NtSoRKFXupR75EM3mPJZ2CLgdRwem37ChcnogRpump",
"So11111111111111111111111111111111111111112",
"7xWVbWAa6rZ18eDdqJPJa4RMLYUq55bH5kURKZHpGd6w",
null
],
"stage": "executed",
"source": "geyser",
"commitment": "processed",
"slot": 454291879,
"sig": "BUfoYNxSd272g2R1uwguuhswcapPsqUfRDFeMUYSNMnjNGsEBxqRcVrsocGdnS1cUhxwA9g2d5S2AmTtf649Cud",
"ix": 2,
"inner": 40,
"t_ingest_us": 1791394632951407,
"t_emit_us": 1791394632951434,
"via": null,
"mint": "32NtSoRKFXupR75EM3mPJZ2CLgdRwem37ChcnogRpump",
"from_curve": "AYuNPrKAvAPr7hxhddYkxFp1cwh2n7wkbL56p25nFw5C",
"to_venue": "pumpswap",
"to_pool": "7xWVbWAa6rZ18eDdqJPJa4RMLYUq55bH5kURKZHpGd6w",
"base_amount": "206900000000000",
"quote_amount": "1104806152",
"quote_mint": "So11111111111111111111111111111111111111112",
"fee": "15000001"
}
Captured from our live feed on 2026-10-07.
venueis where the token came from (pump);to_venueis where it went. pump.fun migrations always go topumpswap.to_poolis the new PumpSwap pool. Add it to a watchlist (?watch=<pool>) to receive its trades.base_amount/quote_amountare what the new pool received, as strings of raw integer units: scale them by each mint's decimals.feeis the migration fee.keysis[mint, quote, new pool, null]: a migration has no actor wallet.
Raydium migrations come from LaunchLab
Tokens graduating from Raydium LaunchLab (the launchpad behind bonk.fun, StonkFun and others) migrate to
raydium_cpmm or raydium_v4. There is no separate curve-complete message for LaunchLab, so
the migration is the message to watch:
{
"v": 1,
"seq": 143993,
"kind": "migration",
"venue": "launchlab",
"keys": [
"3XFyVaZMFcA5qht3STXyKPJ4fUAqHEDCM52okDveWqih",
"Xs3oZwbHvqis4NYcf4YKWmEia2eC84wSiVrcYcTqpH8",
"6hGrxWm6xXjDbf5WPT3QgTkvMxZi4o2jsUUtpTexTpWo",
null
],
"stage": "executed",
"source": "geyser",
"commitment": "processed",
"slot": 454292601,
"sig": "5DmGV8LaXoA4SARR4a3MiaEnDuji9dYSB96Do7Z7HS1oTH4UJP2z4jM4fm81hVjw5rckhU868HGqExpgiEWERsRV",
"ix": 2,
"inner": null,
"t_ingest_us": 1791394829450596,
"t_emit_us": 1791394829450688,
"via": null,
"mint": "3XFyVaZMFcA5qht3STXyKPJ4fUAqHEDCM52okDveWqih",
"from_curve": "GTBhLTEQpioBDt5uh3w5uH9uhHfY3drxYuHKVkVJPUgB",
"to_venue": "raydium_cpmm",
"to_pool": "6hGrxWm6xXjDbf5WPT3QgTkvMxZi4o2jsUUtpTexTpWo",
"base_amount": "204831000000000",
"quote_amount": "5922030322",
"quote_mint": "Xs3oZwbHvqis4NYcf4YKWmEia2eC84wSiVrcYcTqpH8",
"fee": null
}
Captured from our live feed on 2026-10-07.
The quote mint isn't always SOL: LaunchLab platforms can configure other quote tokens, so read
quote_mint rather than assuming.
Meteora Dynamic Bonding Curve
Meteora DBC launchpads (meteora_dbc) produce both curve_complete and
migration; their migrations go to meteora_damm_v1 or meteora_damm_v2.
Things to know
- Events are published at
processedcommitment, before confirmation. A rare fork can drop a transaction. - If our upstream stream reconnects you receive a
gapmessage; that is the only signal that events may have been missed. See gaps and resume.
Try the feed
One WebSocket, 12 Solana venues, one flat price.
Start free trial Read the docs
3-day free trial, then $49/month per license plus applicable tax, charged automatically every month until you cancel. Cancel online any time before the trial ends and you pay nothing. Starting a trial means you agree to the Terms. Market data only, no signals or advice.