> For the complete documentation index, see [llms.txt](https://docs.crystal.exchange/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.crystal.exchange/developer-resources/aggregator-defi-integration/launchpad-integration.md).

# Launchpad Integration

This page describes how applications should integrate with Crystal Launchpad.

For a high-level explanation of how the launchpad works, see the Launchpad Overview.

### Integration Model

Launchpad tokens have two states:

| State       | Trading source          | Recommended functions                            |
| ----------- | ----------------------- | ------------------------------------------------ |
| Ungraduated | Virtual bonding curve   | `quoteBuy`, `quoteSell`, `buy`, `sell`           |
| Graduated   | Crystal orderbook + AMM | Standard Crystal swaps/orders, or `buy` / `sell` |

A Crystal market is created when the token is created, but it is not routable through the normal pair router until graduation.

Before graduation:

```
getMarketByTokens(weth, token) = placeholder
```

After graduation:

```
getMarketByTokens(weth, token) = real market
```

Because the placeholder is nonzero, integrations should not use `market != address(0)` alone to determine whether the token has graduated.

### Detecting Launchpad State

#### `getVirtualReserves`

```solidity
function getVirtualReserves(address token)
    external
    view
    returns (
        uint256 virtualNativeReserve,
        uint256 virtualTokenReserve
    )
```

For an active launchpad token, both values are nonzero.

After graduation, the launchpad state is deleted and both values return zero.

This is the simplest way to distinguish the active bonding-curve state.

#### `launchpadTokenToMarket`

The public mapping exposes:

```
virtualNativeReserve
virtualTokenReserve
k
creator
market
```

The `market` field is the future Crystal market address, even before that market becomes routable.

After graduation, the mapping entry is cleared.

#### `wasLaunchpad`

```solidity
function wasLaunchpad(address market) external view returns (bool)
```

Returns true if a market originated from the launchpad.

#### `allTokens`

```solidity
function allTokens(uint256 index) external view returns (address)
```

Enumerates launchpad-created tokens.

### Creating a Token

```solidity
function createToken(
    string name,
    string symbol,
    string metadataCID,
    string description,
    string social1,
    string social2,
    string social3,
    string social4
) external payable returns (address token)
```

The `name` and `symbol` must be nonempty.

Creation:

* deploys a new `CrystalToken`;
* creates its future type-4 Crystal market;
* stores the token in `allTokens`;
* initializes the bonding curve;
* prepares the graduated AMM position; and
* emits `TokenCreated`.

If `msg.value > 0`, Crystal immediately performs an exact-input buy using that native amount.

### Buying

```solidity
function buy(
    bool isExactInput,
    address token,
    uint256 amountIn,
    uint256 amountOut
) external payable returns (
    uint256 inputAmount,
    uint256 outputAmount,
    bool isLaunchpadClosed
)
```

Before graduation, the trade executes against the virtual curve.

After graduation, the same function routes through the normal Crystal market.

#### Exact-input mode

```
isExactInput = true
```

Then:

```
amountIn  = exact native input
amountOut = minimum acceptable token output
```

`msg.value` must equal `amountIn`.

#### Exact-output mode

```
isExactInput = false
```

Then:

```
amountOut = exact token output requested
amountIn  = maximum acceptable native input
```

If `amountIn == 0`, the final maximum-input check is disabled.

The transaction must still provide enough native value for the trade.

#### Graduation during a buy

A single buy can reach graduation.

Crystal first executes the amount required to finish the bonding curve. It then activates the graduated market and can continue any remaining requested trade through the newly active market.

Applications should therefore treat graduation as something that can occur **inside a trade**, rather than as a separate state transition transaction.

### Selling

```solidity
function sell(
    bool isExactInput,
    address token,
    uint256 amountIn,
    uint256 amountOut
) external returns (
    uint256 inputAmount,
    uint256 outputAmount
)
```

Before graduation, the trade executes against the virtual curve.

After graduation, it routes through the normal Crystal market.

#### Exact-input mode

```
amountIn  = exact number of tokens to sell
amountOut = minimum native output
```

#### Exact-output mode

```
amountOut = exact native output requested
amountIn  = maximum token input
```

If `amountIn == 0`, the maximum-input check is disabled.

The user must approve Crystal to transfer the launchpad token.

### Quoting

#### `quoteBuy`

```solidity
function quoteBuy(
    bool isExactInput,
    address token,
    uint256 amountIn,
    uint256 amountOut
) external returns (
    uint256 inputAmount,
    uint256 outputAmount,
    bool graduated
)
```

Uses the same exact-input/exact-output semantics as `buy`.

The `graduated` return value is true when the quoted trade would graduate the token or when the quote uses the graduated market.

A quote that reaches graduation accounts for the launchpad portion and the immediate post-graduation market transition.

#### `quoteSell`

```solidity
function quoteSell(
    bool isExactInput,
    address token,
    uint256 amountIn,
    uint256 amountOut
) external returns (
    uint256 inputAmount,
    uint256 outputAmount
)
```

Uses the same semantics as `sell`.

Before graduation it quotes the bonding curve. After graduation it quotes the Crystal market.

#### Quote functions are read-like

`quoteBuy` and `quoteSell` do not persist reserve changes, but they are not declared Solidity `view`.

Integrations should call them with `eth_call` / simulation rather than sending a transaction.

### Curve State

An active launchpad stores:

```
virtualNativeReserve
virtualTokenReserve
k
```

where:

```
k = virtualNativeReserve * virtualTokenReserve
```

The initial values are:

```
virtualNativeReserve =
    launchpadInitialNativeSupply

virtualTokenReserve =
    INITIAL_CURVE_TOKEN_SUPPLY
```

Crystal uses integer rounding when updating reserves, so integrations should prefer `quoteBuy` and `quoteSell` over independently reproducing execution math.

### Supply Model

Launchpad tokens use 18 decimals.

Current constants are:

```
Total token supply:
1,000,000,000 tokens

Tokens moved through the curve before graduation:
800,000,000 tokens

Tokens reserved for the graduated AMM:
200,000,000 tokens
```

Crystal also adds virtual token reserves for pricing.

The active curve begins at approximately:

```
1,066,666,666.6667 virtual tokens
```

and graduates at approximately:

```
266,666,666.6667 virtual tokens
```

The difference is 800 million tokens.

The virtual amount is part of curve accounting and should not be interpreted as additional circulating supply.

### Graduation Condition

Graduation occurs when:

```
virtualNativeReserve >=
    ceil(k / GRADUATED_CURVE_TOKEN_SUPPLY)
```

Once this condition is reached Crystal:

* clears `launchpadTokenToMarket[token]`;
* sets `wasLaunchpad[market] = true`;
* replaces the placeholder pair mapping with the real market;
* applies graduated market parameters; and
* emits market initialization events.

Afterward, standard Crystal routing can use the pair.

### Graduated Market Parameters

Launchpad markets are created as type `4`, meaning the AMM fee is set at 1%, enabled by default, and the price ticks are base-10 with a fixed 5 digits of precision.

Their fixed core settings are:

| Parameter        |           Value |
| ---------------- | --------------: |
| Quote asset      |            WETH |
| Base asset       | Launchpad token |
| `marketType`     |             `4` |
| `scaleFactor`    |             `9` |
| `tickSize`       |             `1` |
| `maxPrice`       |          `1e15` |
| AMM enabled      |          `true` |
| AMM curve factor |  `9900 / 10000` |

Graduated fee and order-size parameters come from `launchpadParams`:

```
graduatedMinSize
graduatedTakerFee
graduatedMakerRebate
graduatedCreatorFeeSplit
```

### Launchpad Fees

`launchpadFee` is a multiplier scaled by `100000`.

For example:

```
launchpadFee = 99700
```

means:

```
99.7% remains after fee
0.3% is collected as fee
```

For buys:

```
amountAfterFee =
    floor(amountIn * launchpadFee / 100000)
```

For sells, the same factor is applied to native output.

Collected launchpad fees are split between:

```
token creator
protocol governance
```

according to:

```
launchpadCreatorFeeSplit
```

The resulting balances accrue in `claimableRewards`.

### Graduated AMM Liquidity

Crystal prepares the initial graduated AMM position when the token is created.

The base side is:

```
200,000,000 launchpad tokens
```

The quote side is derived from the curve's launch-to-graduation reserve relationship.

The LP tokens for this initial position are transferred to:

```
address(0)
```

so the initial launchpad-created LP position cannot be withdrawn by an ordinary LP holder.

### Events

#### Before graduation

A bonding-curve trade emits:

```solidity
event LaunchpadTrade(
    address indexed token,
    address indexed user,
    bool isBuy,
    uint256 amountIn,
    uint256 amountOut,
    uint256 virtualNativeReserve,
    uint256 virtualTokenReserve
);
```

The reserve fields are the virtual reserves **after** the bonding-curve portion of the trade.

#### Token creation

```solidity
event TokenCreated(
    address indexed token,
    address indexed creator,
    string name,
    string symbol,
    string metadataCID,
    string description,
    string social1,
    string social2,
    string social3,
    string social4
);
```

#### Graduation

Graduation emits:

```
MarketCreated
Sync
Mint
```

#### After graduation

Market execution uses normal Crystal events such as:

```
Trade
Fill
OrdersUpdated
Sync
```

A single transaction that crosses graduation can contain both launchpad and normal market events.

### Recommended Integration Flow

For a token page:

```
1. Query getVirtualReserves(token)
2. If reserves are nonzero:
      token is on launchpad
      use quoteBuy / quoteSell
      use buy / sell
3. If reserves are zero:
      query getMarketByTokens(weth, token)
      token is graduated
      normal Crystal routing is available
```

For trades that may graduate:

```
quoteBuy(...)
    ↓
display input/output
    ↓
buy(...)
    ↓
watch for LaunchpadTrade
    ↓
if graduation occurs:
    also process MarketCreated / Sync / Mint
    and any normal Trade / Fill events
```

### Important Integration Notes

* Do not treat a nonzero `getMarketByTokens` result as proof of graduation because the launchpad uses a nonzero placeholder before graduation.
* Prefer `quoteBuy` and `quoteSell` over reproducing the bonding-curve math locally.
* `buy` can cross graduation and continue into the graduated market in one transaction.
* `buy` and `sell` continue working after graduation.
* Before graduation, listen to `LaunchpadTrade`.
* After graduation, use the normal Crystal market events.
* A launchpad fee such as `99700` means a `0.3%` fee, not a `99.7%` fee.
* Launchpad tokens use 18 decimals.
* The 200 million-token graduated AMM position is separate from the 800 million-token launchpad distribution.
