Mintline:用哈希链注册表证明哪个 Solana 代币先出现
Mintline: prove which Solana token came first
Mintline 推出面向 Solana 代币身份的公开哈希链起源注册表,通过读取链上 Metaplex 元数据账户判断名称与 ticker 是否已被注册,避免仿冒代币。
Mintline: prove which Solana token came first
A public, hash-chained origin registry for Solana token identities - assayed with an open-weight model that runs in your browser.
Copying an established Solana project's name and ticker is free, instant, and hard to spot. The copy looks like a brand-new asset right up until somebody loses money. Today the answer is "ask in the group chat", which does not scale, produces no evidence, and nobody can check later.
Mintline makes it a registry.
- Live app: https://mintline-eight.vercel.app
- Source: https://github.com/aniruddhaadak80/mintline
- Agent console: https://mintline-eight.vercel.app/agent
Real output. Wrapped SOL assayed against live chain data, scored 52.5. The stamp's ink density and rotation are derived from the score, so the mark is a readout rather than decoration.
What it actually does
1. It reads the chain itself. No indexer key, no wallet, no SDK. Mintline derives the Metaplex metadata account for a mint with hand-rolled ed25519 curve maths and decodes the account itself. The address maths is tested against metadata addresses observed on Solana mainnet:
The interesting part is why that matters for origin claims. If a name comes from a third-party index, it is a claim. If it comes from the token's own metadata account, it is the identity the issuer actually published.
2. The open-weight model runs in your browser. This is the answer to "why does open matter here". A 22M-parameter sentence-embedding model (Xenova/all-MiniLM-L6-v2, Apache-2.0) loads through ONNX Runtime Web in the tab. The token's identity text is never sent anywhere, it keeps working with no network after the first load, and nobody rents a GPU to make it work.
3. It never fakes certainty. There are always two comparators. The server has a deterministic lexical n-gram comparator that needs no model and no network, so a score is always reproducible. The browser upgrades to the neural one. Whichever ran is named in the API response, in the UI, and in the export - never silently substituted.
And when a factor cannot be measured it is reported as unavailable, contributes zero, and flags the result degraded. Weights are never renormalised around the gap, because a missing holder reading must lower confidence rather than inflate the score.
4. Every action is sealed. Create, verdict, re-assay, share and retire each append to a per-record SHA-384 chain:
genesis = SHA-384(UTF-8("mintline/genesis/v1"))
seal(n) = SHA-384( UTF-8(seal(n-1)) || canonicalJson(event(n)) )
Because each seal commits to its predecessor, editing one event invalidates every later one, and replay names the first sequence number that fails to reproduce. Deletion is a soft tombstone on purpose: the row survives so its chain stays replayable.
5. It is scriptable by agents. Ten typed MCP tools over JSON-RPC 2.0. The mutating tools do not write SQL - they call the same repository functions the UI forms call, so "the agent mutates through the same path as the UI" is a structural fact rather than a claim. Retrying a mutation with the same idempotency key does not create a duplicate.
6. You leave with evidence. The dossier downloads as Markdown or JSON with the score, the itemised factor table, per-source attribution with fetch timestamps, the full seal list and the disclaimer - enough to stand alone in a launchpad review.
Three key-free sources, honestly labelled
| Source | Contributes | Failure behaviour |
|---|---|---|
| Solana public RPC | on-chain metadata, supply, holder spread | specific reads degrade individually |
| DexScreener | pairs, liquidity, volume, age | depth reported unavailable |
| Jupiter | independent second price reading | divergence reported as null
|
getTokenLargestAccounts is rate-limited on the public RPC, so holder concentration comes back as state: "unavailable" with a reason rather than as a zero. When every source is down, mints with a sealed sample return it flagged fallback with its capture timestamp - never as current data, and never merged into a stored claim.
Three jobs to be done
- A launchpad operator can paste a mint and see whether its name and ticker already belong to a registered origin, so they do not ship an impersonating token.
- A buyer or integrator can inspect live market structure and metadata provenance, record an auditable verdict, and export a dossier, so they have evidence instead of a group-chat opinion.
- An agent can register, verify and replay claims over typed MCP tools, so the registry is scriptable and every claim stays tamper-evident.
Each was walked end to end through the UI in a real browser: create, read back, decide, engine, agent mutation, replay, export, delete.
Where the honesty costs something
- The rate limiter is held in process memory. On serverless that is per instance, so it stops casual scripting, not a determined flood. A global cap needs a hosted limiter, and the README says so rather than implying otherwise.
- A high provenance score means an identity is not obviously impersonating another. It is not an endorsement of the project behind it, and it says nothing about price. This is not financial advice.
- The storage guard fires on genuinely ephemeral runtimes. On a long-lived Node server the embedded adapter is allowed, and
/api/healthreportsembeddedAdapter: truerather than implying a hosted store.
Verification
Everything below was run against the deployed alias, not asserted:
| Gate | Result |
|---|---|
tsc --noEmit |
clean |
eslint |
clean, React Compiler rules enforced, no suppressions |
| Unit + integration tests | 151 passing across 6 files |
| Production build | passes |
| GitHub Actions | both jobs green |
| Live HTTP verifier | 103 of 103 |
| Browser journey (desktop + mobile) | 39 of 39, zero console errors, zero failed requests |
The verifier is checked in and takes only a base URL:
npm run build && node scripts/smoke.mjs # boots its own server
BASE_URL=https://mintline-eight.vercel.app npm run verify:live # against production
What a browser pass caught that nothing else did
Worth stating plainly, because it is the argument for doing it. Every functional gate was green - typecheck, lint, 151 tests, build, and 91 HTTP checks including full CRUD, the agent mutation and chain replay. The site was still shipping no stylesheet at all, because the rewritten layout.tsx never imported globals.css. It was a working product rendering as raw HTML.
Only driving a real browser surfaced it. Same pass found a hydration mismatch from typeof window in a server-rendered component, a 404 from <Link> RSC-prefetching a static file, and 1952px of horizontal overflow on mobile from unbreakable JSON. The Linux CI run then exposed a fourth: PGlite reaching into node:path with a URL from a different realm once the bundler inlined it.
Try it in ten seconds
Paste a mint on the landing page. Live chain data lands, the model loads in your tab, and the card is stamped with the verdict and the seal.
- No wallet. No API key. No signature. Only public chain state is read.
Built with Next.js 16, TypeScript strict, Tailwind v4, Neon Postgres, and transformers.js. MIT licensed.
Repo: https://github.com/aniruddhaadak80/mintline
Live: https://mintline-eight.vercel.app
My entry for the Hacktoberfest Open-Source AI Challenge: Week 1. Built for the theme that open-weight models should be able to do real work without asking anyone's permission or paying anyone for the privilege.
来源:Google AI:DEV 作者专属(RSS) · dev.to



