# Indexing Slyng coins

For explorers, wallets, trackers and aggregators. Everything here is readable from the chain
with no key, no API and no permission from us.

Written to be sent as-is. If you are reading it because you want a coin's page to say
**Launched on Slyng**, § 2 is the only part you strictly need.

---

## 0. Start here

One URL answers everything below in JSON, and it is generated from the deployment rather than
edited by hand, so it cannot go stale the way a document can:

```
https://slyng.tech/api/launchpad
```

If you keep a table of launchpads and tag coins by the contract that created them, this is the
row, already filled in:

| Field | Value |
|---|---|
| id | `slyng` |
| Display name | `Slyng` |
| Logo | `https://slyng.tech/logo.png` |
| Chain | `evm:4663` (Robinhood Chain) |
| Factory | `0xCe0ABC33eC4264377045Ae17F9B887DB33Cc95B4` |
| First block | `60372065` |
| Creation event | `TokenCreated` |
| Type | bonding curve |

And the feeds:

| For | URL |
|---|---|
| Every coin, with its curve, stats and artwork | `https://slyng.tech/api/coins` |
| One coin | `https://slyng.tech/api/coins?addresses=0x…` |
| A coin's artwork, at a permanent URL | `https://slyng.tech/api/coin-image/0x…` |
| Trades | `https://slyng.tech/api/trades?token=0x…` · `https://slyng.tech/api/activity?hours=24` |
| CoinGecko-format DEX endpoints (§ 11) | `https://slyng.tech/api/coingecko/tickers` |

All open CORS, no key, no rate limit we enforce.

---

## 1. What Slyng is

A token launchpad on **Robinhood Chain** (chain ID **4663**). A creator opens a coin; its whole
supply starts on a constant-product bonding curve held by the launchpad; when enough quote
accumulates the coin graduates into a Uniswap v4 pool whose liquidity is minted into a contract
with no withdrawal path.

Every coin is a plain fixed-supply ERC-20. Nothing about indexing one is special.

---

## 2. How to tell a coin was launched on Slyng

**Read one field.** Every coin records its launchpad on the token contract:

```solidity
address public immutable launchpad;   // LaunchToken.sol
```

It is set to `msg.sender` in the constructor — the launchpad that minted it — and it is
`immutable`, so there is no setter, no proxy and no owner path that can change it afterwards.

```
launchpad() == <SLYNG_LAUNCHPAD_ADDRESS>   →  the coin was launched on Slyng
```

**This is worth preferring over a hardcoded list**, because it cannot be faked in either
direction: a coin minted somewhere else cannot claim us, and one of ours cannot be made to
disown us. A clone can copy our name and logo onto a website; it cannot make a token return
our address from an immutable.

If you would rather watch events, `TokenCreated` (§ 4) is emitted once per coin by the same
address.

---

## 3. Addresses

| | Address |
|---|---|
| Chain | Robinhood Chain, id `4663` |
| RPC | `https://rpc.mainnet.chain.robinhood.com` |
| **Launchpad** | `0xCe0ABC33eC4264377045Ae17F9B887DB33Cc95B4` |
| Deploy block | `60372065` — start a backfill here; nothing of ours exists before it |
| Name to display | `Slyng` |
| Logo | `https://slyng.tech/logo.png` |
| Site | `https://slyng.tech` |
| A coin's page | `https://slyng.tech/token/<address>` |

`https://slyng.tech/api/launchpad` serves this table as JSON, read from the deployment. Prefer
it: a document gets edited on deploy day and eventually says something that is not true any
more, which is exactly what this row did until 2026-09-20.

---

## 4. Events

All emitted by the launchpad.

```solidity
event TokenCreated(
    address indexed token,
    address indexed creator,
    address indexed quote,
    string  name,
    string  symbol,
    uint256 lockupSeconds,
    uint256 creatorUnlockAt,
    uint256 graduationTarget
);

event Bought(address indexed token, address indexed buyer,  uint256 quoteIn,  uint256 tokensOut, uint256 fee);
event Sold  (address indexed token, address indexed seller, uint256 tokensIn, uint256 quoteOut,  uint256 fee);
event Graduated(address indexed token, uint256 lpQuote, uint256 tokenReserve, uint256 graduationFee);
```

**One caution specific to this chain:** `eth_getLogs` here silently truncates above roughly one
million blocks — it returns a short result rather than an error. Chunk your backfill. We use
200,000.

---

## 5. Reading a coin's state

`Launchpad.curves(address token)` returns, in order:

```
quoteReserve, tokenReserve, graduationTarget, virtualQuote, lpQuote,
quote, creator, createdAt, exists, graduated
```

Useful derivations:

- **Liquidity / raised** — `quoteReserve`. It is zeroed at graduation, when trading moves to
  Uniswap v4; a graduated coin's depth is the pool's, not ours.
- **Price** — the curve is constant-product over `quoteReserve + virtualQuote` and
  `tokenReserve`, so the spot price of one whole coin, in base units of the quote asset, is:

  ```
  price = (virtualQuote + quoteReserve) * 1e18 / tokenReserve
  ```

  **`virtualQuote` is the term to get right.** It is the seed that sets a coin's opening price
  and it is not money anyone deposited; leave it out and every new coin prices at nothing.
  `Launchpad.quoteToTokens` / `tokensToQuote` price a *specific* size against the same curve,
  which is the honest number when the trade is large enough to move it.

- **Market cap** — `price * 1_000_000_000`. Supply is a constant and there is no mint function,
  so fully diluted and circulating are the same number and no adjustment is needed.

- **Graduation progress** — `quoteReserve / graduationTarget`. Clamp at 1: the buy that
  graduates a coin can carry the reserve past the target in a single trade.

- **After graduation** — `quoteReserve` and `tokenReserve` are zero and the formula above says
  nothing. The Uniswap v4 pool is the price from then on, and the coin appears in
  `/tokenlist.json`. Publishing a zero here is the one failure mode worth guarding against:
  it renders a coin that succeeded as a coin that died.
- **Supply** — always exactly 1,000,000,000 with 18 decimals. It is a `constant`; there is no
  mint function anywhere.
- **Holders** — from ERC-20 `Transfer` logs, as with any token.

---

## 6. Things worth surfacing, because they are enforced rather than claimed

Each of these is a property of deployed bytecode, and each is checkable without trusting us:

- **The creator cannot sell before their time gate opens.** Enforced in the token itself, on
  every transfer out of the creator's address — `creatorUnlocked()`, `creatorUnlockAt()`,
  `creatorLockRemaining()`. Not in the launchpad and not in our interface, because either
  could be sidestepped by trading elsewhere. § 6a has the full lock, and the Rug Safe mark.
- **Graduated liquidity cannot be withdrawn by anyone**, including us. The locker has no owner
  and no path that reduces liquidity.
- **Tokens have no owner at all** — no mint, no pause, no blacklist, no upgrade path.
- **The creator got no free allocation.** Any coins they hold were bought on the same curve as
  everyone else, capped at 5%.

If you show a "verified" or "safe" badge, these are the specific claims behind ours, and you
are welcome to check every one before repeating any of them.

---

## 6a. Creator lock and Rug Safe Launch

Every Slyng coin launches with a **creator lock**: for a period the creator picks at launch,
the creator's address cannot sell or transfer the coin. Coins whose lock is 12 hours or longer
carry the **Rug Safe** mark on Slyng. Both are read off the token, so you can show them
without trusting us or calling our API.

**The rules, from the launchpad's constants:**

| | Value | Launchpad constant |
|---|---|---|
| Shortest lock (there is no zero) | 1 hour | `MIN_LOCKUP()` |
| Shortest lock that earns the Rug Safe mark | 12 hours | `RUG_PROTECTED_LOCKUP()` |
| Default when the creator picks nothing | 12 hours | `DEFAULT_LOCKUP()` |
| Longest lock | 30 days | `MAX_LOCKUP()` |

The lock is fixed at launch. It cannot be shortened, extended or added later, so a coin that
launched without the mark can never gain it, and one that has it can never lose it.

**Reading it from the token** (`LaunchToken`, all `view`, all immutable or derived from immutables):

```solidity
uint256 public immutable timeGateSeconds;   // the lock length the creator chose
uint256 public immutable creatorUnlockAt;   // unix time the creator can first sell
function creatorUnlocked() view returns (bool);           // true once that time has passed
function creatorLockRemaining() view returns (uint256);   // seconds left, 0 once unlocked
address public immutable creator;           // the address the lock applies to
```

**Rug Safe, as one test:**

```
token.timeGateSeconds() >= launchpad.RUG_PROTECTED_LOCKUP()    // 12 hours
```

Check the coin is ours first (§ 2: `token.launchpad() == 0xCe0ABC33eC4264377045Ae17F9B887DB33Cc95B4`).

**From events,** without a call per coin: `TokenCreated` (§ 4) carries `lockupSeconds` and
`creatorUnlockAt` for every coin, from the first block.

**From our feed:** `https://slyng.tech/api/coins` returns `creatorUnlockAt` (unix seconds) and
`rugProtected` (the test above) on every coin.

**What it means for a buyer, and what it does not.** The lock stops the creator selling or
moving their coins until `creatorUnlockAt`; the token itself refuses the transfer, so trading
elsewhere does not get around it. It does not stop anyone else selling, and it ends on
schedule. A fair way to show it: a "Rug Safe" badge while the mark holds, and "Creator locked
· 2d 4h left" / "Creator unlocked" from `creatorLockRemaining()`.

---

## 7. Token list

`https://slyng.tech/tokenlist.json` — tokenlists.org schema, **graduated coins only**, since a
coin still on its curve does not trade anywhere a wallet could route to. Each entry carries:

```json
"extensions": {
  "launchpad": "Slyng",
  "launchpadUrl": "https://slyng.tech",
  "launchpadAddress": "0x..."
}
```

Coins whose name or symbol falls outside the schema's own regexes are omitted rather than
included, so one bad coin cannot invalidate the document for everybody.

---

## 8. The coin feed — curve, stats and artwork, including coins still bonding

`https://slyng.tech/api/coins` — every coin this launchpad has minted, curve and graduated
alike, with everything the chain has no room for and the curve arithmetic already done.

The token list above is a *tradability* document and excludes bonding coins by design, so a
coin of ours will render as an anonymous ERC-20 in an app that has indexed it correctly unless
it reads this.

```
GET /api/coins                       newest 50, add ?limit= (max 200) and ?offset=
GET /api/coins?addresses=0x..,0x..   exactly those, up to 100
```

```json
{
  "chainId": 4663,
  "launchpad": "0xCe0ABC33eC4264377045Ae17F9B887DB33Cc95B4",
  "fees": {
    "tradeBps": 100,
    "graduationBps": 500,
    "openingSurchargeBps": 5000,
    "openingWindowSeconds": 30,
    "creatorShareBps": 7000
  },
  "usd": { "unit": "USDG", "ethUsd": 2627.67, "source": "Uniswap V3 WETH/USDG spot, this chain" },
  "total": 1,
  "count": 1,
  "metadataAvailable": true,
  "statsAvailable": true,
  "coins": [
    {
      "address": "0x066FFa6AAF8B54C6094d1Ed1bE818AFA5e0f290E",
      "name": "SLYNG",
      "symbol": "SLYNG",
      "decimals": 18,
      "totalSupply": "1000000000000000000000000000",
      "creator": "0x6D3e4eC533d34dD87DB1117D0b3B650EBb45E2a2",
      "createdAt": 1789435818,
      "quote": { "address": null, "symbol": "ETH", "decimals": 18 },
      "graduated": false,
      "creatorUnlockAt": 1792027818,
      "rugProtected": true,
      "url": "https://slyng.tech/token/0x066FFa6AAF8B54C6094d1Ed1bE818AFA5e0f290E",
      "curve": {
        "quoteReserve": "149229214963614729",
        "tokenReserve": "909515782518497877947009684",
        "virtualQuote": "1500000000000000000",
        "graduationTarget": "5000000000000000000",
        "lpQuote": "0",
        "progress": 0.0298458,
        "price": "1813304668",
        "marketCap": "1813304668000000000",
        "liquidity": "149229214963614729",
        "priceUsd": 4.7647e-6,
        "marketCapUsd": 4764.77,
        "liquidityUsd": 392.12
      },
      "stats": { "holders": 9, "volume24h": "10470873933702284", "volume24hUsd": 27.51, "trades24h": 2 },
      "logoURI": "https://slyng.tech/api/coin-image/0x066FFa6AAF8B54C6094d1Ed1bE818AFA5e0f290E",
      "logoSourceURI": "https://…supabase.co/…/0x066f….png?v=1789435823599",
      "description": "Slyng launchpad token. 70% fees to creators, 30% to Protocol and BURN…",
      "links": { "website": "https://slyng.tech/", "x": "https://x.com/SlyngTech", "telegram": "https://t.me/SlyngCommunity" }
    }
  ],
  "next": null
}
```

### The fields, and what they are not

- **Every amount is base units, as a string.** Quote amounts in the quote asset's decimals,
  token amounts in 18. They are the chain's own integers and a decimal would round your
  arithmetic for you.
- **`curve.price` is base units of the quote asset per one whole coin**, and `curve.marketCap`
  is that times the billion. Both are `null` for a graduated coin — read its Uniswap v4 pool.
- **`curve.liquidity` is `quoteReserve`**: what the curve will actually pay out. A bonding coin
  has no pool, so it has no pool liquidity, and reporting zero for it is the common mistake.
- **`…Usd` fields are convenience, not truth.** Computed at the rate stated in `usd`, which is
  this chain's WETH/USDG spot. A coin paired against a tokenized equity has no dollar rate at
  all, so its dollar fields are `null` while its base-unit amounts stay exact.
- **`fees` is read from the launchpad on each request**, not hardcoded by us, so it is what a
  trade is actually priced by. The opening surcharge is flat inside
  `openingWindowSeconds` of `createdAt` and nothing after — it is withheld *before* the curve
  prices the trade, so a quote that ignores it is wrong by up to half during the window.
- **`quote.address` is `null` for native ETH**, which is how the contract spells it.
- **An address we did not mint comes back in `unknown`**, not as an error and not silently
  dropped — so this doubles as an attribution check alongside `launchpad()` on the token.
- **`metadataAvailable: false` / `statsAvailable: false` mean those blocks are absent**, not
  that the coins have none. Those responses are sent `no-store`; do not cache "no logo" or
  "zero holders" from one.
- **`stats` comes from our indexer**, which runs every ten minutes. Everything else on a coin
  is read from the chain on the request.
- **A coin moderated off our own site is omitted.** It still exists on chain and you will still
  see it in `TokenCreated`; what you will not get from us is its artwork.

Cached 120s at the edge. CORS is open.

---

## 9. A coin's artwork, at a URL that does not change

```
https://slyng.tech/api/coin-image/<address>        (`.png` may be appended; it is ignored)
```

302s to wherever the bytes currently live. **Prefer it to `logoSourceURI`.** That one is the
storage URL, and it carries a cache-busting query that changes every time a creator edits their
picture — fine for our pages, and the reason an external index either re-downloads forever or
decides the coin has no logo.

`404` means this coin has no artwork; `503` means we could not look. They are different answers
and only the first one is safe to remember.

---

## 10. Trades

```
GET /api/trades?token=0x…&limit=500     one coin, newest first
GET /api/activity?hours=24              every coin, oldest first (&trader=0x… to filter)
```

Each row: `side` (`buy`/`sell`), `quote`, `tokens`, `fee` — base units, strings — plus
`trader`, `txHash` and `at` (unix seconds).

Both lay the last half hour read live from the chain over the indexed rows, deduplicated, so a
trade appears the moment it confirms rather than after the next indexer run. `fee` is included
because it is the part of each trade that did *not* reach the reserve, which you need if you
replay the curve from these rows.

You can of course read `Bought` and `Sold` yourself — but see the caution in § 4 about this
chain's `eth_getLogs`. These feeds are the same data without that trap.

---

## 11. CoinGecko and GeckoTerminal API

```
https://slyng.tech/api/coingecko
```

The same data as § 8 and § 10, in the shape CoinGecko's exchange integration standard asks
for. No key, open CORS, cached 30 s at the edge, every number a decimal string.

**Which markets.** One market per Slyng coin on Robinhood Chain (id `4663`) that is **still on
its bonding curve**. A graduated coin trades on Uniswap v4 and is left out on purpose:
GeckoTerminal tracks those pools natively, and listing them here as well would count their
volume twice.

**Identifiers.**

| Field | Value |
|---|---|
| `ticker_id` | `{coinAddress}_{quoteAddress}`, lower-case |
| `base_currency` | the coin's address |
| `target_currency` | WETH `0x0bd7d308f8e1639fab988df18a8011f41eacad73` for an ETH-quoted coin, USDG `0x5fc5360d0400a0fd4f2af552add042d716f1d168` for a USDG-quoted one |
| `pool_id` | the coin's address. The curve lives inside the launchpad (`0xCe0ABC33eC4264377045Ae17F9B887DB33Cc95B4`), keyed by coin, so there is no separate pool contract |

### Routes

```
GET /api/coingecko/pairs
GET /api/coingecko/tickers
GET /api/coingecko/historical_trades?ticker_id=&type=buy|sell&limit=200&start_time=&end_time=
GET /api/coingecko/orderbook?ticker_id=&depth=100
```

**`/pairs`** — every market:

```json
[
  {
    "ticker_id": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e_0x0bd7d308f8e1639fab988df18a8011f41eacad73",
    "base": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e",
    "target": "0x0bd7d308f8e1639fab988df18a8011f41eacad73",
    "pool_id": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e"
  }
]
```

**`/tickers`** — 24 h stats per market (SLYNG at the § 8 snapshot, ETH at $2,627.67):

```json
[
  {
    "ticker_id": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e_0x0bd7d308f8e1639fab988df18a8011f41eacad73",
    "base_currency": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e",
    "target_currency": "0x0bd7d308f8e1639fab988df18a8011f41eacad73",
    "pool_id": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e",
    "last_price": "0.00000000181330467",
    "base_volume": "5774512.3",
    "target_volume": "0.01047087",
    "liquidity_in_usd": "392.13",
    "virtual_liquidity_in_usd": "4333.63",
    "bid": "0.00000000179517162",
    "ask": "0.00000000183162088",
    "high": "0.00000000181330467",
    "low": "0.00000000180100000"
  }
]
```

- **`last_price`** — the curve's spot price, quote per whole coin:
  `(virtualQuote + quoteReserve) / tokenReserve`, in decimals (§ 5).
- **`base_volume` / `target_volume`** — coins and quote traded in the last 24 hours, rolling,
  summed from on-chain `Bought` and `Sold`.
- **`high` / `low`** — highest and lowest trade price over the same 24 hours.
- **`bid` / `ask`** — what the next marginal sell and buy actually get once the 1 % trade fee
  is taken: `bid = last_price × 0.99`, `ask = last_price ÷ 0.99`. The curve itself has no spread. In a coin's first 30 seconds the
  opening surcharge (50 %) also comes off a buy, so `ask = last_price ÷ 0.49` until it lapses.
- **`liquidity_in_usd`** — the **real** quote reserve (`quoteReserve`) in dollars: what the
  curve can pay out to sellers. It excludes `virtualQuote`, which nobody deposited.
- **`virtual_liquidity_in_usd`** — `virtualQuote + quoteReserve` in dollars: the quote side of
  the constant product that sets the price. Needed for depth, below.

**`/historical_trades`** — newest first, split by side as the standard asks; `type` picks one
side. `limit` defaults to 200; `start_time` / `end_time` are Unix seconds.

```json
{
  "buy": [
    {
      "trade_id": 4821,
      "price": "0.00000000181330467",
      "base_volume": "5774512.3",
      "target_volume": "0.01047087",
      "trade_timestamp": "1789440000",
      "type": "buy"
    }
  ],
  "sell": []
}
```

`trade_id` is an integer unique to the trade. `price` is `target_volume / base_volume` for
that trade.

**`/orderbook`** — an AMM has no resting orders, so this is **simulated from the curve**:
levels stepped out from `last_price`, each sized by what the curve would fill between it and
the one before, fee included. `depth` is the total number of levels (`100` = 50 a side).

```json
{
  "ticker_id": "0x066ffa6aaf8b54c6094d1ed1be818afa5e0f290e_0x0bd7d308f8e1639fab988df18a8011f41eacad73",
  "timestamp": "1789440000",
  "bids": [["0.00000000179517162", "1820.5"], ["…", "…"]],
  "asks": [["0.00000000183162088", "1815.1"], ["…", "…"]]
}
```

### ±2 % depth, from `/tickers` alone

The curve is constant-product over `X = virtualQuote + quoteReserve` (quote) and
`Y = tokenReserve` (coins), so it is a Uniswap V2 pool whose quote side is `X`. Moving the
price by a factor `k` takes the quote side from `X` to `X·√k`. With
`X_usd = virtual_liquidity_in_usd` and `R_usd = liquidity_in_usd`:

```
+2% depth (USD, buys)  = X_usd × (√1.02 − 1)                     ≈ X_usd × 0.009950
−2% depth (USD, sells) = min( X_usd × (1 − √0.98), R_usd )         ≈ X_usd × 0.010050
```

For SLYNG above: +2 % = $43.12, −2 % = $43.56 (under the $392.13 the curve holds, so the
cap does not bind).

Why not the default Uniswap V2 formula on `liquidity_in_usd`: that assumes the pool's quote
side is half of `liquidity_in_usd`. Here the quote side that sets the price is
`virtual_liquidity_in_usd`, and `liquidity_in_usd` is only the real money in it, so the
default understates depth by about 20× on a young coin. The `min` on the sell side is the one
place the virtual reserve stops being real: the curve can never pay out more than
`quoteReserve`.

Both amounts are what reaches the curve; a buyer's gross spend is that ÷ 0.99 for the 1 % fee.
In the first 30 s after launch an opening surcharge also applies (§ 8 `fees`); the formula
ignores it.

---

## 12. Contact

`https://x.com/SlyngTech` · `https://slyng.tech`

If something here is wrong, missing, or would be easier for you in another shape, say so and we
will change it. Being easy to index is the entire point of this file.
