Docs

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.

Program9GMVRdY66xm3SZQEvedDso14Ekwg2iEkWEJo1z1YqZfG
Config PDACcYZwk2bMuHzbQoBjSkBV1AVa5h3AzH3tdKtK6AXHW3oPDA(["config"])
Treasury7fz8aGRq14yGeyefyLLNXsZCKGsfdUJhAzVsR6pQoE6Hreceives the 1% curve fee, in the pair asset
Token programTokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEbevery launched token is Token-2022, 6 decimals, with a fixed 1.5% transfer fee
Raydium CPMMCPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1Cwhere a graduated token trades
Raydium fee tierD4FPEruKEHrG5TenZ2mpDGEfu1iUvTiqBxvpU8HLBvC2amm_config the pools are created with (0.25%)
Metaplex metadatametaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1sname, symbol and URI at PDA(["metadata", program, mint])

Live config (readable from the config PDA, layout below):

curve_fee_bps1001% of the quote leg of every curve trade, to the treasury
tax_bps150the Token-2022 transfer fee on every launched token, on every transfer, anywhere
supply_total1,000,000,000 tokens1e15 base units; the mint authority is revoked at launch
supply_for_sale800,000,000 tokenssold on the curve; the other 200,000,000 seed the pool
price_multiple00 = 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):

OffsetFieldTypeMeaning
8creatorpubkeythe launching wallet
40mintpubkeythe token (Token-2022)
72quote_mintpubkeythe pair asset buyers pay with: wrapped SOL, a stablecoin, anything SPL
104token_vaultpubkeythe curve's token account (ATA of market_signer)
136quote_vaultpubkeythe curve's pair-asset account (ATA of market_signer)
168reward_vaultpubkeywhere harvested transfer fees wait for a push (not part of trading)
200p0u128curve parameter, see Pricing (bit 127 set = constant product)
216p1u128curve parameter
232supply_for_saleu64token base units the curve sells in total (S)
240supply_totalu64token base units minted (T)
248tokens_soldu64base units sold so far (s); rises on buys, falls on sells
256reserveu64quote base units the curve holds, net of fees; equals the quote vault balance
264graduation_reserveu64quote base units at which the curve is full (G)
272fees_collectedu64curve fees paid to the treasury so far
280phaseu80 Curve (tradable here), 1 Complete (sold out, waiting for graduate), 2 Graduated (trade the pool)
281rewards36 bytesmode u8 (0 creator, 1 holders, 2 burn), scope u8, interval_minutes u16, fee_wallet pubkey
317poolpubkeythe Raydium CPMM pool once graduated, else the zero pubkey
349created_ati64unix seconds
357graduated_ati64unix seconds, 0 until graduation
365last_push_ati64last reward push
373pushed_totalu64pair-asset base units paid to the creator or holders so far
381bump, signer_bump, rewards_bump3 × u8PDA 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 reservesv0 = 13,333,333,334 lamports · vt0 = 1,066,666,666,666,666 base unitsvt0 − S = S·(T − S)/(2S − T), v0 = ceil(G·(vt0 − S)/S)
spot at s = 012.5 lamports per tokenmarket cap 12.5 SOL
spot at s = S200 lamports per tokenmarket cap 200 SOL, and the pool opens at this price
buy 1,000,000 tokens from s = 0cost 12,511,729 · fee 125,118 · pays 12,636,847 lamportswallet receives 985,000 tokens
then sell those 985,000curve receives 970,225 · proceeds 12,139,532 · fee 121,396 · gets 12,018,1361.5% withheld on the way in
tokens for 0.1 SOL from s = 07,940,446.728543 tokensbinary 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.

#AccountFlagsHow to get it
1buyersigner, writablethe wallet
2configPDA(["config"])
3marketwritablePDA(["market", mint])
4market_signerPDA(["signer", mint])
5mintmarket.mint
6quote_mintmarket.quote_mint
7token_vaultwritablemarket.token_vault
8quote_vaultwritablemarket.quote_vault
9buyer_tokenwritableATA(buyer, mint, Token-2022); created by the program if missing (init_if_needed, buyer pays rent)
10buyer_quotewritableATA(buyer, quote_mint, quote program); must exist and hold max_quote_in. For SOL: wrap first (below)
11treasury_quotewritableATA(treasury, quote_mint, quote program); create-idempotent it in the same transaction, it may not exist for a new pair
12token_programToken-2022
13quote_token_programthe owner program of quote_mint (Token or Token-2022)
14associated_token_programATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL
15system_program11111111111111111111111111111111

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.

#AccountFlagsHow to get it
1sellersigner, writablethe wallet
2configPDA(["config"])
3marketwritablePDA(["market", mint])
4market_signerPDA(["signer", mint])
5mintmarket.mint
6quote_mintmarket.quote_mint
7token_vaultwritablemarket.token_vault
8quote_vaultwritablemarket.quote_vault
9seller_tokenwritableATA(seller, mint, Token-2022)
10seller_quotewritableATA(seller, quote_mint, quote program); create-idempotent first. For SOL: close it after the sell to unwrap
11treasury_quotewritableATA(treasury, quote_mint, quote program); create-idempotent first
12token_programToken-2022
13quote_token_programthe 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/marketsevery 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.

TokenMintMarketPair
ANONYMOUS CAT (NONCAT)GELcZDVEMxDiuWmdNAfdRAdvLkdTWzGVuQpdoUKGkrYT3WDZv1MCLhM28BXCiYDwFPu6gYG66NnzaeMVuWbqt6kUZEC · A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS (8 decimals)
TESTAMDDzZRPUpdLP2cuxLAxgF1QqAKFNujfQ4WgPqrZf31o6GLdXpbPzshW2FTFwZyvAiAEBNuwKYgQNCH2aquKneBLPONKE · 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.