> For the complete documentation index, see [llms.txt](https://degen-games-2.gitbook.io/degen-games-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://degen-games-2.gitbook.io/degen-games-docs/developers/launching.md).

# Launching a Coin

Launch a coin programmatically, with pinned economics, team exemptions and an atomic dev buy.

Launching is one call to the launch factory. You pick a **launch config** (supply, curve fee, virtual reserve, graduation threshold, pool settings) and a **raise asset**, and you send the launch fee as value.

Examples use [viem](https://viem.sh). `client` is a public client and `wallet` is a wallet client on the target chain.

## 1. Check the gate

Launching can be restricted, for example to an allowlist during a rollout. One call tells you whether an address can launch:

```js
import { parseAbi } from "viem";

const factory = "0xa8788400ECe2342F17Faf659E2793a06bc4ad140";

const gateAbi = parseAbi([
  "function canLaunch(address launcher) view returns (bool)",
]);

const allowed = await client.readContract({
  address: factory,
  abi: gateAbi,
  functionName: "canLaunch",
  args: [creator],
});
```

## 2. Pick a launch config

Configs live in an append-only list, so an id always means the same config. The owner can edit or disable configs. A disabled one reverts with `LaunchConfigDisabled`, so read the list at launch time instead of caching ids forever.

```js
const configAbi = parseAbi([
  "struct LaunchConfig { uint256 supply; uint256 curveFeeBps; uint256 phantomQuote; uint256 graduationThreshold; uint24 poolFee; int24 tickSpacing; bool enabled; }",
  "function launchConfigCount() view returns (uint256)",
  "function getLaunchConfig(uint256 id) view returns (LaunchConfig)",
]);

const count = await client.readContract({
  address: factory, abi: configAbi, functionName: "launchConfigCount",
});

const configs = await Promise.all(
  Array.from({ length: Number(count) }, (_, id) =>
    client.readContract({
      address: factory, abi: configAbi, functionName: "getLaunchConfig", args: [BigInt(id)],
    }),
  ),
);

const open = configs
  .map((config, id) => ({ id: BigInt(id), ...config }))
  .filter((c) => c.enabled);
```

## 3. Pick a raise asset

Use the **zero address** for a native (ETH) launch, or an approved ERC-20. Only offer assets that pass both checks, because anything else reverts with `PairTokenNotApproved`.

```js
const pairAbi = parseAbi([
  "function approvedPairTokens(address pairToken) view returns (bool)",
  "function pairTokenEconomics(address pairToken) view returns (uint256 phantomQuote, uint256 graduationThreshold, uint8 decimals)",
]);

async function isUsable(asset) {
  const [approved, [phantomQuote, threshold]] = await Promise.all([
    client.readContract({ address: factory, abi: pairAbi, functionName: "approvedPairTokens", args: [asset] }),
    client.readContract({ address: factory, abi: pairAbi, functionName: "pairTokenEconomics", args: [asset] }),
  ]);
  return approved && phantomQuote > 0n && threshold > 0n;
}
```

Economics for ERC-20 assets are stored in the asset's own decimals. USDG has 6, for example. Always format amounts with the asset's `decimals`, never assume 18.

## 4. Launch with pinned economics

Pass `expectedEconomics` from `previewLaunchEconomics` so the launch can't settle on terms you didn't read. If the config changes between your read and your transaction, the launch reverts with `LaunchEconomicsMismatch` instead.

```js
import { toHex, zeroAddress } from "viem";

const launchAbi = parseAbi([
  "struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }",
  "struct TokenParams { string name; string symbol; string logo; string description; Socials socials; address creatorFeeRecipient; uint16 creatorTaxBps; bool buybackEnabled; bytes32 expectedEconomics; bytes32 salt; }",
  "function launchToken(TokenParams params, uint256 launchConfigId, address pairToken) payable returns (address token, address curve)",
  "function launchToken(TokenParams params, uint256 launchConfigId, address pairToken, address[] snipeTaxExemptions) payable returns (address token, address curve)",
  "function previewLaunchEconomics(uint256 launchConfigId, address pairToken) view returns (bytes32)",
  "function launchFee() view returns (uint256)",
]);

const launchConfigId = 0n;
const pairToken = zeroAddress; // native ETH

const [expectedEconomics, launchFee] = await Promise.all([
  client.readContract({ address: factory, abi: launchAbi, functionName: "previewLaunchEconomics", args: [launchConfigId, pairToken] }),
  client.readContract({ address: factory, abi: launchAbi, functionName: "launchFee" }),
]);

const params = {
  name: "Degen Anniversary",
  symbol: "DEGEN",
  logo: "ipfs://<cid>",
  description: "Insert coin.",
  socials: { twitter: "", telegram: "", discord: "", website: "", farcaster: "" },
  creatorFeeRecipient: zeroAddress,   // zero = the caller
  creatorTaxBps: 0,                   // 0–1000 (max 10%)
  buybackEnabled: false,
  expectedEconomics,
  salt: toHex(crypto.getRandomValues(new Uint8Array(32))),
};

const hash = await wallet.writeContract({
  address: factory,
  abi: launchAbi,
  functionName: "launchToken",
  args: [params, launchConfigId, pairToken, [teamWalletA, teamWalletB]],
  value: launchFee,
});
```

**Notes**

* `creatorFeeRecipient = 0x0` defaults to the caller. `creatorTaxBps` above `maxCreatorTaxBps()` reverts with `CreatorTaxTooHigh`.
* The **4-argument** overload takes extra snipe-tax exemptions (team wallets). The launcher and the fee recipient are exempted automatically. Past the list limit it reverts with `ExemptionListTooLong`. The 3-argument overload launches with no extra exemptions.
* The launch fee must be sent exactly as value, or it reverts with `LaunchFeeNotPaid`.

### Deterministic addresses

The **salt** feeds a CREATE2 deployment of the curve and token. It's namespaced to the initiating wallet, so nobody can take your address by submitting the same salt first. Use a fresh random salt for a normal launch, or mine one offline if you want a vanity address. Reusing a salt with identical terms reverts.

## 5. Launch and buy in one transaction

A launch followed by a separate buy leaves a gap that anyone watching can trade into. The **launch & buy router** does both in a single call, so the creator's first buy can't be front-run. The buy's recipient is exempted from the snipe tax automatically.

```js
import { parseEther } from "viem";

// Resolve the router from the factory instead of hard-coding it.
const router = await client.readContract({
  address: factory,
  abi: parseAbi(["function launchForwarder() view returns (address)"]),
  functionName: "launchForwarder",
});

const routerAbi = parseAbi([
  "struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }",
  "struct TokenParams { string name; string symbol; string logo; string description; Socials socials; address creatorFeeRecipient; uint16 creatorTaxBps; bool buybackEnabled; bytes32 expectedEconomics; bytes32 salt; }",
  "function launchAndBuy(TokenParams params, uint256 launchConfigId, address pairToken, uint256 quoteIn, uint256 minTokensOut, address recipient, address[] snipeTaxExemptions) payable returns (address token, address curve, uint256 tokensOut)",
]);

const quoteIn = parseEther("0.5");

await wallet.writeContract({
  address: router,
  abi: routerAbi,
  functionName: "launchAndBuy",
  args: [
    { ...params, creatorFeeRecipient: creator }, // must be explicit here, not zero
    launchConfigId,
    pairToken,
    quoteIn,
    minTokensOut,
    recipient,
    [], // extra exemptions; the recipient is added for you
  ],
  // Native launch: fee + buy travel as value.
  // ERC-20 raise: send only the fee, and approve the router for quoteIn first.
  value: pairToken === zeroAddress ? launchFee + quoteIn : launchFee,
});
```

If `quoteIn` is larger than the whole curve, the buy fills the curve, the rest is refunded, and the coin graduates inside the launch transaction.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://degen-games-2.gitbook.io/degen-games-docs/developers/launching.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
