The logo registry for assets issued on DecentralChain.
A logo in this repository is a reviewed logo. That is the whole point.
The DecentralChain exchange shows a coloured monogram for every asset — the first letter of its name on a hue derived from its asset ID. That mark is stable, legible and automatic, so no token ever renders blank.
This repository is how a token replaces that monogram with a real logo.
Anyone can issue a token and call it whatever they like. So a logo has to mean more than "somebody uploaded a picture" — otherwise the first thing it would be used for is dressing a look-alike token in a well-known brand's mark. Here, a logo appears in the exchange only after a human has reviewed and merged it. That review is the feature.
you this repo the exchange
│ │ │
├─ 1. open an issue ──────▶│ │
│ (image attached) │ │
│ ├─ 2. intake bot opens a PR │
│ ├─ 3. a human reviews and merges │
│ ├─ 4. publish derives 64/128.webp │
│ │ and rebuilds manifest.json │
│ │ │
│ └──── 5. jsDelivr serves it ──────▶│
│ │
│ 6. your logo appears
Steps 2, 4 and 5 are automatic. Step 3 is a person, on purpose.
Step 5 is not instant. jsDelivr caches the manifest for up to 12 hours at its edge and 7 days in a browser that has already loaded the exchange. We do not control those headers. Until your logo arrives, your token shows its monogram — which is why the delay is acceptable rather than a bug.
Issue a token in the exchange. The success screen prepares a correctly-sized
logo.png, downloads it, and hands you a link that opens an issue here with
every field already filled in. Drag the file into the issue and submit.
Open a submission issue and fill in this exact shape — the intake bot parses it, so the labels matter:
**Asset ID:** `8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS`
**Name:** Wizard Coin
**Symbol:** WIZ
**Issuer:** `3PQ6wCS3zAkDEJtvGntQZbjuLw24kxTqndr`Then drag your logo.png into the issue body before submitting. GitHub
uploads and hosts it; the bot fetches it from there.
That last step is the one thing that cannot be automated: a URL cannot carry a binary file, so the image has to be attached by hand. Everything after it is.
| Requirement | Value | Why |
|---|---|---|
| Format | PNG | Lossless, universal, alpha support |
| Dimensions | 256 × 256 | Square. Reviewers need detail; the app derives smaller sizes itself |
| File size | ≤ 100 KB | A mark this size has no business being larger |
| Background | Transparent | The exchange renders logos in a circle on light and dark surfaces |
| Content | No text, no watermark | It sits at 20 px. Words are unreadable and become noise |
| Rights | Yours to publish | You are asserting this when you submit |
Your submitted logo.png is the source of truth. The 64.webp and 128.webp
files beside it are generated on merge — never edit them by hand. They will
be overwritten.
- An asset ID that does not exist on chain, or is not valid base58
- A logo for a token impersonating another project
- Anything not square, oversized, or with a baked-in background
- A directory whose name differs from an existing one only by capitalisation (asset IDs are case-sensitive; macOS filesystems are not, so this would collide on a contributor's machine)
assets/
<assetId>/
logo.png ← you submit this. 256×256, the source of truth
info.json ← metadata, including the hot-set flag
64.webp ← generated. inlined into manifest.json
128.webp ← generated. what the exchange fetches for most assets
manifest.json ← generated. do not hand-edit
{
"name": "Wizard Coin",
"symbol": "WIZ",
"issuer": "3PQ6wCS3zAkDEJtvGntQZbjuLw24kxTqndr",
"links": { "website": "https://example.com" },
"hot": false
}hot is the only field with runtime consequences — see below.
{
"hot": { "<assetId>": "data:image/webp;base64,…" },
"sha": "a1b2c3d"
}The exchange fetches this one file and nothing else by default.
hotcarries the 64 px logo of a handful of curated assets, inlined as data URIs. Those render with zero additional requests.shais the commit every other logo's URL is pinned to:…@<sha>/assets/<assetId>/128.webp.
Because the URL is derived from the asset ID, there is no index of the tail. The manifest stays roughly the same size whether the registry holds fifty tokens or five thousand.
Set "hot": true in an asset's info.json to inline it. Reserve it for assets
people see constantly — the ones that should never flicker. Every hot entry
is downloaded by every visitor, so keep the set around 30. Everything else
lazy-loads and shows its monogram in the meantime, which is fine.
Promoting an asset is a one-line PR, not a code change in the exchange.
Both are easy to trip and neither fails loudly. They are enforced by CI — please do not work around them.
jsDelivr's @latest does not mean "the newest commit". For a GitHub
repository it resolves to the newest version tag, falling back to the
default branch only when the repository has no tags at all.
The day someone cuts v1.0.0, @latest pins to that tag and every logo
merged afterwards stops appearing — with no error anywhere. The manifest
still fetches, still parses, still resolves. It is simply frozen.
guard-tagless.yml fails the build if a tag or release exists.
(If tagging ever becomes necessary, the alternative is to change the exchange's
manifestUrl to pin an explicit branch — @main — which ignores tags.)
Tail URLs are pinned to manifest.sha, and the manifest lives in the repository
whose commit it names. A workflow committing assets and manifest together can
only record the sha it knew before that commit existed — the parent — so
every newly merged logo would 404 at a commit predating its own addition.
Commit A — the derived 64.webp / 128.webp files. → sha: a1b2c3d
Commit B — manifest.json, with "sha": "a1b2c3d".
@latest then serves commit B's manifest, whose sha points at commit A, where
the assets demonstrably exist. publish.yml does this automatically.
npm install
npm run validate -- assets/<assetId> # the checks CI runs on a PR
npm run derive -- assets/<assetId> # regenerate 64.webp / 128.webp
npm run manifest # rebuild manifest.jsonRequires Node 20+. Image work uses sharp.
A submission arrives as an issue labelled logo-submission. intake.yml
parses it, downloads the attachment, runs the same validation CI will run, and
opens a PR. Then it is a judgement call:
- Is this token what it claims to be? The single question that matters. A logo is a trust signal; approving one for an impersonator is worse than having no logos at all.
- Does the asset ID resolve to a real asset on chain, issued by the address in the issue?
- Is the mark legible at 20 px, and does it work on both light and dark grounds?
Merging triggers publish.yml. Nothing else is needed.
Tooling in this repository is MIT. Logos are not — each is the property of its submitter, published here for use in the DecentralChain exchange and ecosystem. Submitting one asserts that you have the right to do so.