> Bull Launch docs. Every page is available as Markdown by adding `.md` to its URL; the index is https://bulllaunch.fun/llms.txt. This page on the web: https://bulllaunch.fun/docs/token-metadata

# Token metadata

How a coin's description, image and links are encoded at launch, and how to read them back.

A coin's name and symbol are ERC-20 fields. Everything else a creator enters, the description, the image and the links, travels as the `tokenData` argument of `LauncherFactory.launch`, is stored on chain once, and cannot be changed afterwards.

## Encoding

`tokenData` is the ABI encoding of one tuple. Send `0x` when there is no metadata at all: the factory accepts it, whereas bytes it cannot decode revert the launch.

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

const tokenData = encodeAbiParameters(
  [{ type: "tuple", components: [
    { name: "description", type: "string" },
    { name: "website",     type: "string" },
    { name: "image",       type: "string" },
    { name: "extraData",   type: "bytes"  },
  ] }],
  [{
    description: "The bull that never sleeps.",
    website: "https://bullcoin.example",
    image: "https://…/bull.webp",
    extraData: toHex(JSON.stringify({
      x: "https://x.com/bullcoin",
      telegram: "https://t.me/bullcoin",
      website: "https://bullcoin.example",
    })),
  }]
);
```

| Field | What goes in it |
| --- | --- |
| description | Plain text, shown on the coin's page. |
| website | One URL. The coin's own site when it has one, otherwise its X link, then Telegram. Older launches put an X or Telegram URL here, so classify it by host before drawing it as a website. |
| image | An absolute `https` URL, stored on chain as written. PNG, JPEG or WebP; square, around 600px, is what every surface draws. |
| extraData | UTF-8 JSON, hex-encoded, with any of `x`, `telegram`, `website` as full URLs. The contract never reads it; it exists so a launch can carry more than one link. Empty is `0x`. |

## Reading it back

The indexer decodes all of it: `token { name symbol image description }` plus the links, on the same GraphQL API the app uses (see [Indexer API](https://bulllaunch.fun/docs/indexer-api.md)). From the chain alone, decode `tokenData` from the `TokenLaunched` event or the launch transaction's input.

> Treat every field as untrusted input: it is whatever the creator typed. Allow only `http` and `https` links, and never render the description as HTML.
