Developers
Build on Sparcs.
The contracts are permissionless. Anyone can launch, trade and read straight from the chain with nothing but an RPC. This API is a convenience on top: it serves reads and builds unsigned transactions for bots, scripts and other sites. It never signs anything and never sees a key — you sign locally and broadcast yourself.
At a glance
- Base URL
https://sparcs.fun/api/v1- Chain
- Arc Testnet · id
5042002(mainnet is 5042) - Native currency
- USDC, 18 decimals. Every msg.value, balance and amount here is an 18-decimal integer.
- Auth
- None. No keys, no sign-up.
- CORS
Access-Control-Allow-Origin: *on every route, so browsers on other sites can call it.- Rate limit
- 300 requests per minute per IP → HTTP 429.
- Errors
{ "error": "…" }with 400 (input), 404 (not a Sparcs coin), 409 (wrong phase / launches paused), 429, 502 (RPC), 503 (not deployed).
Contracts on Arc Testnet
- SparcsFactory
- 0x52617743…C07e1782
- SparcsLens
- 0xb4CC405b…4167a203
- UniswapV3Adapter
- 0x381F3a48…8e27A900
- LpLocker
- 0xbC589E5F…86444DB5
- RPC
https://rpc.testnet.arc.io— answers servers, returns 503 to browsers- Explorer
- https://testnet.arcscan.app
Supply
1,000,000,000 tokens, exactly
800M sold on the curve, 200M reserved for the Uniswap pool. Nothing minted or burned after launch. 18 decimals.
Launch fee
$1.00
Paid in msg.value with createToken. Anything above it is the creator's first buy.
Trade fee
1%
On every buy and sell, in USDC. The creator picks their cut of it at launch, up to 50% of the fee (0.5% of volume); the rest funds the protocol. Pull-claimed from the factory.
Curve
$4,473 → $69,105
Constant product with virtual reserves. Raises ≈ $14,065 then graduates to a Uniswap v3 pool whose LP is locked forever.
Launch buy cap
5% of supply
The first buy inside createToken may take at most 5% of the supply — ≈ $236.97 right now (
maxCreatorBuyUsdc()). Above it the factory revertsCreatorBuyTooLarge.Snipe protection
99% → 0 over 3 s
Buys in a coin's first 3 s pay a tax on the USDC sent that starts at 99% and decays linearly to 0. It goes to the fee ledger, not the curve. The launch buy, the creator and up to 10 declared wallets are exempt.
Curve maths, for local quoting: tokensOut = net · vT / (vU + net) where net = usdcIn − fee; sells are usdcOut = vU · tokensIn / (vT + tokensIn) minus the fee. Or just call quoteBuy / quoteSell on the curve — or quoteBuyFor(buyer, usdcIn), which also returns the snipe tax that wallet would pay right now.
Reads
Everything is an eth_call against the lens or a curve; there is no indexer. Bigints come back as decimal strings.
- GET
/api/v1/contractsChain id, RPC, explorer, contract addresses, live launch fee, curve params and launch limits (max creator share, launch-buy cap, snipe window), gas limits, event topics, and the full factory / curve / token / lens ABIs so you can skip this API entirely.
Request
curl https://sparcs.fun/api/v1/contracts
Response
{ "chainId": 5042002, "chain": "Arc Testnet", "rpc": "https://rpc.testnet.arc.io", "explorer": "https://testnet.arcscan.app", "factory": "0x52617743d06Db65A16eA06c9Da063Be8C07e1782", "lens": "0xb4CC405bb0805E41E27cA01a9Cff603A4167a203", "launchFee": "1000000000000000000", "launchesPaused": false, "params": { "virtualUsdc": "4800000000000000000000", "virtualToken": "1073000000000000000000000000", "curveSupply": "800000000000000000000000000", "lpSupply": "200000000000000000000000000", "tradeFeeBps": "100", "snipeWindow": "3", // seconds after launch during which buys pay the snipe tax "snipeTaxBps": "9900" // tax at t=0, decays linearly to 0 at snipeWindow }, "totalSupply": "1000000000000000000000000000", "maxCreatorShareBps": 1000, // the creator's cut of the fee is chosen at launch, 0..this (bps OF THE FEE) "maxCreatorBuyBps": 500, // the launch buy may take at most 5 % of supply … "maxCreatorBuyUsdc": "254545454545454545454", // … which is this much USDC right now (factory.maxCreatorBuyUsdc()) "maxSnipeExempt": 10, // wallets a launch may declare snipe-tax exempt "snipe": { "window": "3", "taxBps": "9900", "note": "…" }, "gas": { "createToken": "5000000", "buy": "400000", "buyFilling": "7000000", "sell": "400000", "approve": "80000", … }, "events": { "TokenCreated": { "topic0": "0x18e3…abcb", "indexed": ["token", "curve", "creator"] }, "LaunchConfigured": { "topic0": "0x…", "indexed": ["token", "launcher"] }, // creatorShareBps + snipeExempt list "SnipeTaxed": { "topic0": "0x…", "indexed": ["trader"] } }, "abis": { "factory": [ … ], "curve": [ … ], "token": [ … ], "lens": [ … ] } } - GET
/api/v1/statsProtocol analytics read live from the contracts: all-time and rolling-24h volume, launches, trades and graduations, a 14-day daily series, and the flywheel (buyback & burn) balances. Volume counts bonding-curve trades only; Uniswap swaps after graduation are not included. Memoized server-side for two minutes.
Request
curl https://sparcs.fun/api/v1/stats
Response
{ "chainId": 5042002, "updatedAt": 1757548800000, "partial": false, // true when only the newest coins were scanned for the all-time totals "totals": { "coins": 12, "scanned": 12, "graduated": 2, "volumeUsdc": "48211500000000000000000", "trades": 1930, "creators": 9 }, "last24h": { "volumeUsdc": "9120000000000000000000", "trades": 410, "launches": 3, "graduations": 1 }, "prior24h": { "volumeUsdc": "7810000000000000000000", "trades": 352, "launches": 2, "graduations": 0 }, "daily": [ { "day": "2026-08-28", "dayStart": 1756339200, "volumeUsdc": "…", "trades": 12, "launches": 1, "graduations": 0 }, … ], // 14 UTC days, oldest first "flywheel": { "platformToken": "0x…", "buyback": "0x…", "splitter": "0x…", "ledgerProtocolUsdc": "…", // protocol share of other coins' fees, claimable by the splitter "ledgerPlatformUsdc": "…", // $SPARCS's own fees, claimable by the buyback "splitterPendingUsdc": "…", "splitterBalanceUsdc": "…", // pending = balance + unclaimed ledger share "buybackBps": 8000, "totalToBuybackUsdc": "…", "totalToOpsUsdc": "…", "buybackPendingUsdc": "…", "buybackBalanceUsdc": "…", // pending = what the next buybackAndBurn() spends "totalUsdcSpent": "…", "totalBurned": "…", "buybacks": 41, "callerRewardBps": 50, "platformSupply": "…" } } - GET
/api/v1/coinsList coins. Same tabs as the home page; hidden tokens are excluded. All amounts are 18-decimal integers as strings.
- sort
- new (default) · trending · graduating (≥ 50 % sold, not graduated) · graduated
- limit
- 1–200, default 50
- offset
- default 0
Request
curl "https://sparcs.fun/api/v1/coins?sort=new&limit=50"
Response
{ "coins": [ { "token": "0xFf151E5cA37599827905dE254761bbac5B4dbB3c", "curve": "0xf6842Cd01DCDdd9C61245c5259837Da64429c4C6", "creator": "0x936077fC9bfBb0eFe229eB96fbF2e856768012F2", // fee recipient "launcher": "0x936077fC9bfBb0eFe229eB96fbF2e856768012F2", // wallet that sent the launch tx (may differ) "creatorShareBps": 1000, // the creator's cut of the trade fee, chosen at launch "name": "Peg", "symbol": "PEG", "imageURI": "https://…/peg.svg", "description": "…", "website": "", "twitter": "", "telegram": "", "phase": "trading", // "trading" | "filled" | "graduated" "pool": null, // Uniswap v3 pool once graduated "price": "4479897436116", // USDC per token, 18 decimals "marketCap": "4479897436116000000000", "progressBps": 9, // 10000 = curve sold out "tokensSold": "773728473518629120975237", "realUsdc": "3463724748697034329", "totalVolumeUsdc": "8476275251302965671", "tradeCount": "3", "holderCount": "3", "createdAt": "1789093046", "lastTradeAt": "1789094473", "snipeWindow": 3, "snipeTaxBps": 9900, "snipeWindowEndsAt": "1789093049", "snipeTaxCollected": "0", "curveSupply": "…", "lpSupply": "…", "virtualUsdc": "…", "virtualToken": "…", "tradeFeeBps": 100, "totalSupply": "…", "filledAt": "0" } ], "total": 3, "offset": 0, "limit": 50, "sort": "new" } - GET
/api/v1/coins/{token}One coin (same fields as above) plus its last 200 trades, oldest first. 404 if the address is not a Sparcs token.
- token
- token address (path)
Request
curl https://sparcs.fun/api/v1/coins/0xFf151E5cA37599827905dE254761bbac5B4dbB3c
Response
{ "token": "0xFf151E5cA37599827905dE254761bbac5B4dbB3c", "symbol": "PEG", "phase": "trading", …, "trades": [ { "trader": "0x9360…12F2", "timestamp": 1789093046, "side": "buy", "usdc": "1000000000000000000", "tokens": "221260614998156630195022", "priceAfter": "4475284440062" }, { "trader": "0x01Cf…83ff", "timestamp": 1789094473, "side": "sell", "usdc": "2451512498789936015", "tokens": "552467858520472490780215", "priceAfter": "4479897436116" } ] } - GET
/api/v1/quote/buyWhat a given amount of USDC buys right now, from the curve's own quoteBuy — or quoteBuyFor(buyer, usdc) when you pass buyer, which includes the snipe tax that wallet would pay inside the launch window (0 for the creator and declared wallets). Always pass buyer when quoting a coin that just launched. 409 unless the coin is trading.
- token
- token address
- usdc
- whole USDC, e.g. 5 or 0.25
- buyer
- optional wallet the buy is for; enables the snipe-tax quote
Request
curl "https://sparcs.fun/api/v1/quote/buy?token=0xFf151E5cA37599827905dE254761bbac5B4dbB3c&usdc=5&buyer=0xYOUR_ADDRESS"
Response
{ "buyer": "0xYOUR_ADDRESS", // null when omitted "tokensOut": "1103798538952359103041454", "usdcUsed": "5000000000000000000", // < usdc when the buy would overfill the curve; the rest is refunded "fee": "50000000000000000", "snipeTax": "0", // USDC taken off the top inside the launch window (before the curve math) "snipeTaxBps": "0", // e.g. "6600" = 66 % one second into a 3 s window "snipeWindowEndsAt": "1789093049", // unix seconds; the tax is 0 from then on "snipeWindowOpen": false, "refund": "0", "priceImpactBps": 10, "willFill": false, // true → this buy sells out the curve and triggers graduation "remainingOnCurve": "799226271526481370879024763", "price": "4479897436116" } - GET
/api/v1/quote/sellUSDC received (after the trade fee) for selling tokens back to the curve.
- token
- token address
- tokens
- whole tokens, e.g. 100000
Request
curl "https://sparcs.fun/api/v1/quote/sell?token=0xFf151E5cA37599827905dE254761bbac5B4dbB3c&tokens=100000"
Response
{ "usdcOut": "443468486576547847", "fee": "4479479662389372", "priceImpactBps": 0, "price": "4479897436116" }
Unsigned transactions
Every builder returns the same core shape — { chainId, to, data, value, gas } — plus what it used to build it. Sign with any wallet library and send it as-is: value is the native USDC to attach and gas is a safe limit. Bodies that contain anything named like a private key are rejected with 400.
- POST
/api/v1/tx/launchUnsigned SparcsFactory.createToken(input, options, minTokensOut, deadline). value = launch fee + the optional first buy. The first buy is capped at 5 % of supply (400 above factory.maxCreatorBuyUsdc(); on-chain it would revert CreatorBuyTooLarge) and is exempt from the snipe tax. options carries the fee recipient, the creator's cut of the fee and the snipe-exempt list. minTokensOut comes from the live curve params minus your slippage. Same validation as the launch form.
- name
- required, ≤ 32 bytes
- symbol
- required, ≤ 12 bytes, whitespace stripped
- imageURI
- https:// URL, ≤ 256 bytes (optional, but a coin without one looks broken)
- description
- ≤ 400 bytes, optional
- website · twitter · telegram
- https:// URLs, ≤ 128 bytes each, optional
- firstBuyUsdc
- whole USDC to buy in the same tx, e.g. "1" (optional; ≤ maxCreatorBuyUsdc from /contracts)
- creator
- fee recipient (optional, default = the wallet that sends the tx). Always snipe-exempt
- creatorShareBps
- the creator's cut of the trade fee, in bps OF THE FEE: 0..maxCreatorShareBps (default = the max, 1000 = 10 %)
- snipeExempt
- array of ≤ 10 wallets that never pay the snipe tax (optional)
- slippageBps
- default 200 (2 %), max 5000
- deadlineSeconds
- default 600, min 30
Request
curl -X POST https://sparcs.fun/api/v1/tx/launch \ -H "content-type: application/json" \ -d '{"name":"Arc Frog","symbol":"FROG","imageURI":"https://example.com/frog.png","description":"ribbit", "firstBuyUsdc":"1","creatorShareBps":1000,"snipeExempt":["0xTEAM_WALLET_1","0xTEAM_WALLET_2"]}'Response
{ "chainId": 5042002, "to": "0x52617743d06Db65A16eA06c9Da063Be8C07e1782", "data": "0x…", "value": "2000000000000000000", // 1 USDC fee + 1 USDC first buy "gas": "5000000", "minTokensOut": "216835402698193497591121", "deadline": "1789096026", "launchFee": "1000000000000000000", "firstBuyUsdc": "1000000000000000000", "maxCreatorBuyUsdc": "254545454545454545454", // the 5 %-of-supply ceiling for firstBuyUsdc right now "quote": { "tokensOut": "221260614998156630195022", "usdcUsed": "1000000000000000000", "fee": "10000000000000000", "refund": "0", "willFill": false, "shareOfSupplyBps": 2 }, "input": { "name": "Arc Frog", "symbol": "FROG", "imageURI": "https://example.com/frog.png", "description": "ribbit", "website": "", "twitter": "", "telegram": "" }, "options": { "creator": "0x0000000000000000000000000000000000000000", "creatorShareBps": 1000, "snipeExempt": ["0xTEAM_WALLET_1", "0xTEAM_WALLET_2"], "note": "…" } } // first buy above the cap: { "error": "firstBuyUsdc is too large: the launch buy is capped at 5% of supply, which is at most $254.54 USDC right now (…)" } ← HTTP 400 // creatorShareBps above maxCreatorShareBps: { "error": "creatorShareBps must be between 0 and 1000." } ← HTTP 400 - POST
/api/v1/tx/buyUnsigned BondingCurve.buy(recipient, minTokensOut, deadline) with value = usdc. The quote is quoteBuyFor(recipient, usdc), so inside a coin's launch window minTokensOut already accounts for the snipe tax and the response carries a warning. gas is 7,000,000 when the buy fills the curve (it also seeds the Uniswap pool), else 400,000.
- token
- token address
- usdc
- whole USDC to spend
- recipient
- address that receives the tokens
- slippageBps · deadlineSeconds
- as above
Request
curl -X POST https://sparcs.fun/api/v1/tx/buy \ -H "content-type: application/json" \ -d '{"token":"0xFf151E5cA37599827905dE254761bbac5B4dbB3c","usdc":"5","recipient":"0xYOUR_ADDRESS","slippageBps":200}'Response
{ "chainId": 5042002, "to": "0xf6842Cd01DCDdd9C61245c5259837Da64429c4C6", // the curve, not the token "data": "0xa59ac6dd0000…", "value": "5000000000000000000", "gas": "400000", "minTokensOut": "1081722568173311920980624", "deadline": "1789096026", "quote": { "tokensOut": "1103798538952359103041454", "usdcUsed": "5000000000000000000", "fee": "50000000000000000", "snipeTax": "0", "snipeTaxBps": "0", "snipeWindowEndsAt": "1789093049", "refund": "0", "priceImpactBps": 10, "willFill": false } } - POST
/api/v1/tx/approveUnsigned ERC-20 approve(curve, amount) on the token. Needed once before sell; the curve pulls tokens with transferFrom.
- token
- token address
- amount
- whole tokens, or "max"
Request
curl -X POST https://sparcs.fun/api/v1/tx/approve \ -H "content-type: application/json" \ -d '{"token":"0xFf151E5cA37599827905dE254761bbac5B4dbB3c","amount":"max"}'Response
{ "chainId": 5042002, "to": "0xFf151E5cA37599827905dE254761bbac5B4dbB3c", // the token "data": "0x095ea7b3000000000000000000000000f6842cd0…ffff", "value": "0", "gas": "80000", "spender": "0xf6842Cd01DCDdd9C61245c5259837Da64429c4C6", "amount": "115792089237316195423570985008687907853269984665640564039457584007913129639935" } - POST
/api/v1/tx/sellUnsigned BondingCurve.sell(tokensIn, minUsdcOut, deadline), value 0. Requires the approve above first — or build an EIP-2612 permit yourself and call sellWithPermit(tokensIn, minUsdcOut, deadline, v, r, s) in one transaction, which is what the website does.
- token
- token address
- tokens
- whole tokens to sell (≤ what the curve has sold)
- slippageBps · deadlineSeconds
- as above
Request
curl -X POST https://sparcs.fun/api/v1/tx/sell \ -H "content-type: application/json" \ -d '{"token":"0xFf151E5cA37599827905dE254761bbac5B4dbB3c","tokens":"100000","slippageBps":200}'Response
{ "chainId": 5042002, "to": "0xf6842Cd01DCDdd9C61245c5259837Da64429c4C6", "data": "0xd3c9727c0000…", "value": "0", "gas": "400000", "minUsdcOut": "434599116845016890", "deadline": "1789096027", "quote": { "usdcOut": "443468486576547847", "fee": "4479479662389372", "priceImpactBps": 0 }, "note": "Requires a prior approve(curve, tokens) on the token …" } - POST
/api/v1/tx/graduateUnsigned BondingCurve.graduate(). Only meaningful when the phase is filled (sold out, pool seed deferred); anyone may call it. 409 in any other phase.
- token
- token address
Request
curl -X POST https://sparcs.fun/api/v1/tx/graduate \ -H "content-type: application/json" \ -d '{"token":"0xFf151E5cA37599827905dE254761bbac5B4dbB3c"}'Response
{ "chainId": 5042002, "to": "0x<curve>", "data": "0xd3618cca", "value": "0", "gas": "6500000", "filledAt": "…", "realUsdc": "…" } // while the coin is still trading: { "error": "Cannot graduate: PEG is trading, not filled." } ← HTTP 409
Launch a coin from a bot
TypeScript with viem. One POST, one signature, one receipt.
import { createPublicClient, createWalletClient, defineChain, http, parseEventLogs, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const API = "https://sparcs.fun/api/v1";
const post = (path: string, body: unknown) =>
fetch(API + path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) }).then((r) => r.json());
// 1. Chain + ABIs from the API (don't hard-code the chain id: testnet is 5042002, mainnet 5042).
const info = await fetch(API + "/contracts").then((r) => r.json());
const chain = defineChain({ id: info.chainId, name: info.chain, nativeCurrency: { name: "USDC", symbol: "USDC", decimals: 18 }, rpcUrls: { default: { http: [info.rpc] } } });
const account = privateKeyToAccount(process.env.BOT_PRIVATE_KEY as Hex); // the key never leaves your process
const wallet = createWalletClient({ account, chain, transport: http() });
const client = createPublicClient({ chain, transport: http() });
// 2. The unsigned createToken tx. value = 1 USDC launch fee + 1 USDC first buy (≤ 5 % of supply), minTokensOut = quote − 2 %.
// creatorShareBps = your cut of the 1 % trade fee (max 1000 = 10 % of the fee = 0.1 % of volume). snipeExempt = wallets
// your team opens with; they skip the launch-window snipe tax (your own wallet is exempt automatically).
const tx = await post("/tx/launch", {
name: "Arc Frog", symbol: "FROG", imageURI: "https://example.com/frog.png", description: "ribbit",
firstBuyUsdc: "1", creatorShareBps: 1000, snipeExempt: ["0xTEAM_WALLET_1"],
});
if (tx.error) throw new Error(tx.error);
// 3. Sign, send, wait. Pass gas explicitly — eth_estimateGas is unreliable on Arc.
const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gas: BigInt(tx.gas) });
const receipt = await client.waitForTransactionReceipt({ hash });
// 4. The new addresses are in the TokenCreated log: topics[1] = token, topics[2] = curve, topics[3] = creator.
const [created] = parseEventLogs({ abi: info.abis.factory, eventName: "TokenCreated", logs: receipt.logs });
console.log("token", created.args.token, "curve", created.args.curve, "→", "https://sparcs.fun/t/" + created.args.token);Or skip the API and hit the factory directly. The first argument is a tuple; the tuple syntax and --value are the parts people get wrong.
# Direct route with Foundry. --value 2ether = 2 USDC (cast's "ether" unit is 1e18 base units, and Arc's base unit is USDC):
# 1 USDC launch fee + 1 USDC first buy. minTokensOut is 0 here, so the first buy has no slippage floor.
# The second tuple is LaunchOptions(creator, creatorShareBps, snipeExempt[]): address(0) = your wallet, 1000 = 10 % of the fee.
cast send 0x52617743d06Db65A16eA06c9Da063Be8C07e1782 \
"createToken((string,string,string,string,string,string,string),(address,uint16,address[]),uint256,uint256)" \
'("Arc Frog","FROG","https://example.com/frog.png","ribbit","","","")' \
'(0x0000000000000000000000000000000000000000,1000,[])' 0 $(($(date +%s) + 600)) \
--value 2ether --gas-limit 5000000 \
--rpc-url https://rpc.testnet.arc.io --private-key $BOT_PRIVATE_KEYBuy and sell
Same clients as above. Buys are one transaction. Sells need an approval first because the curve pulls the tokens with transferFrom; if you would rather do it in one go, sign an EIP-2612 permit for the curve and call sellWithPermit.
const token = "0xFf151E5cA37599827905dE254761bbac5B4dbB3c";
// Buy: (optional) quote → unsigned tx → send. value is the USDC you pay; the curve refunds anything it can't use.
// Pass buyer= so the quote includes the snipe tax your wallet would pay in a coin's first seconds (0 once the window closes).
const q = await fetch(API + "/quote/buy?token=" + token + "&usdc=5&buyer=" + account.address).then((r) => r.json());
console.log("≈", q.tokensOut, "tokens · impact", q.priceImpactBps, "bps · snipe tax", q.snipeTaxBps, "bps · fills the curve:", q.willFill);
const buy = await post("/tx/buy", { token, usdc: "5", recipient: account.address, slippageBps: 200 });
const buyHash = await wallet.sendTransaction({ to: buy.to, data: buy.data, value: BigInt(buy.value), gas: BigInt(buy.gas) });
await client.waitForTransactionReceipt({ hash: buyHash });
// Sell: the curve pulls tokens with transferFrom, so approve it first (once with "max", or per sale).
const approve = await post("/tx/approve", { token, amount: "max" });
const approveHash = await wallet.sendTransaction({ to: approve.to, data: approve.data, gas: BigInt(approve.gas) });
await client.waitForTransactionReceipt({ hash: approveHash });
const sell = await post("/tx/sell", { token, tokens: "100000", slippageBps: 200 });
if (sell.error) throw new Error(sell.error); // e.g. 409 once the coin has graduated → trade it on Uniswap instead
await wallet.sendTransaction({ to: sell.to, data: sell.data, gas: BigInt(sell.gas) });Notes
- Gas
eth_estimateGasis unreliable on Arc, so every builder returns a safegas: 5,000,000 for a launch, 400,000 for a buy (7,000,000 when it fills the curve and seeds the pool), 400,000 for a sell, 6,500,000 for a graduation retry. Pass it explicitly; unused gas is not charged. A transaction is capped at 16.7M gas. - DeadlinesEvery trade carries a unix deadline; the curve reverts with
Expired()past it. Default 10 minutes from when you asked. Ask again if you waited. - Slippage
minTokensOut/minUsdcOutare the live quote minusslippageBps(default 2 %). Too tight and someone trading ahead of you makes it revert withSlippage(); too loose and you can be sandwiched. - Fee splitTraders always pay exactly
params.tradeFeeBps(1%). What changes per coin is the creator's cut of that fee:options.creatorShareBpsat launch, in bps of the fee, 0..maxCreatorShareBps(50%). At the max the creator earns 0.5% of all volume and the protocol the rest; the split also applies to snipe tax and, after graduation, to the locked LP's fees. Read a coin's share fromcreatorShareBpson its curve or the coin JSON. The fee recipient (creator) can differ from the wallet that launched (launcher); both are in the coin JSON. - Launch buy cap
firstBuyUsdcmay buy at most 5% of the supply. Read the live USDC ceiling frommaxCreatorBuyUsdcin/api/v1/contracts(≈ $236.97 now); the builder returns 400 above it and the factory revertsCreatorBuyTooLarge. The launch buy never pays the snipe tax. - Snipe taxFor
snipeWindowseconds (3 s) aftercreatedAt, a buy payssnipeTaxBps × timeLeft / snipeWindowof the USDC it sends (99% at t=0, 0 at the end) before the curve math runs. A bot that buys in the first block gets almost nothing. Exempt: the launch tx, the creator, and the ≤ 10 wallets insnipeExempt. Quote withbuyer=on/quote/buy(orquoteBuyForon the curve) and checksnipeWindowEndsAt;/tx/buyalready quotes for the recipient sominTokensOutis right either way. - AmountsInputs are whole units (
"1.5"USDC,"100000"tokens), outputs are 18-decimal integers as strings. USDC on Arc has 18 decimals natively; the ERC-20 view at0x3600…0000shows the same balance with 6. - Images
imageURIis stored on-chain as-is and must be an https URL (≤ 256 bytes). Host it yourself; the website only renders https images. - LimitsName ≤ 32 bytes, symbol ≤ 12, image ≤ 256, description ≤ 400, links ≤ 128 — UTF-8 bytes, enforced by the factory too.
- Testnet vs mainnetThe base URL is the same; the chain id differs (testnet 5042002, mainnet 5042). Read it from
/api/v1/contractsand never assume. Testnet runs the same curve and fees, funded from faucet.circle.com. - Rate limits300 requests per minute per IP across all v1 routes. Reads are cached for a few seconds at the edge. For anything heavier, run your own RPC and read the lens directly.
- Direct reads
SparcsLens.getLatestTokens(n)andgetToken(addr)return everything the list and coin pages show;BondingCurve.getRecentTrades(n)the trades (stored on-chain because public-RPC log ranges are tightly capped);SparcsFactory.curveOf(token),launcherOf(token),launchFee(),params(),maxCreatorShareBps(),maxCreatorBuyUsdc()the rest.