Integration
Launch a token on biddin, from code
biddin is a memecoin launchpad on Arc, Circle's L1 where gas is paid in USDC. A launch is one contract call with no prior approval. Everything on this page is enforced by public contracts, so you can launch, trade, read and index without ever touching our site.
How it works
A token is sold along a bonding curve priced in USDC. When the curve has raised its threshold the token graduates: the proceeds and the remaining supply seed a Uniswap V3 position, the position is locked, and a slice of supply is burned. Trading continues in that pool. The creator keeps earning from every trade, before and after graduation.
Every number above is read from the factory, not from this page. See Reading state for how to fetch them yourself, and What cannot change for which of them are frozen once your token exists.
Graduation
A coin lives on its curve until the curve has taken in 8,000 USDC. Then it graduates, in two permissionless steps anyone can call — our keeper does it within a block or two, and if it ever stops, anybody else can finish the job.
What happens is fixed:
- The curve closes for good. No more buying or selling against it.
- The USDC it collected and the tokens it still holds open a Uniswap V3 pool at the price the curve closed at — so there is no gap for a first buyer to arbitrage.
- About 8.16% of the supply is burned in the same transaction.
- The pool position goes to a locker contract that has no withdrawal function. Not a promise not to pull it — there is no code path that could.
The burn is not a marketing number, it falls out of the arithmetic. The curve prices against a
phantom reserve that has no real USDC behind it, so seeding every remaining token would open the
pool cheaper than the curve closed and hand the first buyer free money, paid for by the people who
bought last. Seeding only what the collected USDC supports at the closing price leaves a surplus,
and that surplus is burned rather than kept. Exactly
1 / (1 + threshold/virtualQuote)² — with 8,000 over 3,200 that is 8.16%.
Sending that surplus anywhere other than a burn address would make it a hidden team allocation, which is why the contract burns it rather than transferring it.
What the creator earns
Creators get no token allocation here. What they get is 70% of the 1% trade fee — 0.70% of every dollar traded, in USDC, on the curve and in the pool afterwards, for as long as the coin trades. There is no cliff, no vesting and no end date.
It accrues to an escrow contract and is claimed with one call. Anyone may trigger that claim, but the money can only ever go to the recipient, never to the caller — so a front end or a relayer can pay a creator out without ever holding their funds.
The right to those fees is a movable thing, not a fixed link to the wallet that launched the coin. Whoever currently holds it can hand it to someone else — a multisig, a treasury, a co-founder — and it only moves forwards, so the launching wallet cannot take it back afterwards. That is what makes launching from a hot wallet safe.
A creator may also set a tax of their own, up to 10%, charged on top of the protocol fee and paid entirely to them. Most do not, and there is a reason: a 5% tax costs someone who buys and later sells 10% of their money, which suppresses the trading volume the 0.70% is calculated on.
Buyback and burn
A creator can point their own fee stream at the coin instead of at their wallet. Switch it on and every fee the coin earns is used to buy the coin back and burn what it buys, from the first trade onwards.
It is a contract, not a policy. Turning it on at launch replaces the fee recipient with a buyback contract deployed for that coin, so the fees never pass through a wallet at all. Nobody — not the creator, not us — can redirect them afterwards or withdraw from it.
| Rule | Value | Why |
|---|---|---|
| Runs when it holds | 50 USDC | Below that the gas is a meaningful share of the buy |
| …or after | 3 days | Then 10 USDC is enough, so a quiet coin still gets its buybacks |
| Max spend per run | 3% of the curve | A buyback should support the price, not spike it |
| Tokens bought | all burned | Burned in the same transaction; the contract never holds the coin between runs |
Who may trigger it is deliberate. Our keeper has it to itself for the first three days after each run, then anyone can call. That is not gatekeeping: an attacker who controls when a buyback fires could buy just before it, sell into it and use the coin's own fees as their exit liquidity. Taking the timing away costs nothing while the keeper is alive, and the public fallback means a dead keeper can never strand a coin's fees.
Everything above is readable on chain: pending() for what is waiting,
totalBurned() for what it has destroyed so far, and a BoughtBack event for
every run.
Quick start — launch in one call
launchWithNative creates the token, opens its curve, optionally buys your own
allocation and optionally enrols the coin in buyback-and-burn — in a single transaction
with no approval step. Arc's gas asset is USDC and the native balance is the same
money as the ERC-20, so the factory is funded by the value you send.
// npm i viem
import { createPublicClient, createWalletClient, http, defineChain } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
export const arc = defineChain({
id: 5042,
name: 'Arc',
nativeCurrency: { name: 'USDC', symbol: 'USDC', decimals: 18 },
rpcUrls: { default: { http: ['https://rpc.arc-scan.org'] } },
});
export const account = privateKeyToAccount(process.env.PRIVATE_KEY);
export const pub = createPublicClient({ chain: arc, transport: http() });
export const wallet = createWalletClient({ account, chain: arc, transport: http() });
import { parseAbi, parseEventLogs, parseUnits } from 'viem';
import { pub, wallet, account } from './client.js';
const FACTORY = '0xA5b69A713bf53C7f6f2E230428CebA62842fc9e2';
const factoryAbi = parseAbi([
'struct Metadata { string name; string symbol; string imageUri; string description; string xUrl; string telegramUrl; string websiteUrl; }',
'struct LaunchOptions { uint16 creatorTaxBps; address creatorFeeRecipient; uint256 devBuyQuote; uint256 devBuyMinTokensOut; bool buyback; address[] snipeTaxExemptions; }',
'function launchWithNative(Metadata meta, LaunchOptions opts) payable returns (address token, address curve)',
'function params() view returns (uint256 saleSupply, uint256 virtualQuote, uint256 graduationThreshold, uint256 launchFee, uint16 tradeFeeBps, uint16 creatorFeeShareBps, uint16 maxCreatorTaxBps)',
'event Launched(address indexed token, address indexed curve, address indexed creator, string name, string symbol, uint256 saleSupply, uint16 creatorTaxBps)',
// With the errors in the ABI a revert decodes into a name and arguments, not a bare selector.
'error WrongNativeValue(uint256 sent, uint256 needed)',
'error CreatorTaxTooHigh()',
]);
// USDC has two faces on Arc: 6 decimals as an ERC-20, 18 as the native gas balance.
// Every AMOUNT in these structs is the 6-decimal one. Only msg.value is 18.
// parseUnits takes a STRING. Never build a money amount from a float — Math.round(n * 1e6)
// drifts, and it drifts silently.
const NATIVE_SCALE = 10n ** 12n;
const devBuy = parseUnits('50', 6); // 50 USDC of your own coin, same transaction
const [, , , launchFee] = await pub.readContract({
address: FACTORY, abi: factoryAbi, functionName: 'params',
});
const { request, result } = await pub.simulateContract({
address: FACTORY, abi: factoryAbi, functionName: 'launchWithNative', account,
args: [
{ name: 'Example Coin', symbol: 'EXMPL',
imageUri: 'ipfs://bafy...', description: 'launched from code',
xUrl: '', telegramUrl: '', websiteUrl: '' },
{ creatorTaxBps: 0, // your own tax on top of the 1% protocol fee
creatorFeeRecipient: account.address, // zero means the launching wallet
devBuyQuote: devBuy,
devBuyMinTokensOut: 0n, // set a real floor in production
buyback: false,
snipeTaxExemptions: [] },
],
// EXACT. The factory refuses an over- or under-payment rather than keeping the difference.
value: (launchFee + devBuy) * NATIVE_SCALE,
});
const hash = await wallet.writeContract(request);
const receipt = await pub.waitForTransactionReceipt({ hash });
const [launched] = parseEventLogs({ abi: factoryAbi, eventName: 'Launched', logs: receipt.logs });
console.log('token', launched.args.token, 'curve', launched.args.curve);
console.log('simulated return', result); // [token, curve] — same values, before sending
Both over- and under-payment revert with WrongNativeValue(uint256 sent, uint256
needed), which names both numbers — sent first, then what was required. The factory refuses
rather than keeping the difference: it has no sweep and no owner withdrawal, so an over-payment
left inside would be unrecoverable. Compute value from
params().launchFee + devBuyQuote at call time rather than hardcoding it.
If you would rather approve USDC first and send no value, the three
launch(...) overloads do the same work against an ERC-20 allowance:
launch(meta) for defaults, launch(meta, creatorTaxBps), and
launch(meta, opts) for the full option set.
Launch options
| Field | Type | What it does |
|---|---|---|
| creatorTaxBps | uint16 | A tax you charge on every trade, on top of the 1% protocol fee, paid entirely to you.
Capped at 10% by params().maxCreatorTaxBps. Frozen at launch.
A 5% tax costs a round-tripping buyer 10%, so it suppresses volume — price it deliberately. |
| creatorFeeRecipient | address | Where your earnings go. Zero means the launching wallet. Transferable afterwards by whoever currently holds it, one way — which is what makes launching from a hot wallet safe. |
| devBuyQuote | uint256 | USDC (6 dp) spent buying your own launch in the same transaction, at the same curve price as anyone else. Exempt from the snipe tax, because it settles before the market exists. |
| devBuyMinTokensOut | uint256 | Slippage floor on that buy. Zero disables the check. |
| buyback | bool | Enrol the coin in buyback-and-burn in this same transaction, so every creator fee it ever earns buys the coin back and burns it from the first trade. Enrolling later takes two more transactions and leaves a window where fees went to the wallet instead. |
| snipeTaxExemptions | address[] | Wallets that skip the snipe tax. Up to 100. Declared at launch only — there is deliberately no way to add one later. See the disclosure note below. |
The snipe tax
For the first 4 seconds after a curve opens, buys pay a tax on top of the normal fee. Selling is never taxed, and the creator's launch buy is exempt because it settles before the market exists for anyone else.
The schedule is startBps >> ((elapsed * 14) / window) with
elapsed in whole seconds. Because block timestamps have one-second resolution, the
rate is a step function, not a smooth curve — it changes once per second and
nothing in between:
| Seconds after launch | Tax on the buy |
|---|---|
| 0 | 99.00% |
| 1 | 12.37% |
| 2 | 0.77% |
| 3 | 0.09% |
| 4 and later | 0% |
Read the live rate for a specific wallet with
curve.currentSnipeTaxBps(address), which returns 0 for an exempt wallet
and for everyone once the window closes. Tax plus fee together are capped so a trade can never be
charged more than 100%.
A creator may bring up to 100 wallets into the untaxed window. The tax then protects buyers
from bots outside that group, not from the group itself. This is a deliberate product
choice, and it is public: exemptions are readable at
curve.snipeTaxExempt(address) and each one emits
SnipeTaxExempted(address) in the launch transaction.
If you are building a front end or a discover feed on top of biddin, count those events and show the number. A feed that omits it is not neutral; it is hiding the thing that matters most about a new launch.
Subtract one when you count. Every launch emits one
SnipeTaxExempted for the factory itself, because the factory is what executes the
creator's bundled buy and would otherwise pay its own 99% tax. A launch declaring no exemptions at
all still emits exactly one event. Verified on a real launch: two events for one declared
address.
Metadata
Metadata is stored on-chain as plain strings, so there is no upload API you are
required to use and no gateway that can lose your image. Point imageUri at anything a
browser can load — an ipfs:// URI, an https:// URL, or a
data: URI for something small.
Our own front end uploads the picture to our storage and writes that https:// URL
into imageUri. That is a convenience, not a recommendation, and it is worth knowing what
it costs: the bytes live with us, so such an image lasts as long as our hosting does, and whoever
controls the host can change what sits behind the URL after people have already bought. Artwork that
cannot be swapped and does not depend on us means pinning it yourself and passing the
ipfs:// URI. The contract is indifferent — it stores whichever string you give
it.
Trading on the curve
Before graduation a token trades against its own bonding curve, not a pool. Quote first: the curve refunds any overshoot past the graduation threshold and charges the fee on the filled amount only, so a large buy does not revert at the line — it fills what fits.
import { parseAbi } from 'viem';
import { pub, wallet, account } from './client.js';
const curveAbi = parseAbi([
'function previewBuyFor(uint256 quoteIn, address recipient) view returns (uint256 tokensOut, uint256 quoteSpent, uint256 refund, uint256 fee, uint256 tax, uint256 snipeTax)',
'function previewSell(uint256 tokensIn) view returns (uint256 quoteOut, uint256 fee, uint256 tax)',
'function buyWithNative(uint256 minTokensOut) payable returns (uint256 tokensOut, uint256 quoteSpent)',
'function buy(uint256 quoteIn, uint256 minTokensOut) returns (uint256 tokensOut, uint256 quoteSpent)',
'function sell(uint256 tokensIn, uint256 minQuoteOut) returns (uint256 quoteOut)',
'function currentSnipeTaxBps(address recipient) view returns (uint256)',
'function readyToGraduate() view returns (bool)',
]);
const CURVE = '0x…';
const NATIVE_SCALE = 10n ** 12n;
const amountIn = 10n * 10n ** 6n; // 10 USDC, 6 decimals
// Never buy inside the snipe window unless you are exempt: at t=0 the tax is 99%.
const tax = await pub.readContract({
address: CURVE, abi: curveAbi, functionName: 'currentSnipeTaxBps', args: [account.address],
});
if (tax > 0n) throw new Error(`snipe tax still ${Number(tax) / 100}% — wait`);
// previewBuyFor prices the snipe tax for THIS buyer; previewBuy uses msg.sender, which is
// the zero address on an eth_call and therefore never exempt. Always pass the real recipient.
const [tokensOut, , refund] = await pub.readContract({
address: CURVE, abi: curveAbi, functionName: 'previewBuyFor', args: [amountIn, account.address],
});
if (refund > 0n) console.log('partial fill — curve is at the graduation line');
const minOut = (tokensOut * 9750n) / 10000n; // 2.5% slippage
const hash = await wallet.writeContract({
address: CURVE, abi: curveAbi, functionName: 'buyWithNative',
args: [minOut], value: amountIn * NATIVE_SCALE, // no approval needed
});
await pub.waitForTransactionReceipt({ hash });
Selling needs one ERC-20 approval of the curve, then
sell(tokensIn, minQuoteOut). There is also
buyWithPermit if you would rather sign an EIP-2612 permit than send a separate
approval transaction.
After graduation
At readyToGraduate() the curve closes permanently and two permissionless steps
run: drainCurve(token) moves the proceeds into the factory, then
seedPoolV3(token) opens the Uniswap V3 pool, seeds it, burns the surplus and hands the
position to the locker. They are two calls rather than one so that a pool creation that fails cannot
strand the drain. Anyone may call either; our keeper does it within a block or two. See
Graduation for what the burn is and why it exists.
From that point the token is an ordinary Uniswap V3 pair against Arc USDC. Trade it through any V3 router — nothing routes through us.
Why a locked V3 position rather than a burned LP token. Burning the LP is the usual way to prove liquidity cannot be pulled, and it works — but a burned position stops paying anyone. Ours is held by a contract with no withdrawal function, which is the same guarantee, except the position keeps collecting swap fees. Those fees are what let the creator keep earning after graduation rather than only on the curve. The token surplus is still burned, because a full-range V3 position holds the same reserve ratio as a V2 pair and the surplus has nowhere else to go.
Reading state
Two calls cover most integrations: factory.params() for the economics every new
launch inherits, and factory.launchOf(token) for one coin's identity. Per-coin
economics live on the curve as immutables.
import { parseAbi } from 'viem';
import { pub } from './client.js';
const FACTORY = '0xA5b69A713bf53C7f6f2E230428CebA62842fc9e2';
const factoryAbi = parseAbi([
'function params() view returns (uint256 saleSupply, uint256 virtualQuote, uint256 graduationThreshold, uint256 launchFee, uint16 tradeFeeBps, uint16 creatorFeeShareBps, uint16 maxCreatorTaxBps)',
'function launchOf(address token) view returns (address token_, address curve, address creator, uint64 createdAt, uint16 creatorTaxBps, bool exists)',
'function tokenCount() view returns (uint256)',
'function allTokens(uint256 i) view returns (address)',
'function snipeTaxStartBps() view returns (uint16)',
'function snipeTaxSeconds() view returns (uint32)',
]);
const curveAbi = parseAbi([
'function quoteReserve() view returns (uint256)',
'function graduationThreshold() view returns (uint256)',
'function tradeFeeBps() view returns (uint16)',
'function creatorFeeShareBps() view returns (uint16)',
'function creatorTaxBps() view returns (uint16)',
'function totalChargeBps() view returns (uint256)',
'function graduated() view returns (bool)',
'function creatorFeeRecipient() view returns (address)',
'function snipeTaxExempt(address) view returns (bool)',
]);
const TOKEN = '0x…';
const { curve, creator, creatorTaxBps } = await pub.readContract({
address: FACTORY, abi: factoryAbi, functionName: 'launchOf', args: [TOKEN],
}).then(([token_, curve, creator, createdAt, creatorTaxBps, exists]) =>
({ curve, creator, createdAt, creatorTaxBps, exists }));
const [raised, target, total, graduated] = await Promise.all([
pub.readContract({ address: curve, abi: curveAbi, functionName: 'quoteReserve' }),
pub.readContract({ address: curve, abi: curveAbi, functionName: 'graduationThreshold' }),
pub.readContract({ address: curve, abi: curveAbi, functionName: 'totalChargeBps' }),
pub.readContract({ address: curve, abi: curveAbi, functionName: 'graduated' }),
]);
console.log('progress', (Number(raised) / Number(target) * 100).toFixed(1) + '%');
console.log('all-in charge per trade', Number(total) / 100 + '%'); // protocol fee + creator tax
console.log('graduated', graduated, 'creator tax', creatorTaxBps / 100 + '%');
tradeFeeBps is the protocol's 1%. A creator may add up to 10% on top.
totalChargeBps() is the sum — the number a trader actually pays. Quoting with
the protocol fee alone will overstate the output on every taxed coin.
Events
Six events cover the lifecycle. The two curve events are emitted by each coin's own curve, so filter them by topic0 alone (or by the curve address if you already know it); the factory events are worth filtering by the factory address as well.
| Event | Emitted by | topic0 |
|---|---|---|
| Launched(address,address,address,string,string,uint256,uint16) | Factory | 0xd3908bba65accd90a4c5d3d668306b13dfb4d28f31ad27405142cbc149364f88 |
| CreatorBought(address,address,uint256,uint256) | Factory | 0x5772767e7b2a80bb7caf31ec477440a12dec4d0c71f0388af6dd6ec5234a0f38 |
| PoolSeeded(address,address,uint256,uint256,uint256) | Factory | 0x5d70d05a0cfd1a00cf62cd97af9b9ca9787a8d02f6acb398437ab82ee88e527e |
| Bought(address,uint256,uint256,uint256,uint256,uint256,uint256) | Curve | 0x15053609d51f61ee8a7b1c2250290b901d8ef6cb2afec5d8987f3d8cafa06c4f |
| Sold(address,uint256,uint256,uint256,uint256,uint256) | Curve | 0x917d0fe1b6c3328f12a0177d25bf1b7d9e963116addad0bfc06b0cdcb6427603 |
| SnipeTaxExempted(address) | Curve | 0xe4b7e48fbd47c2f602bacadee76ad33b16542ddb4997cfc0de04c311adcfa8c7 |
Launched carries the token, curve and creator as indexed topics, so you can build
a complete coin list from that one filter without a single extra call. CreatorBought
appears in the same transaction when the creator bundled a dev buy — its absence is itself
information worth surfacing.
Fees
Every trade pays 1.00% on the USDC leg, in both directions, on the curve and in the pool after graduation. It splits 70% to the creator, 30% to the protocol. A creator tax, if the creator set one, is charged on top and goes entirely to the creator.
| Stage | Protocol fee | Creator | Protocol | Creator tax |
|---|---|---|---|---|
| On the curve | 1.00% | 0.70% | 0.30% | 0–10%, set at launch |
| After graduation | 1.00% | 0.70% | 0.30% | — |
Creator earnings accrue in USDC to an escrow and are pulled with
claim(token, recipient). Anyone may trigger a claim; the money only ever goes to the
recipient, never to the caller, so a relayer or a front end can pay a creator out without ever
holding their funds.
Launching costs a flat 1.00 USDC. There is no listing fee, no revenue share agreement and no allowlist — the contracts do not know who you are.
Addresses
Arc mainnet, chain 5042. These are final — safe to compile in.
| Contract | Address |
|---|---|
| Launch factory | 0xA5b69A713bf53C7f6f2E230428CebA62842fc9e2 |
| Fee escrow | 0xcC7F665d28247155a48d359A281761A397E75DF7 |
| V3 liquidity locker | 0x8C6B6A4Cc7E8B6D3715BcB0be0fD677bF8cb3Ead |
| Buyback factory | 0x203343182aD32A66d53355a64Bc71baaC6DC5E40 |
| Quote asset (Arc USDC) | 0x3600000000000000000000000000000000000000 |
| Owner (2-of-3 Safe) | 0xA4F1883D025E12e760124A9701704133A6FB6D1e |
Check you are talking to the real one
The factory is not a proxy — deliberately, so that nobody can swap the logic under a coin that already exists. Nothing about the address above can change, and it holds no admin key over your coin once launched.
Four reads confirm it, and they cost nothing:
import { parseAbi } from 'viem';
import { pub } from './client.js';
const FACTORY = '0xA5b69A713bf53C7f6f2E230428CebA62842fc9e2';
const abi = parseAbi([
'function owner() view returns (address)',
'function pendingOwner() view returns (address)',
'function quote() view returns (address)',
'function feeEscrow() view returns (address)',
]);
const read = (fn) => pub.readContract({ address: FACTORY, abi, functionName: fn });
console.assert((await read('owner')).toLowerCase()
=== '0xa4f1883d025e12e760124a9701704133a6fb6d1e'); // the 2-of-3 Safe
console.assert((await read('pendingOwner')) === '0x0000000000000000000000000000000000000000');
console.assert((await read('quote')).toLowerCase()
=== '0x3600000000000000000000000000000000000000'); // Arc USDC, not a lookalike
console.assert((await read('feeEscrow')).toLowerCase()
=== '0xcc7f665d28247155a48d359a281761a397e75df7');
A zero pendingOwner matters: it means the ownership handover to the
Safe completed, rather than sitting half-done with a deploy key still able to claim it back.
Going the other way, any token's curve exposes factory(). A coin whose
factory() is not the address above was not launched here, whatever its name and image
claim.
What cannot change
The Safe that owns the factory can change what future launches inherit:
setParams, the snipe-tax knobs, the protocol fee recipient, the pool venue. It has no
function that can reach a coin that already exists.
That is not a policy, it is the storage layout. Every economic term is declared
immutable on the curve at construction:
| Frozen at launch | Meaning |
|---|---|
| tradeFeeBps | The 1% protocol fee your coin pays, forever |
| creatorFeeShareBps | Your 70% share of it |
| creatorTaxBps | The tax you chose, if any |
| snipeTaxStartBps / snipeTaxSeconds | The anti-snipe schedule |
| graduationThreshold / virtualQuote | The curve shape and the finish line |
| protocolFeeRecipient | Where our 30% goes, for this coin |
| saleSupply / quote / token | Supply and the asset it trades against |
Verify it yourself: read any of these off a live curve, then read the same field off the factory. If the Safe ever changes the factory's value, the curve's will not move.
Two more properties worth checking rather than trusting:
- The factory has no sweep, no withdraw and no owner-controlled token transfer.
The single exception is
rescueStuckGraduation, which is owner-only, requires the graduation to have been stuck for 7 days, and reverts outright if the normal seeding path would still work. - The graduated liquidity position is held by a locker contract with no withdrawal function. Not a pledge — there is no code path.
Known traps on Arc
These are the things that have actually cost us time. None of them are biddin-specific; all of them will bite any integrator on this chain.
USDC has two decimal counts
The native balance — what you send as msg.value and what pays gas — is
18 decimals. The ERC-20 at 0x3600…0000 is the same money at
6 decimals. Every amount in our structs and quotes is the 6-decimal one; only
msg.value is 18. Scale by 1e12 when you cross. A bot that reuses one
number on both sides is wrong by six orders of magnitude, and the failure is a silent
under-payment rather than a revert.
eth_call with a gas field but no from returns 503
Arc's RPC answers 503, not a JSON-RPC error, when a call carries gas
without from. It reads exactly like an outage. Send both or neither.
Public nodes drop eth_call under load
We have measured the free public endpoint refusing every eth_call for minutes at a
time while eth_blockNumber answered instantly. If your health check only pings
eth_blockNumber it will report green through an outage that breaks all your quoting.
Use a paid endpoint for anything that trades.
Foundry cannot simulate USDC transfers here
Because gas is the same asset being moved, forge script's gas estimation fails on
transfers and the run reverts while still printing SUCCESS. Pass --gas-limit
explicitly, and never take Foundry's success line as confirmation — read the receipt.
getLogs caps out around 10,000 blocks
A single eth_getLogs spanning more than about 9,960 blocks is
refused — measured by bisection against Arc mainnet, not taken from a doc. Arc produces roughly
two blocks a second, so that window is only about 80 minutes of history. Backfilling a day means
about 17 calls, and a scanner written against a chain with a 10,000-block convention will
work while a scanner that asks for a month in one call gets nothing but an error.
Page it in chunks under 9,000 to leave headroom, and treat a failure as "range too wide" before you treat it as "no logs".
Do not pre-fund the pool router
Our router sweeps its entire balance to the caller at the end of every swap, as periphery routers do. Anything you send it ahead of time belongs to whoever calls next.
For AI agents
Everything on this page is also served as plain files at fixed paths, so an agent can read the reference without rendering HTML or running any JavaScript.
| Path | What it is |
|---|---|
| /llms.txt | A short summary of the protocol plus every contract address, in the llms.txt format. Start here. |
| /docs.md | This entire page as Markdown — the complete integration reference. |
| /skills/launch-token-on-biddin/SKILL.md | An agent skill: step-by-step instructions for launching a token end to end, including the confirmation the agent must get from its user before spending money. |
Before you spend anything A launch costs real USDC and an optional dev buy costs more. The skill above requires the agent to state the exact total and get an explicit yes from its user first. Please keep that step.
Risk
Anyone can launch anything here. The name, symbol, image and description are claims made by whoever paid the 1 USDC, and no contract verifies them.
Locked liquidity means the launch position cannot be pulled. It does not mean a token is a good idea and it will not stop a price going to nearly zero.
The snipe tax raises the cost of instant sniping. It does not make early buying safe, and a creator may have exempted up to 100 wallets from it — check before you buy.
What we publish is data, not advice.