> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moralis.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Token Bonding Status (Solana Launchpads)

> Sync every pump.fun / Raydium LaunchLab launchpad event, created, traded, migrated, into your own database, and serve a launchpad's new / bonding / graduated token lists plus any token's bonding-curve status.

### Question it answers

> "For a Solana launchpad like **pump.fun**: which tokens just launched, which are still climbing the bonding curve, and which have graduated to a DEX, and what's a given token's bonding-curve status?"

Lands one row per **launchpad event** (`created` / `traded` / `migrated`) from the decoded `launchpadEvents` feed, and derives a per-token latest-status projection. The four deprecated pump.fun surfaces, new, bonding, graduated, and per-token status, are all reads over this one template.

### What you get

The template reads the master-block `launchpadEvents` array and lands two surfaces:

* **The launchpad event log**, keyed by exchange, one row per `created` / `traded` / `migrated` event.
* **A per-token status projection**, keyed by token, latest bonding progress, graduated flag, and graduation time.

| Column                                             | Description                                                                                      |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `token_address`                                    | The launchpad token (SPL mint)                                                                   |
| `exchange_address`                                 | The launchpad program (the `:exchange` path param, e.g. pump.fun `6EF8…F6P`)                     |
| `launchpad_platform`                               | Friendly name, `pumpfun`, `raydium_launchlab`                                                    |
| `event_type`                                       | `created` · `traded` · `migrated` (**migrated = graduated**)                                     |
| `progress_percentage`                              | Bonding-curve progress 0–100 (sparse, set on trading activity)                                   |
| `pool_address`                                     | The DEX pool a token migrated into, populated on the `migrated` event (take `max(pool_address)`) |
| `token_name`, `token_symbol`, `token_uri`          | Emitted on the `created` event only                                                              |
| `trade_direction`, `token_amount`, `native_amount` | On `traded` events, native price = `native_amount / token_amount`                                |
| `block_number`, `log_index`, `event_ts`, `tx_hash` | On-chain ordering + provenance                                                                   |

### Source

The transform reads one per-block array, `launchpadEvents`, one row per event. `event_type` distinguishes `created` (a new token, carries name/symbol/uri), `traded` (a bonding-curve fill, carries `progress_percentage` and trade amounts), and `migrated` (graduation to a DEX pool, carries `pool_address`). On the Solana feed today the price field (`current_price`) is **not populated**, see [Fidelity gaps](#fidelity-gaps). The `exchange_address` (launchpad program) is shared by every token on a platform.

### Destination

| Destination                  | Tables                                                                         | Access                                                                                                        |
| ---------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| **ClickHouse** (first-class) | `fact_launchpad_events` (by exchange) + `fact_token_bonding_status` (by token) | prefix scan on `(chain_id, exchange_address, block_number)` for the event log; per-token aggregate for status |
| **Postgres**                 | `launchpad_events` + `token_bonding_status` (materialized view)                | index on `(exchange_address, block_number)`; unique on `token_address`                                        |
| **MySQL**                    | `launchpad_events` + `token_bonding_status` (trigger-maintained)               | same shape                                                                                                    |

ClickHouse uses the collapsing log-table pattern so chain reorganizations self-correct. `fact_launchpad_events` is ordered for the by-exchange event log (bloom skip index on `token_address` for the by-token log); `fact_token_bonding_status` is keyed by token for the latest-state read.

### Full schema

<Accordion title="ClickHouse, fact_launchpad_events">
  ```sql theme={null}
  CREATE TABLE recipe_token_bonding_status.fact_launchpad_events
  (
      vendor_event_id       String,
      ingested_at           DateTime64(3),
      chain_id              UInt32,
      block_hash            String,
      block_number          UInt64,
      event_ts              DateTime64(3),
      token_address         String,
      launchpad_platform    LowCardinality(String),   -- pumpfun | raydium_launchlab | …
      event_type            LowCardinality(String),   -- created | traded | migrated
      exchange_address      String,
      initiated_by          String,
      token_name            String,
      token_symbol          String,
      token_uri             String,
      token_amount          String,
      native_amount         String,
      trade_direction       LowCardinality(String),   -- buy | sell | ''
      bonding_curve_address String,
      pool_address          String,                    -- DEX pool (migrated events)
      current_price         String,
      progress_percentage   Nullable(Float64),         -- 0-100, sparse
      metadata              String,
      tx_hash               String,
      log_index             Nullable(UInt32),
      transaction_index     Nullable(Int32),
      sign                  Int8,
      INDEX bf_token token_address TYPE bloom_filter(0.01) GRANULARITY 4
  )
  ENGINE = ReplicatedCollapsingMergeTree(
      '/clickhouse/tables/{database}/fact_launchpad_events', '{replica}', sign)
  PARTITION BY (chain_id, toYYYYMM(event_ts))
  ORDER BY (chain_id, exchange_address, block_number, vendor_event_id);
  ```
</Accordion>

<Accordion title="ClickHouse, fact_token_bonding_status (per-token)">
  ```sql theme={null}
  CREATE TABLE recipe_token_bonding_status.fact_token_bonding_status
  (
      vendor_event_id     String,
      ingested_at         DateTime64(3),
      chain_id            UInt32,
      block_number        UInt64,
      event_ts            DateTime64(3),
      token_address       String,
      launchpad_platform  LowCardinality(String),
      exchange_address    String,
      event_type          LowCardinality(String),
      token_name          String,
      token_symbol        String,
      progress_percentage Nullable(Float64),
      current_price       String,
      log_index           Nullable(UInt32),
      sign                Int8
  )
  ENGINE = ReplicatedCollapsingMergeTree(
      '/clickhouse/tables/{database}/fact_token_bonding_status', '{replica}', sign)
  PARTITION BY (chain_id, toYYYYMM(event_ts))
  ORDER BY (chain_id, token_address, block_number, vendor_event_id);
  ```

  Postgres / MySQL keep an append-only `launchpad_events` table plus a `token_bonding_status` current-state projection (a materialized view on Postgres, a trigger-maintained table on MySQL).
</Accordion>

### Run it

Everything runs in **your** infrastructure: the sink writes into a database you own and you query it with plain SQL, no API and no per-call limits.

**Prerequisites**

* **Docker** and Docker Compose.
* A **Data Feeds key**, a `cm_live_…` key with `continuum:read` scope (this is *not* your Web3 API key).

<Card title="Sign up for a Data Feeds key" icon="key" href="https://admin.moralis.com">
  Log in to the Moralis admin panel to create your account and generate a `cm_live_…` key.
</Card>

**Start the sink**

Generate a **starter pack** for `tokenBondingStatus` in the [Moralis Admin Panel](https://admin.moralis.com), choose **Solana** as the chain (launchpad activity is densest on pump.fun and Raydium LaunchLab) and your destination, then run it with Docker. The [quickstart](/data-feeds/migration/quickstart) walks through it end to end.

<Note>
  **Backfill by use case.** The new / bonding / graduated **lists** are event feeds, run **realtime** to track launches live, no backfill needed. A per-token **status** is current state, backfill from the token's `created` event to capture its full curve. See [History & backfill](/data-feeds/concepts/history-and-backfill).
</Note>

### Example reads

**New tokens** on a launchpad, the token's `created` event, newest first:

```sql theme={null}
SELECT token_address,
       argMax(token_name,   (block_number, log_index)) AS name,
       argMax(token_symbol, (block_number, log_index)) AS symbol,
       min(event_ts)                                   AS created_at
FROM recipe_token_bonding_status.fact_launchpad_events FINAL
WHERE exchange_address = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'
  AND event_type = 'created'
GROUP BY token_address
ORDER BY created_at DESC
LIMIT 50;
```

**Bonding tokens**, progress \< 100, not yet graduated, closest to graduating first:

```sql theme={null}
SELECT token_address,
       argMaxIf(progress_percentage, block_number, progress_percentage IS NOT NULL) AS bonding_progress
FROM recipe_token_bonding_status.fact_token_bonding_status FINAL
WHERE exchange_address = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'
GROUP BY token_address
HAVING maxIf(1, event_type = 'migrated') = 0 AND bonding_progress < 100
ORDER BY bonding_progress DESC
LIMIT 50;
```

**Graduated tokens**, tokens with a `migrated` event, plus the DEX pool they migrated into (`max` grabs the non-empty `pool_address`, since a graduation can emit more than one `migrated` row):

```sql theme={null}
SELECT token_address,
       minIf(event_ts, event_type = 'migrated') AS graduated_at,
       max(pool_address)                        AS pool_address
FROM recipe_token_bonding_status.fact_launchpad_events FINAL
WHERE exchange_address = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P'
GROUP BY token_address
HAVING maxIf(1, event_type = 'migrated') = 1
ORDER BY graduated_at DESC
LIMIT 50;
```

**Bonding status** for one token:

```sql theme={null}
SELECT token_address AS mint,
       argMaxIf(progress_percentage, (block_number, log_index),
                progress_percentage IS NOT NULL)  AS bonding_progress,
       maxIf(1, event_type = 'migrated') = 1       AS graduated,
       minIf(event_ts, event_type = 'migrated')    AS graduated_at
FROM recipe_token_bonding_status.fact_token_bonding_status FINAL
WHERE token_address = {mint:String}
GROUP BY token_address;
```

### Other ways to consume this data

The sink is the way to get **these pre-shaped tables**. The *same underlying data* is also available as the **raw decoded feed**, if you'd rather shape it yourself:

* **Your existing message clients**: stream `launchpadEvents` live with **Kafka / AMQP / SQS** (great for a real-time launch feed).
* **REST / Arrow Flight**: pull the decoded Solana block stream directly.
* **Your warehouse**: query it via **Iceberg** from Snowflake, BigQuery, Spark, or DuckDB.

Those give you the raw `launchpadEvents` array to project yourself, not these tables. All read the one data lake into **your** infrastructure. See [What are Data Feeds?](/data-feeds/concepts/what-are-data-feeds).

### Modes

Shipped defaults: **ClickHouse `hybrid`** (backfill → realtime), **Postgres / MySQL `historical`**. For live launch discovery use ClickHouse, see the [overview](/data-feeds/templates/overview#modes).

### Multichain

Launchpad activity is densest on **Solana** (pump.fun, Raydium LaunchLab) and **Base**; on Ethereum mainnet the `launchpadEvents` array is effectively empty. Point the template at Solana in the Admin Panel wizard for real coverage. On Solana `logIndex` isn't row-unique within an instruction, so `vendor_event_id` widens with `(tokenAddress, eventType)` to keep rows distinct.

### How much data does this consume?

`tokenBondingStatus` reads a single per-block array, `launchpadEvents`, one of the smallest slices in the feed. On **Solana mainnet**, where launchpad activity is concentrated, a continuous real-time feed measured:

|                     | Uncompressed bytes per month |
| ------------------- | ---------------------------- |
| Typical month (P50) | **\~8.7 GB**                 |
| Busy month (P90)    | **\~15.1 GB**                |

<sub>Measured 2026-08-04 against the live feed, 30 sampled partitions over 30 days, `metered` delivery. Billing is on uncompressed bytes.</sub>

**Size your allowance against the top of the band, not the middle.** Chain activity varies, and this template tracks launchpad activity specifically, which is bursty by nature: a quiet month and a memecoin frenzy are not the same month. Worked example, against a hypothetical 10 GB monthly allowance:

| If the month runs at | Against a 10 GB allowance              |
| -------------------- | -------------------------------------- |
| 8.5 GB               | Within allowance, nothing extra to pay |
| 15 GB                | 5 GB of overage                        |

Both are inside the measured range for this template, so choose an allowance that covers the busy figure and treat the typical figure as the good case.

What this figure does and does not cover:

* **Real-time only.** A historical backfill is billed separately and is usually the larger number; its size depends entirely on how far back you go.
* **Solana.** On EVM chains the `launchpadEvents` array is effectively unpopulated (see [Multichain](#multichain)), so this template reads close to nothing on Ethereum.
* **The whole slice, across every launchpad and every token.** Filtering to specific tokens, platforms, or programs happens after the data is delivered, so it does not reduce the figure. To reduce cost, narrow the **block range**, not the entity set.
* **`metered` delivery.** Under `presigned_url` you are billed for whole partitions rather than the columns you project, which is a different number.

If you want your exact scope measured before you commit to a plan, [reach out](/data-feeds/early-access) and we will probe it against the live feed rather than estimate it.

### Fidelity gaps

* **`name` / `symbol`** ride on the `created` event; a token seen only via `traded` events carries none until you join [Token Metadata](/data-feeds/templates/token/token-metadata) (also the source of `decimals`).
* **`progress_percentage` is sparse**: `created` events carry no curve progress (0 is coerced to null), so a freshly-created token has null progress until its first trade.
* **No price in the feed.** `current_price` lands **empty on the Solana feed today** (0 populated in live sampling). Derive the **native price** per token from `traded` events (`native_amount / token_amount`), and convert to **USD** with a SOL/USD mark (e.g. wrapped SOL from a [Token Prices](/data-feeds/templates/token/token-prices) sync). **Liquidity** (cumulative curve `native_amount`, or post-graduation [Pair Reserves](/data-feeds/templates/markets/pair-reserves)) and **FDV** (`token_metadata.total_supply` × price) are derive-or-omit.
* **`pool_address` arrives on the `migrated` event**: the DEX pool the token graduated into (verified live). A graduation can emit **more than one** `migrated` row, so take the non-empty value with `max(pool_address)` rather than `anyLast`.
* **`logo`** and other off-chain metadata aren't in the feed.

Core fields, `token_address`, `exchange_address`, `event_type`, `progress_percentage`, graduation (the `migrated` event, with `pool_address`), token name/symbol (on `created`), trade amounts, and timestamps, are sourced from `launchpadEvents`.

## Migrating from the REST API

<Warning>
  All four Solana launchpad endpoints below are **deprecated and sunset on July 31, 2026**. This one template replaces all of them, each REST response is a read over the tables above.
</Warning>

The four endpoints share most of their response shape, so the common fields map once:

| REST API field (all four endpoints) | Data Feeds                                                                                                                      | Fidelity     |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| `tokenAddress` / `mint`             | `token_address`                                                                                                                 | exact        |
| `name`, `symbol`                    | `token_name` / `token_symbol` on the `created` event, or [Token Metadata](/data-feeds/templates/token/token-metadata)           | exact        |
| `decimals`                          | `token_metadata.decimals` (join [Token Metadata](/data-feeds/templates/token/token-metadata))                                   | exact        |
| `priceNative`                       | derive `native_amount / token_amount` from `traded` events, `currentPrice` is **not populated** on the Solana feed today        | calculated   |
| `priceUsd`                          | `priceNative` × a SOL/USD mark (wrapped SOL via [Token Prices](/data-feeds/templates/token/token-prices))                       | calculated   |
| `liquidity`                         | cumulative curve `native_amount` × price; post-graduation, [Pair Reserves](/data-feeds/templates/markets/pair-reserves) × price | calculated   |
| `fullyDilutedValuation`             | `token_metadata.total_supply` × price                                                                                           | calculated   |
| `logo`                              | not in the feed, bring your own token list, or omit                                                                             | add yourself |

In every deprecated endpoint URL, `:exchange` is the launchpad's onchain **program address** (pump.fun is `6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P`); each event carries it as `exchange_address` plus a friendly `launchpad_platform` (`pumpfun`, `raydium_launchlab`), filter on either. None of the lists have a per-call cap anymore; page with a keyset on the sort column.

### New tokens by exchange

```
GET /token/:network/exchange/:exchange/new
```

"New" is the set of **`created`** events on a launchpad, newest first, a view over `fact_launchpad_events`:

```sql theme={null}
CREATE VIEW new_tokens_by_exchange AS
SELECT
  token_address,
  exchange_address,
  argMax(token_name,   (block_number, log_index)) AS name,
  argMax(token_symbol, (block_number, log_index)) AS symbol,
  min(event_ts)                                   AS created_at
FROM recipe_token_bonding_status.fact_launchpad_events FINAL
WHERE event_type = 'created'
GROUP BY token_address, exchange_address;
-- per launchpad: WHERE exchange_address = :exchange ORDER BY created_at DESC
```

`createdAt` maps to `min(event_ts)` over the `created` event (exact).

* Launches are an **event list**, run the template realtime for a live feed, no backfill needed; index back only to list tokens created before you started.
* A brand-new token has **no price and no curve progress** until its first trade.

### Bonding tokens by exchange

```
GET /token/:network/exchange/:exchange/bonding
```

"Bonding" is the set of tokens still on the curve, progress below 100, never migrated, ranked by progress:

```sql theme={null}
CREATE VIEW bonding_tokens_by_exchange AS
SELECT
  token_address,
  exchange_address,
  argMaxIf(progress_percentage, block_number, progress_percentage IS NOT NULL) AS bonding_progress
FROM recipe_token_bonding_status.fact_token_bonding_status FINAL
GROUP BY token_address, exchange_address
HAVING maxIf(1, event_type = 'migrated') = 0   -- still bonding (not graduated)
   AND bonding_progress < 100;
-- per launchpad: WHERE exchange_address = :exchange ORDER BY bonding_progress DESC
```

`bondingCurveProgress` maps to the latest non-null `progress_percentage` per token (exact).

* **Progress is carried forward**: it updates with each trade, and is null until the first trade (same as the old endpoint, which had nothing to report before curve activity).
* A token **leaves the bonding list** the moment it emits a `migrated` event; the `HAVING` clause excludes those.

### Graduated tokens by exchange

```
GET /token/:network/exchange/:exchange/graduated
```

Graduation is the **`migrated`** event, a token with one has left the curve for a DEX pool:

```sql theme={null}
CREATE VIEW graduated_tokens_by_exchange AS
SELECT
  token_address,
  exchange_address,
  minIf(event_ts, event_type = 'migrated') AS graduated_at,
  max(pool_address)                        AS pool_address   -- the migrated DEX pool
FROM recipe_token_bonding_status.fact_launchpad_events FINAL
GROUP BY token_address, exchange_address
HAVING maxIf(1, event_type = 'migrated') = 1;  -- has graduated
-- per launchpad: WHERE exchange_address = :exchange ORDER BY graduated_at DESC
```

`graduatedAt` maps to `minIf(event_ts, event_type = 'migrated')`, and `poolAddress`, which the old endpoint didn't even expose, is `max(pool_address)` over the token's `migrated` events (both exact).

<Note>
  **This one is not a 1:1 swap.** The REST response bundled prices, liquidity, and FDV, but a graduated token trades on a normal DEX pool, so price it with [Token Prices](/data-feeds/templates/token/token-prices) and read pool liquidity with [Pair Reserves](/data-feeds/templates/markets/pair-reserves), keyed on the migrated `pool_address`. Run those templates alongside this one if you serve those fields.
</Note>

* `pool_address` is **only populated on `migrated` events** (verified live), and a graduation can emit more than one `migrated` row, take the non-empty value with `max(pool_address)`, not `anyLast`.
* Graduations are an event list, run realtime to catch them as they happen.

### Token bonding status

```
GET /token/:network/:address/bonding-status
```

The most direct migration of the set, the template's per-token projection *is* this response. `mint`, `bondingProgress`, and `graduatedAt` map to `token_address`, `bonding_progress`, and `graduated_at` (all exact). On Postgres or MySQL it's a single-row lookup on the maintained status table:

```sql theme={null}
SELECT token_address AS mint, bonding_progress, graduated, graduated_at
FROM token_bonding_status
WHERE token_address = $1;
```

On ClickHouse, use the per-token aggregate shown in [Example reads](#example-reads).

* **Status is current state**, not an event list, backfill from the token's `created` event to capture its full curve and graduation history.
* `graduated` / `graduated_at` come from the `migrated` event; both are empty until the token graduates.

### Related

<Columns cols={2}>
  <Card title="Token Metadata" href="/data-feeds/templates/token/token-metadata" icon="tag">
    Names, symbols, and decimals for launchpad tokens.
  </Card>

  <Card title="Token Prices" href="/data-feeds/templates/token/token-prices" icon="dollar-sign">
    USD marks to layer onto bonding and graduated tokens.
  </Card>
</Columns>
