Integrate bagggr
Everything a trading terminal or an aggregator needs to list, quote, buy and sell tokens on the bagggr bonding curve, straight from the chain. One Anchor program on Solana mainnet; no API key, no SDK required.
Addresses
Mainnet only. The program is upgradeable by the bagggr admin; the IDL above is the deployed version (constant-product curve, fee-on-transfer pair assets, buy-back-and-burn slice), September 2026.
| Program | 9GMVRdY66xm3SZQEvedDso14Ekwg2iEkWEJo1z1YqZfG | |
| Config PDA | CcYZwk2bMuHzbQoBjSkBV1AVa5h3AzH3tdKtK6AXHW3o | PDA(["config"]) |
| Treasury | 7fz8aGRq14yGeyefyLLNXsZCKGsfdUJhAzVsR6pQoE6H | receives the 1% curve fee, in the pair asset |
| Token program | TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb | every launched token is Token-2022, 6 decimals, with a fixed 1.5% transfer fee |
| Raydium CPMM | CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C | where a graduated token trades |
| Raydium fee tier | D4FPEruKEHrG5TenZ2mpDGEfu1iUvTiqBxvpU8HLBvC2 | amm_config the pools are created with (0.25%) |
| Metaplex metadata | metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s | name, symbol and URI at PDA(["metadata", program, mint]) |
Live config (readable from the config PDA, layout below):
| curve_fee_bps | 100 | 1% of the quote leg of every curve trade, to the treasury |
| tax_bps | 150 | the Token-2022 transfer fee on every launched token, on every transfer, anywhere |
| supply_total | 1,000,000,000 tokens | 1e15 base units; the mint authority is revoked at launch |
| supply_for_sale | 800,000,000 tokens | sold on the curve; the other 200,000,000 seed the pool |
| price_multiple | 0 | 0 = constant-product curve for new launches (older markets are straight lines, see Pricing) |
Finding markets
One Market account per token, at PDA(["market", mint]). List them all with getProgramAccounts on the program, filtered on the 8-byte account discriminator at offset 0; the account is 384 bytes.
Market discriminator [219, 190, 213, 55, 0, 227, 198, 154] dataSize 384 Config discriminator [155, 12, 170, 224, 30, 250, 204, 130] PDAs (program 9GMVRdY66xm3SZQEvedDso14Ekwg2iEkWEJo1z1YqZfG) market ["market", mint] market_signer ["signer", mint] authority of the vaults; system-owned, no data config ["config"]
New launches also emit a MarketCreated event (see Events), so a log subscription on the program catches a token the second it exists. Name, symbol and the metadata URI (a JSON with the image) are standard Metaplex metadata on the mint.
Market layout (little-endian, offsets from the start of the account data, 8-byte discriminator included):
| Offset | Field | Type | Meaning |
|---|---|---|---|
| 8 | creator | pubkey | the launching wallet |
| 40 | mint | pubkey | the token (Token-2022) |
| 72 | quote_mint | pubkey | the pair asset buyers pay with: wrapped SOL, a stablecoin, anything SPL |
| 104 | token_vault | pubkey | the curve's token account (ATA of market_signer) |
| 136 | quote_vault | pubkey | the curve's pair-asset account (ATA of market_signer) |
| 168 | reward_vault | pubkey | where harvested transfer fees wait for a push (not part of trading) |
| 200 | p0 | u128 | curve parameter, see Pricing (bit 127 set = constant product) |
| 216 | p1 | u128 | curve parameter |
| 232 | supply_for_sale | u64 | token base units the curve sells in total (S) |
| 240 | supply_total | u64 | token base units minted (T) |
| 248 | tokens_sold | u64 | base units sold so far (s); rises on buys, falls on sells |
| 256 | reserve | u64 | quote base units the curve holds, net of fees; equals the quote vault balance |
| 264 | graduation_reserve | u64 | quote base units at which the curve is full (G) |
| 272 | fees_collected | u64 | curve fees paid to the treasury so far |
| 280 | phase | u8 | 0 Curve (tradable here), 1 Complete (sold out, waiting for graduate), 2 Graduated (trade the pool) |
| 281 | rewards | 36 bytes | mode u8 (0 creator, 1 holders, 2 burn), scope u8, interval_minutes u16, fee_wallet pubkey |
| 317 | pool | pubkey | the Raydium CPMM pool once graduated, else the zero pubkey |
| 349 | created_at | i64 | unix seconds |
| 357 | graduated_at | i64 | unix seconds, 0 until graduation |
| 365 | last_push_at | i64 | last reward push |
| 373 | pushed_total | u64 | pair-asset base units paid to the creator or holders so far |
| 381 | bump, signer_bump, rewards_bump | 3 × u8 | PDA bumps |
Config layout: admin (8), treasury (40), curve_fee_bps u16 (72), tax_bps u16 (74), protocol_share_bps u16 (76), pusher_cap_bps u16 (78), price_multiple u16 (80), supply_total u64 (82), supply_for_sale u64 (90), launch_fee_lamports u64 (98), raydium_program (106), raydium_amm_config (138), raydium_create_pool_fee (170), markets_created u64 (202), pusher (210), converter_program (242), bump u8 (274), burn_share_bps u16 (275). You need treasury (for the fee account) and curve_fee_bps.
Pricing
Units everywhere: token base units (6 decimals) and quote base units (the pair asset's own decimals, 9 for SOL). Spot prices from the program are quote base units per whole token, scaled by 1e9. All arithmetic is integer; buyers round up, sellers round down. Replicate it exactly and your quote is the fill.
Which curve. If bit 127 of p0 is set the market is a constant product with virtual reserves: v0 = p0 & ~(1 << 127) (quote base units) and vt0 = p1 (token base units). Every launch since the September 2026 upgrade is this shape. If the bit is clear the market is a straight line with p0 and p1 the scaled prices at s = 0 and s = S (the first markets, including the two listed today).
// constant product (s, Δ, S, vt0 in token base units; v0, quote in quote base units) raised(s) = floor(v0 · s / (vt0 − s)) quote the curve holds after s sold cost(s, Δ) = max(1, raised(s + Δ) − raised(s)) buy Δ from s (Δ ≤ S − s) proceeds(s, Δ) = raised(s) − raised(s − Δ) sell Δ at s (Δ ≤ s) spot(s) = v0 · vt0 · 1e6 / (vt0 − s)² quote base units per whole token // straight line (p0, p1 scaled by 1e9 per whole token; DENOM = 1e6 · 1e9) price(s) = p0 + (p1 − p0) · s / S cost(s, Δ) = ceil( (p0·Δ + (p1 − p0)·(floor(s·Δ / S) + floor(Δ² / 2S))) / DENOM ) proceeds(s, Δ) = floor( (p0·Δ + (p1 − p0)·(floor(s·Δ / S) − floor(Δ² / 2S))) / DENOM ) // both fee(q) = ceil(q · curve_fee_bps / 10000) 1% today buyer pays = cost + fee(cost) ≤ max_quote_in seller receives = proceeds − fee(proceeds) ≥ min_quote_out
The transfer tax. The token program withholds 1.5% of every transfer of the token, on any venue. On a buy the curve sends Δ and the buyer's account receives Δ − ceil(Δ · 150 / 10000), i.e. 98.5%. On a sell the seller sends token_amount, the curve receives 98.5% of it and pays for that net amount. Quote the user on what lands in their wallet.
Pair assets with a transfer fee of their own (a Token-2022 quote mint such as ZCAT): the program grosses the buyer's transfers up so the curve and the treasury receive cost and fee net, and checks the vault actually received it. Size max_quote_in on the grossed-up total (Token-2022's inverse fee calculation). Plain SPL pairs and wrapped SOL need nothing extra.
Worked example, a fresh SOL-paired launch with a 40 SOL graduation target (G = 40,000,000,000 lamports, S = 8e14, T = 1e15):
| virtual reserves | v0 = 13,333,333,334 lamports · vt0 = 1,066,666,666,666,666 base units | vt0 − S = S·(T − S)/(2S − T), v0 = ceil(G·(vt0 − S)/S) |
| spot at s = 0 | 12.5 lamports per token | market cap 12.5 SOL |
| spot at s = S | 200 lamports per token | market cap 200 SOL, and the pool opens at this price |
| buy 1,000,000 tokens from s = 0 | cost 12,511,729 · fee 125,118 · pays 12,636,847 lamports | wallet receives 985,000 tokens |
| then sell those 985,000 | curve receives 970,225 · proceeds 12,139,532 · fee 121,396 · gets 12,018,136 | 1.5% withheld on the way in |
| tokens for 0.1 SOL from s = 0 | 7,940,446.728543 tokens | binary search on cost, 40 steps |
Tokens for a quote amount: cost is monotone in Δ, so binary-search Δ in [0, S − s] for the largest cost ≤ amount (subtract the fee first: amount_net = floor(amount · 10000 / 10100) is a safe start, then check cost + fee(cost) ≤ amount). Market cap = spot × current supply of the mint (supply falls as the buy-back burns tokens). Progress = reserve / graduation_reserve.
Buy
buy(token_amount: u64, max_quote_in: u64) data = [102, 6, 61, 18, 1, 218, 235, 234] ++ u64 LE token_amount ++ u64 LE max_quote_in
Buys token_amount base units from the curve, or whatever is left if less (a bigger order is cut to the remainder, not rejected), for at most max_quote_in quote base units including the fee. Selling out sets phase = Complete.
| # | Account | Flags | How to get it |
|---|---|---|---|
| 1 | buyer | signer, writable | the wallet |
| 2 | config | PDA(["config"]) | |
| 3 | market | writable | PDA(["market", mint]) |
| 4 | market_signer | PDA(["signer", mint]) | |
| 5 | mint | market.mint | |
| 6 | quote_mint | market.quote_mint | |
| 7 | token_vault | writable | market.token_vault |
| 8 | quote_vault | writable | market.quote_vault |
| 9 | buyer_token | writable | ATA(buyer, mint, Token-2022); created by the program if missing (init_if_needed, buyer pays rent) |
| 10 | buyer_quote | writable | ATA(buyer, quote_mint, quote program); must exist and hold max_quote_in. For SOL: wrap first (below) |
| 11 | treasury_quote | writable | ATA(treasury, quote_mint, quote program); create-idempotent it in the same transaction, it may not exist for a new pair |
| 12 | token_program | Token-2022 | |
| 13 | quote_token_program | the owner program of quote_mint (Token or Token-2022) | |
| 14 | associated_token_program | ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL | |
| 15 | system_program | 11111111111111111111111111111111 |
Wrapped SOL. A SOL-paired market has quote_mint = So11111111111111111111111111111111111111112. The reference transaction: SetComputeUnitLimit(300,000); CreateIdempotent ATA(buyer, WSOL); SystemProgram.transfer(buyer → that ATA, max_quote_in); SyncNative; CreateIdempotent ATA(treasury, WSOL); buy; CloseAccount(WSOL ATA → buyer), which also refunds whatever the fill did not use. A buy runs in about 60,000 compute units.
With @coral-xyz/anchor and the IDL, the PDAs and buyer_token resolve themselves: pass buyer, mint, quoteMint, tokenVault, quoteVault, buyerQuote, treasuryQuote, tokenProgram, quoteTokenProgram.
Sell
sell(token_amount: u64, min_quote_out: u64) data = [51, 230, 133, 164, 1, 127, 131, 173] ++ u64 LE token_amount ++ u64 LE min_quote_out
Sends token_amount base units to the curve (98.5% arrive) and pays proceeds minus the fee, at least min_quote_out. Rejected when the market is not in phase Curve or the amount exceeds tokens_sold.
| # | Account | Flags | How to get it |
|---|---|---|---|
| 1 | seller | signer, writable | the wallet |
| 2 | config | PDA(["config"]) | |
| 3 | market | writable | PDA(["market", mint]) |
| 4 | market_signer | PDA(["signer", mint]) | |
| 5 | mint | market.mint | |
| 6 | quote_mint | market.quote_mint | |
| 7 | token_vault | writable | market.token_vault |
| 8 | quote_vault | writable | market.quote_vault |
| 9 | seller_token | writable | ATA(seller, mint, Token-2022) |
| 10 | seller_quote | writable | ATA(seller, quote_mint, quote program); create-idempotent first. For SOL: close it after the sell to unwrap |
| 11 | treasury_quote | writable | ATA(treasury, quote_mint, quote program); create-idempotent first |
| 12 | token_program | Token-2022 | |
| 13 | quote_token_program | the owner program of quote_mint |
Errors you will meet: 6007 CurveClosed (phase is not Curve: sold out or graduated), 6009 SlippageExceeded (buy), 6010 SlippageBelowMin (sell), 6011 SellExceedsSold, 6017 BadTokenAccount (wrong owner or mint on a quote account), 6025 WrongTokenProgram (the token side must be Token-2022), 6035 ShortReceived (a fee-on-transfer pair delivered less than cost).
Events
Anchor events, base64 after Program data: in the transaction log, first 8 bytes the discriminator, then the fields little-endian. Trade carries the post-trade state, so one log subscription is a complete price and volume feed.
Trade [24, 254, 218, 152, 253, 43, 18, 81] market pubkey · trader pubkey · side u8 (0 buy, 1 sell) · tokens u64 · quote u64 · fee u64 · tokens_sold u64 · reserve u64 buy: tokens = what the curve sold (the wallet gets 98.5%), quote = cost before the fee sell: tokens = what arrived at the curve after the tax, quote = what the seller received after the fee MarketCreated [88, 184, 130, 231, 226, 84, 6, 58] market · mint · quote_mint · creator · graduation_reserve u64 · p0 u128 · p1 u128 Graduated [51, 241, 66, 50, 140, 245, 156, 192] market · pool · quote_seeded u64 · tokens_seeded u64 · lp_burned u64
Graduation
When tokens_sold reaches supply_for_sale the phase becomes Complete and the curve stops. Anyone may then call graduate; bagggr's keeper does within a minute. It creates a Raydium CPMM pool with the whole reserve and the 200,000,000 held-back tokens at the curve's final price, and burns the LP. The market's pool field and the Graduated event give you the pool; from then on route the token like any Raydium CPMM pair (Jupiter indexes it). The 1.5% transfer tax keeps applying on every transfer, including pool swaps, so a graduated buy also lands 98.5%.
REST API
Optional, for charts and history; everything above needs only an RPC. Base URL https://bagggr.com, JSON, no key. Please cache: the site refreshes market state every 10 s and candles every 20 s.
| GET /api/markets | every listed market: name, symbol, image, curve in whole units, state, phase, pool, quote info, 24h stats |
| GET /api/candles/<mint>?tf=1m|5m|15m|1h|4h|1d&limit=&since= | OHLCV in pair-asset units, sampled by the site from the curve and, after graduation, the pool |
| GET /api/trades/<mint>?limit= | trades newest first: wallet, side, price, amount, venue (curve or pool) |
| GET /api/holders/<mint> | holder count and the top 20 wallets |
| GET /api/art/<mint> | the token image (PNG/JPG/WebP), cached |
| GET /api/token/<mint> | name, symbol, decimals, logo and price of any mint (for pair assets) |
Test on mainnet
Two public markets are live on the curve today. Both are straight-line markets (launched before the constant-product upgrade); ask us for a fresh SOL-paired launch to test the constant-product shape.
| Token | Mint | Market | Pair |
|---|---|---|---|
| ANONYMOUS CAT (NONCAT) | GELcZDVEMxDiuWmdNAfdRAdvLkdTWzGVuQpdoUKGkrYT | 3WDZv1MCLhM28BXCiYDwFPu6gYG66NnzaeMVuWbqt6kU | ZEC · A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS (8 decimals) |
| TEST | AMDDzZRPUpdLP2cuxLAxgF1QqAKFNujfQ4WgPqrZf31o | 6GLdXpbPzshW2FTFwZyvAiAEBNuwKYgQNCH2aquKneBL | PONKE · 5z3EqYQo9HiCEs3R84RCDMu2n7anpDMxRhdK8PSWmrRC |
Compare your numbers with the token page (https://bagggr.com/token/<mint>) and with /api/markets: the site runs the same integer math against the same account, so a quote that differs by more than a base unit means a unit mismatch. Every market the program has ever created is in the getProgramAccounts result, including test launches the site hides.