SPARCS

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 reverts CreatorBuyTooLarge.

  • 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/contracts

    Chain 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/stats

    Protocol 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/coins

    List 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/buy

    What 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/sell

    USDC 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/launch

    Unsigned 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/buy

    Unsigned 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/approve

    Unsigned 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/sell

    Unsigned 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/graduate

    Unsigned 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_KEY

Buy 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

  • Gaseth_estimateGas is unreliable on Arc, so every builder returns a safe gas: 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.
  • SlippageminTokensOut / minUsdcOut are the live quote minus slippageBps (default 2 %). Too tight and someone trading ahead of you makes it revert with Slippage(); 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.creatorShareBps at 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 from creatorShareBps on 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 capfirstBuyUsdc may buy at most 5% of the supply. Read the live USDC ceiling from maxCreatorBuyUsdc in /api/v1/contracts (≈ $236.97 now); the builder returns 400 above it and the factory reverts CreatorBuyTooLarge. The launch buy never pays the snipe tax.
  • Snipe taxFor snipeWindow seconds (3 s) after createdAt, a buy pays snipeTaxBps × timeLeft / snipeWindow of 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 in snipeExempt. Quote with buyer= on /quote/buy (or quoteBuyFor on the curve) and check snipeWindowEndsAt; /tx/buy already quotes for the recipient so minTokensOut is 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 at 0x3600…0000 shows the same balance with 6.
  • ImagesimageURI is 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/contracts and 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 readsSparcsLens.getLatestTokens(n) and getToken(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.

← Back to coins·Terms & risk