Documentation
Quickstart
Launch a token with an opening buy, in one transaction, with viem. Every address below is Arc testnet; see Addresses.
1 · Check you are allowed to launch#
Launching is gated and disabled by default on a fresh deployment. Always check first:
const allowed = await client.readContract({
address: FACTORY, abi: factoryAbi, functionName: "canLaunch", args: [account],
});
if (!allowed) throw new Error("launching is not open for this address");2 · Pin the economics#
expectedEconomics freezes the terms your user was shown. If the owner re-pegs the curve or
changes the launch fee between your quote and your signature, the launch reverts instead of
landing on terms nobody agreed to.
const expectedEconomics = await client.readContract({
address: FACTORY, abi: factoryAbi,
functionName: "previewLaunchEconomics", args: [0n, USDC],
});Fetch it in the same flow as the submit. Do not cache it. Passing bytes32(0) waives the
check, which means accepting whatever terms are live when the transaction lands.
3 · Approve the router#
The atomic path pulls the fee and the opening buy, so one approval covers both — and the spender is the router, not the factory.
const fee = await client.readContract({ address: FACTORY, abi: factoryAbi, functionName: "launchFee" });
const openingBuy = 1_000_000n; // 1 USDC — 6 decimals
await walletClient.writeContract({
address: USDC, abi: erc20Abi, functionName: "approve",
args: [LAUNCH_AND_BUY, fee + openingBuy],
});4 · Launch#
const { result } = await client.simulateContract({
address: LAUNCH_AND_BUY, abi: launchAndBuyAbi, functionName: "launchAndBuy",
args: [
{
name: "My Token", symbol: "MINE", logo: "", description: "",
socials: { twitter: "", telegram: "", discord: "", website: "", farcaster: "" },
creatorFeeRecipient: account, // must NOT be zero on this path
creatorTaxBps: 0,
expectedEconomics,
salt: crypto.getRandomValues(new Uint8Array(32)),
},
0n, // launchConfigId
USDC, // pairToken
openingBuy, // quoteIn — must be non-zero here
0n, // minTokensOut
account, // recipient of the bought tokens
],
account,
});
const [token, curve, tokensOut] = result;Then send it with an explicit gas limit — see the warning below.
5 · Launch without an opening buy#
launchAndBuy reverts on a zero quoteIn — it exists to buy and refuses to act as a plain
deployer. Use the factory directly, and note the approval target moves with it:
await walletClient.writeContract({
address: USDC, abi: erc20Abi, functionName: "approve",
args: [FACTORY, fee], // the FACTORY, not the router
});
const { result } = await client.simulateContract({
address: FACTORY, abi: factoryAbi, functionName: "launchToken",
args: [params, 0n, USDC], account,
});A token launched this way starts with the creator holding none of its supply.
6 · Buy on the curve#
The curve has no fixed address — read it from the launch record.
const launch = await client.readContract({
address: FACTORY, abi: factoryAbi, functionName: "getLaunchedToken", args: [token],
});
await walletClient.writeContract({
address: USDC, abi: erc20Abi, functionName: "approve",
args: [launch.curve, amountIn], // approve the CURVE
});
await walletClient.writeContract({
address: launch.curve, abi: curveAbi, functionName: "buy",
args: [amountIn, minTokensOut, account],
});