{"agent":"reviewer","tool":"read_page","args":{"url":"https://www.stonkfun.xyz/developers"},"result":"<untrusted_content source=\"https://www.stonkfun.xyz/developers\">\nTitle: Developer API · StonkFun\n\nStonkFun\n$STONK\nRewards\nFlywheel\nRevenue\nAPI\nSearch\nCtrl K\nLaunch token\nConnect wallet\nDeveloper API\n\nRead market data and launch tokens over plain HTTP. There is no API key and nothing to sign up for: a launch is authorised by your own wallet's signature on the fee payment, which is stronger proof than any key we could issue. So we don't issue one.\n\nNon-custodial throughout. We never ask for, accept or store a private key; you sign the launch fee locally, and no endpoint will sign on your behalf or make the platform wallet sign anything you supply.\n\nBase URL /api/public/v1\n\nQuickstart#\n\nEvery endpoint is open behind a per-minute rate limit per IP address. Start from a terminal:\n\nterminal\nCopy\n# No key, no signup, no plan. Just call it.\ncurl https://www.stonkfun.xyz/api/public/v1/tokens?sort=newest\n\n# Launching is the same — what authorises it is your own\n# signature on the launch fee, not a token we hand you.\ncurl https://www.stonkfun.xyz/api/public/v1/pairs?launchable=true\nBuilding it yourself#\n\nThe two calls above hand you a transaction we built. You can skip them entirely and construct the launch yourself against Raydium's LaunchLab program — your own mint keypair, your own instructions, your own bundle — and still get everything this platform does around a launch. Two reads are all you need from us: GET /pairs for a pair, and GET /launchlab/pricing for the numbers that go in the create instruction.\n\nWhat ties the two together is the platform id you bake into the pool. It is what the LaunchLab program charges the 1% curve fee to, and it is what we scan for: every minute we read the pools attributed to our platforms and adopt the ones we do not already have a record of. An adopted launch is indistinguishable from an API-created one — token page, chart, volume, fee ledger, holder rewards — and the pool's own creator account is who gets paid, so a standard launch forwards its creator share to your wallet without you registering anything.\n\nSizing: one number, and it is not the SDK's\n\ntotalFundRaisingB is a RAW amount in the quote token's decimals, and Raydium's own constant is 85 SOL written in lamports. Pass it through on an 8-decimal xStock and you have asked for a 850-unit raise; on a 6-decimal stablecoin, 85,000. Both launch happily and graduate at a market cap nobody intended. raise.raw from the pricing call is the integer to use — sized so your launch opens and graduates where one launched here would — and curve.derived carries the virtual reserves the program will compute from it, so you can check your opening price before signing rather than after landing. It is priced at request time; re-fetch if you have been sitting on the response.\n\nWhat we adopt, exactly\n\nAttribution is necessary but not sufficient: a pool carrying our platform id is adopted only if it matches the launch our own builder would have produced. Everything in this list comes straight out of the pricing response, so matching it is a matter of not substituting your own values:\n\nthe GlobalConfig from curve.configId, and a constant-product curve migrating to cpmm;\nsupply and totalSellA as given — they fix the open-to-graduation run — with a positive totalFundRaisingB;\na base mint created by initialize_with_token2022 at 6 decimals, which every LaunchLab launch is;\nno transfer-fee extension at all for a standard launch, or a rate from modes.reward.transferFeeBps for a reward one — the extension IS the mode, and it is read off the mint rather than claimed;\nthe platform id that matches that mode: platform.standard for an untaxed mint, platform.reward for a taxed one;\nthe platform's curve-rule account — curveRule.standard / curveRule.reward from pricing — appended as the LAST account of the initialize, read-only. Ignored until the platform enforces its launch shape on-chain; once it does, an initialize without it is refused outright (6018) and one outside this list is refused too (6025).\n\nMiss any of them and nothing bad happens on chain — the pool exists and trades on Raydium — but this platform never records it, which for a standard launch means no fee forwarding, and for a taxed one means the warning below.\n\nA taxed mint you get wrong taxes holders for nobody\n\nOn a reward launch the program assigns our platform's withhold authority (modes.reward.withdrawWithheldAuthority) to the mint at creation. Holders are taxed on every transfer from the first trade, and only that wallet can ever withdraw what is withheld. If the launch is adopted we collect it and pay it out to holders on the reward cycle. If it is not — wrong curve, wrong config, an unpublished tax rate — the tax accrues and is never distributed to anyone. Land a standard launch first, confirm it appears in GET /tokens with launchpad: \"launchlab\", and only then build a taxed one.\n\nThe whole thing, end to end:\n\nbuild.mjs\nCopy\nimport {\n  ComputeBudgetProgram, Connection, Keypair, PublicKey, Transaction,\n} from '@solana/web3.js';\nimport { TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';\nimport {\n  getPdaLaunchpadAuth, getPdaLaunchpadConfigId, getPdaLaunchpadPoolId, getPdaLaunchpadVaultId,\n  getPdaPlatformAllowConfig, getPdaPlatformCurveRule, initializeWithToken2022,\n} from '@raydium-io/raydium-sdk-v2';\nimport BN from 'bn.js';\n\nconst API = 'https://www.stonkfun.xyz/api/public/v1';\nconst QUOTE = 'YOUR_QUOTE_MINT';   // a mint from /pairs\nconst TAX_BPS = 100;               // reward launch: an offered tier. 0 = standard, no tax.\nconst COMMUNITY_MODE = false;      // reward launch on the Community Mode platform.\nconst connection = new Connection(pickRpcUrl());\nconst creator = Keypair.fromSecretKey(/* your own wallet, never sent anywhere */);\n\nconst get = async (path) => (await (await fetch(API + path)).json()).data;\n\n// 1. The pair must be launchable here AND carry a LaunchLab config on chain.\nconst { pairs } = await get('/pairs?launchable=true&launchLabReady=true');\nconst pair = pairs.find((item) => item.mint === QUOTE);\nif (!pair) throw new Error('Not launchable against that quote right now');\n\n// 2. Size the curve. raise.raw is a raw amount in the quote's decimals. The SDK's 85-SOL\n//    constant would mean 850 units on an 8-decimal xStock and 85,000 on a 6-decimal stablecoin.\nconst pricing = await get(`/launchlab/pricing?quoteMint=${QUOTE}`);\nif (TAX_BPS && !pricing.modes.reward.transferFeeBps.includes(TAX_BPS)) {\n  throw new Error('That tax rate is not one this platform publishes');\n}\nif (COMMUNITY_MODE && (!TAX_BPS || !pricing.communityMode.offeredOnThisQuote)) {\n  throw new Error('Community Mode is a reward launch, offered only on communityMode.quotes');\n}\n\n// 3. Build the create. The platform id attributes the pool to us, and it is the mode: pick it.\nconst mode = TAX_BPS ? (COMMUNITY_MODE ? 'community' : 'reward') : 'standard';\n// Take the platform id from the same pricing response the accounts are checked against below.\nconst programId = new PublicKey(pricing.curve.programId);\nconst platformId = new PublicKey(pricing.platform[mode]);\nconst quoteMint = new PublicKey(QUOTE);\n\n// Derive the quote's GlobalConfig and the platform's two accounts for it from the platform id\n// above. Read the platform id on every build: it can change. Check each address against the\n// pricing response and stop on a difference: your SDK and this API disagree.\nconst configId = getPdaLaunchpadConfigId(programId, quoteMint, 0, 0).publicKey;\nconst allowConfigId = getPdaPlatformAllowConfig(programId, platformId, configId).publicKey;\nconst curveRuleId = getPdaPlatformCurveRule(programId, platformId, configId).publicKey;\nif (\n  !configId.equals(new PublicKey(pricing.curve.configId)) ||\n  !allowConfigId.equals(new PublicKey(pricing.allowConfig[mode])) ||\n  !curveRuleId.equals(new PublicKey(pricing.curveRule[mode]))\n) {\n  throw new Error('Derived accounts differ from the pricing response');\n}\n\nconst mintKeypair = Keypair.generate();\nconst mint = mintKeypair.publicKey;\nconst { publicKey: poolId } = getPdaLaunchpadPoolId(programId, mint, quoteMint);\n\nconst instruction = initializeWithToken2022(\n  programId,\n  creator.publicKey,                       // payer\n  creator.publicKey,                       // creator: the wallet fees are forwarded to\n  configId,\n  platformId,\n  getPdaLaunchpadAuth(programId).publicKey,\n  poolId,\n  mint,\n  quoteMint,\n  getPdaLaunchpadVaultId(programId, poolId, mint).publicKey,\n  getPdaLaunchpadVaultId(programId, poolId, quoteMint).publicKey,\n  // mintProgramB — the program owning the QUOTE mint. Every xStock is Token-2022, so reading it\n  // from the pair rather than assuming classic SPL is what keeps the account correct.\n  new PublicKey(pair.tokenProgram),\n  pricing.curve.baseDecimals,\n  'My Token', 'MYTKN', 'https://example.com/metadata.json',\n  {\n    type: 'ConstantCurve',\n    supply: new BN(pricing.curve.supply),\n    totalSellA: new BN(pricing.curve.totalSellA),\n    totalFundRaisingB: new BN(pricing.raise.raw),   // must come from the pricing response\n    migrateType: 'cpmm',\n  },\n  new BN(0), new BN(0), new BN(0),         // no vesting\n  pricing.curve.cpmmCreatorFeeOn,\n  // Reward mode only. Both keys must match the Raydium SDK's declaration exactly, as written\n  // here. The SDK ignores keys it does not recognise and then writes a zero-rate transfer-fee\n  // extension, which looks taxed but collects nothing.\n  TAX_BPS ? { transferFeeBasePoints: TAX_BPS, maxinumFee: new BN('1000000000000000') } : undefined\n);\n\n// Account 10 is the base token program (always Token-2022) and 11 the quote program passed\n// above. Check them: a reshuffled SDK layout must fail here, not on chain.\nif (!instruction.keys[10].pubkey.equals(TOKEN_2022_PROGRAM_ID)) throw new Error('layout changed');\nif (!instruction.keys[11].pubkey.equals(new PublicKey(pair.tokenProgram))) {\n  throw new Error('layout changed');\n}\n\n// Always append the allow-config account, then the curve-rule account, both read-only. This\n// create stays valid when the platform turns its allowlist on or off. An initialize missing a\n// required account fails with error 6018, and one outside the published shape fails with 6025.\ninstruction.keys.push({ pubkey: allowConfigId, isSigner: false, isWritable: false });\ninstruction.keys.push({ pubkey: curveRuleId, isSigner: false, isWritable: false });\n\n// 4. Sign with both the creator and the new mint, then send it yourself.\nconst { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');\nconst tx = new Transaction()\n  .add(ComputeBudgetProgram.setComputeUnitLimit({ units: 600_000 }))\n  .add(instruction);\nObject.assign(tx, { recentBlockhash: blockhash, lastValidBlockHeight, feePayer: creator.publicKey });\ntx.sign(creator, mintKeypair);\nconsole.log('sent:', await connection.sendRawTransaction(tx.serialize()));\n\n// 5. There is nothing else to call. Within a minute or two the pool is adopted. Once the venue\n//    is public, GET /tokens/${mint} answers with launchpad \"launchlab\".\n\nTwo details in there are worth repeating, because both fail silently. The transfer-fee parameters take the exact names the Raydium SDK declares — transferFeeBasePoints and maxinumFee — and a key that does not match is simply ignored, leaving an extension with a zero rate: a mint that looks like a reward coin and taxes nobody. The SDK also supplies the classic SPL program in the quote-token-program account, so a Token-2022 quote (every xStock) needs that key substituted before you sign.\n\nYou pay only what Solana charges — rent, fees, and any priority fee you add. There is no launch fee on this path and nothing to submit to us afterwards: no paymentSignature exists to poll, so watch GET /tokens/{mint} instead. A dev buy is yours to arrange too — append a buy_exact_in to the same transaction and it fills against a pool nobody has touched.\n\nClaiming fees#\n\nA fee coin accrues creator fees, a share of every trading fee — about half on the default 1% pool, about three quarters on the 2% tier — on a locked position until they are claimed. The token page has a button for it;\n…(truncated)\n\nLinks:\nhttps://www.stonkfun.xyz/\nhttps://www.stonkfun.xyz/token/6GmAFSYs4gk3FDao5FzzySQpPZaWsa4rUJHacpMpUNgx\nhttps://www.stonkfun.xyz/rewards\nhttps://www.stonkfun.xyz/flywheel\nhttps://www.stonkfun.xyz/revenue\nhttps://www.stonkfun.xyz/developers\nhttps://t.me/stonkfunxyz\nhttps://x.com/launchonsf\nhttps://www.stonkfun.xyz/launch\nhttps://www.stonkfun.xyz/developers#quickstart\nhttps://www.stonkfun.xyz/developers#build-your-own\nhttps://www.stonkfun.xyz/developers#claiming\nhttps://www.stonkfun.xyz/developers#rate-limits\nhttps://www.stonkfun.xyz/developers#endpoints\nhttps://www.stonkfun.xyz/api/public/v1/openapi.json\nhttps://www.stonkfun.xyz/developers#errors\n</untrusted_content>","isError":false,"images":[]}