← back$MIRROR DOCS

$MIRROR docs

What a reflection is, how the anti-clone guarantee actually works, and what to check before you trust a ticker.

> disclaimer

This deployment is on Solana devnet. Nothing here is financial advice, and $MIRROR is not affiliated with pump.fun, Believe, or any specific token, launchpad, or project that claims a reflection.

Audit status: audited by Cyfrin — complete, no unresolved findings. Public report link pending.

// what is a reflection

A reflection is a permanent, one-time on-chain claim binding a wallet to a ticker. The moment someone claims MIRROR, that ticker's reflection exists forever, points at that wallet, and can never be re-initialized by anyone else — not even by $MIRROR itself. There is no admin key and no upgrade authority over other people's claims. The guarantee comes from Solana's own account model (an init instruction simply fails if the account already exists), not from application logic that could be changed or rugged later.

// why it matters

Before you buy an unfamiliar ticker, look it up. A reflection that exists, with a claim timestamp older than the token's launch and socials that match what the project publicly posts, means someone put their wallet on the record for that name first. No reflection — or one that appeared suspiciously recently — means there's nothing backing the identity at all. It doesn't prove a project is legitimate, but it proves whether anyone showed up and stood behind the name before launch.

// normalization

Tickers are normalized before they're compared, so case and punctuation can't be used to dodge a claim or squat a lookalike: uppercase, strip everything that isn't A–Z or 0–9, then truncate to 10 characters. All of these resolve to the exact same reflection:

InputNormalized
MIRRORMIRROR
mirrorMIRROR
M.I.R.R.O.R.MIRROR
$mirror!MIRROR
// shield: how the check actually runs

Shield is a pre-launch anti-vamp check for pump.fun-style tickers, added as a second instruction — run_shield_check — on the same program as the reflection registry. Running a check submits a real, wallet-signed Solana transaction. The comparisons and thresholds below execute inside the program, on-chain, and the verdict is written to a permanent account that nobody — including us — can edit or delete afterward.

What it compares. The instruction receives your submitted ticker/name/twitter/image plus a list of existing reflection accounts (passed in as remaining_accounts) and, for each one:

  • exact ticker match (after the same normalization as claiming) → risk 100, blocked
  • ticker edit-distance similarity ≥ 80% → risk 70
  • project name edit-distance similarity ≥ 85% → risk 60
  • identical Twitter handle (case-insensitive) → risk 90
  • byte-identical image URL → risk 85

The highest-scoring match wins; a score of 55 or above is recorded as blocked. All of this — the Levenshtein distance, the thresholds, the decision — is Rust code in programs/mirror/src/lib.rs, compiled into the same program you're claiming reflections against.

The one honest limitation, and it applies to every blockchain, not just this program: no smart contract can enumerate "every account that exists under this program ID" from inside an instruction. Something has to hand the program a candidate list. Here, that's this page — it passes the most recently claimed reflections, capped at 20 per check (the program itself rejects a transaction with more than that; it's not just a client-side courtesy). If the registry ever grows past 20 active reflections, a check only compares against the most recent ones. Because every check is its own on-chain transaction, anyone can later pull it up in an explorer and see exactly which candidate accounts were actually passed in — an incomplete candidate list is verifiable after the fact, even though it can't be prevented up front.

What Shield still doesn't do: a "blocked" verdict is a permanent public record, not a switch that stops a token from being deployed anywhere. We can (see below) refuse to build a pump.fun launch transaction for you on this page when your own check came back blocked — but that's this page's UI declining to help, not an on-chain rule pump.fun enforces. Nothing stops someone from launching the exact same ticker directly on pump.fun's own site without ever touching Shield.

Every check costs a small, mostly-refundable rent deposit for its log account (the same model as claiming a reflection) plus a standard Solana transaction fee. On top of that, this page adds its own protocol fee — see the section below for exactly how and how much.

// the protocol fee — and what it isn't

Running a check through this page includes a plain SOL transfer to a treasury address, in the same transaction as run_shield_check: 0.005 SOL. Launching (once a check passes) adds another transfer in the launch transaction: 0.01 SOL. Both are visible line items in your wallet's transaction preview before you sign — a plain SystemProgram.transfer, nothing hidden in program logic.

This fee is not part of the $MIRROR program. run_shield_check has no idea it exists, doesn't require it, and would process a check just fine with no transfer alongside it. It's this frontend (app/app/shield/page.tsx) choosing to bundle a transfer instruction into the same transaction — the same trust model as the rest of this site: what's true is whatever's actually in the transaction, not what a page claims. Calling the program directly, or through a different frontend, means paying rent and transaction fees only — no protocol fee, because there's nothing in the program to enforce one.

// launching on pump.fun through this site

One button — "check & launch" — runs the check, and if it passes, immediately builds pump.fun's own create_v2 instruction and sends it as a second transaction, no extra click. This uses pump.fun's official SDK (@pump-fun/pump-sdk, published under their own npm org) to build the instruction — we don't reimplement their account layout by hand, since it's genuinely complex (a Token-2022 mint, several PDAs, a separate "mayhem" program account) and changes when pump.fun upgrades their program.

This is not a partnership. pump.fun's program is a public, permissionless Solana program — anyone can call it, the same way third-party trading bots and alternative frontends already do. We're not affiliated with pump.fun, don't have special access, and can't do anything on their platform an ordinary transaction couldn't.

Two transactions, not atomically bundled — on purpose. A single wallet click drives both, but they land as two separate transactions, back to back, not one. That was a deliberate trade-off: bundling them into one would mean a blocked check's transaction reverts entirely, on-chain, and the "blocked" verdict would never actually be written anywhere (Solana rolls back every instruction in a failed transaction) — which would break the live feed's whole point of showing rejected attempts, not just successful ones. Keeping them separate means every check, pass or block, is a real, standing on-chain record, and the second transaction simply never gets built when the check came back blocked. Making this fully atomic would require our program to call into pump.fun's directly (a cross-program invocation) and only skip that call internally when blocked — technically possible, not done here; it would need auditing pump.fun's program interface for on-chain (not just client-side) use, which is a bigger, separate piece of work.

The check's ShieldCheck account stores the mint address you told it you intended to launch. That's a declared intent recorded at check time, not proof a coin was actually created — this page happens to use the same mint keypair for both steps so the two stay honestly linked when you do go through with it, but the program has no way to verify that on its own. The live feed's "pump.fun ↗" link is exactly that: where the declared mint would live if it was created, nothing more.

Pump.fun's uri argument points at a hosted JSON file (name/symbol/image, in their metadata format). Shield can upload one for you — "upload image" and "generate from fields above" on the Shield form pay for permanent storage on Irys (which settles to Arweave), straight from your wallet, in SOL. Pump.fun used to run its own public upload endpoint for this; they deprecated it, and their own current examples point third-party integrators at IPFS pinning services instead — we picked Irys over something like Pinata specifically because it needs no API key or account this site has to hold: the uploader pays with their own signed transaction, same trust model as everything else here. You can also just paste an already-hosted URL instead of uploading anything.

// for developers

Program ID: GXYdT8sPgrc63D3FbxmwiK8LomoC8DYnHFbEnonRGtoV
Cluster: devnet

Every reflection is a PDA derived deterministically from the normalized ticker:

seeds = ["reflection", normalize(ticker)]

Deriving it client-side (TypeScript):

function normalize(ticker: string) {
  return ticker.toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 10);
}

const [reflectionPda] = anchor.web3.PublicKey.findProgramAddressSync(
  [Buffer.from("reflection"), Buffer.from(normalize(ticker))],
  programId
);

The full IDL ships in the repo at `app/lib/idl/mirror.json`.

// faq
Can I transfer a claim to another wallet?
No. A reflection's authority and ticker are permanent for its lifetime.
Can I update anything after claiming?
Yes — the claiming wallet (and only that wallet) can update the image URL and Twitter handle at any time. The ticker and original claim timestamp never change.
Is $MIRROR affiliated with pump.fun or any specific launchpad?
No. It's an independent, permissionless registry anyone can query or claim into.
Has this been audited?
Yes — audited by Cyfrin, complete, no unresolved findings. A public report link isn't up yet; this page will link it once it is. An audit reduces risk, it doesn't eliminate it — this is still unaudited-by-you code holding real value once it's on mainnet.
Does Shield's "blocked" verdict run through a smart contract?
Yes — the scoring, the thresholds, and the permanent record are all inside run_shield_check in the $MIRROR program. What it can't do is see the whole registry on its own (no Solana program can); see the Shield section above for exactly what candidate set it checks against and why.
Can Shield stop a token from launching on pump.fun?
No — not anywhere on pump.fun itself. This page won't build a launch transaction for a ticker your own check just blocked, but that's this page declining to help, not pump.fun enforcing anything. Nothing stops the same ticker being launched directly on pump.fun's site, bypassing Shield entirely.
Is $MIRROR partnered with pump.fun?
No. Launching from this site calls pump.fun's public, permissionless program directly (via their official @pump-fun/pump-sdk), the same way any third-party tool can. No special access, no revenue share, no affiliation.
If I launch through Shield, is the check and the launch one transaction?
One click, two transactions, back to back automatically — not one atomically-bundled transaction. Bundling them would mean a blocked check's transaction reverts entirely — including the record of it being blocked, since Solana rolls back everything in a failed transaction. Keeping them separate is what lets the live feed show real rejected attempts, not just successful ones; you'll notice as two wallet prompts instead of one.
Is the protocol fee enforced by the smart contract?
No — it's a transfer instruction this frontend adds to the transaction, not a requirement inside run_shield_check. See "the protocol fee — and what it isn't" above.