A proof you can recompute.
FirstProof v1 is a Memo-based Solana commitment/reveal protocol. It records evidence, not smart-contract-enforced protection. Devnet remains the default network. Mainnet creation and reveal are enabled by explicit operator choice despite incomplete live devnet validation. Mainnet transactions spend real SOL and are irreversible; enabling them is not evidence that the live wallet flow has been validated.
Current validation status
Deterministic hashing, browser-compatible base64url encoding, reveal reconstruction and resumption, duplicate-reference reconciliation, signature-account layout, transaction size bounds, privacy, missing-metadata behavior, wallet rejection, changed or invalid signatures, recovery-before-broadcast ordering, pending or failed transactions, and blockhash expiry have automated regression coverage. Mobile browser tests using explicitly synthetic fixtures cover recovery restoration, remaining-signature and fee review, wallet rejection, and pending-submission safeguards; these are not on-chain validation. Live devnet simulation successfully executes the commitment and reveal instructions without broadcasting. Finalized end-to-end wallet signing remains unvalidated because the devnet faucet rejected test funding. No successful on-chain test history is fabricated. Mainnet submissions have been enabled by explicit operator choice without completing this validation. Mainnet creation and reveal display a real-funds warning and require acknowledgement before signing.
1. Hash the exact artwork bytes
The browser computes SHA-256 over the original file bytes. Re-encoding, resizing, or changing image metadata changes this hash—even if the image looks identical. Artwork is not uploaded before reveal.
2. Construct the canonical manifest
All strings are trimmed and NFC-normalized before commitment. Names are limited to 32 UTF-8 bytes, tickers to 10 UTF-8 bytes, URLs to 160 characters, and description to 200 characters. Empty optional fields are empty strings, not null. Use lowercase hex for hashes. The manifest has exactly these keys, in exactly this insertion order, serialized by JSON.stringify without whitespace:
{"version":1,"name":"…","ticker":"…","mint":"…","artworkSha256":"…","website":"","x":"","description":""}Generate a 32-byte salt with crypto.getRandomValues. Encode it as 64 lowercase hexadecimal characters. It must never be reused. The exact commitment preimage is UTF-8, including the two literal NUL bytes shown below:
SHA-256(UTF8("FirstProof:v1" + "\u0000" + canonicalManifest + "\u0000" + saltHex))3. Record the commitment
A legacy Solana transaction includes a zero-lamport System Program transfer from the committing wallet to the public registry address, then a signed Memo. An optional disclosed creation-fee transfer may precede the Memo. The only account supplied to the Memo is the committing wallet, which must be the fee payer and sole transaction signer.
Memo program: MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr Registry: 2hUzxrennGfUeBFBzbXwWfdbYUQzBiqqZsqrRmGx6mUN Memo UTF-8: FP1:C:<64-lowercase-hex-commitment> Proof ID: base58 commitment transaction signature
The registry address is SHA-256(UTF8("firstproof:v1:registry")) interpreted as 32 public-key bytes. It holds no proof account state. Zero-lamport transfers make transactions discoverable by address; Memo accounts themselves cannot be non-signing index keys. The commitment does not publish the manifest, salt, or mint. The wallet, hash, slot, and available block time are public.
4. Preserve the recovery package
The JSON recovery package contains format "firstproof-recovery", version 1, the manifest, salt, network, committing wallet, commitment hash, and transaction signature. A draft downloaded before signing has a null transaction reference. A transaction-linked copy is made available immediately after signing and before broadcasting. Keep a second private backup. If you only have a draft, add the original signature from your wallet history. Losing the manifest or salt can prevent a reveal; FirstProof cannot recover them.
5. Publish a reveal after launch
The payload is JSON.stringify of an object with manifest first (using the canonical key order), then salt. UTF-8 payload bytes are split into contiguous 240-byte chunks. Each chunk is independently base64url encoded with no padding. The payload hash is SHA-256 over all original payload bytes. Each transaction has a signed Memo using:
FP1:R:<commitSignature>:<payloadHashHex>:<zeroBasedIndex>:<totalChunks>:<base64urlChunk>
Every reveal transaction includes zero-lamport transfers to the registry, the reveal index, and the now-public mint address. The reveal index is SHA-256(UTF8("firstproof:v1:reveal:" + commitSignature)) interpreted as 32 public-key bytes. At most 12 chunks are accepted. A reveal chunk must be finalized at or after the commitment slot. The wallet signs each transaction. Partial chunks become public immediately; closing the flow cannot retract them. To resume, restore the same recovery package and any downloaded signed-submission reference backup. The browser checks finalized chunks against the locally reconstructed payload hash, committing wallet, total count, index, and exact chunk-byte SHA-256. Only missing chunks are proposed, and the signature count and network-fee estimate cover only those chunks. Incomplete discovery blocks new signing rather than assuming nothing was published. Known signed submissions must finalize or, if absent from status history, pass their last-valid block height at finalized commitment before retrying. Finalized successful references must also appear in indexed reveal history before signing continues. Reference backups contain signatures and expiry heights, not private launch details; download them before reloading. Interrupted reveals require downloading the latest reference backup before closing the dialog, opening the receipt, or replacing the recovery package. The browser requests confirmation before reload or tab closure while signing or when interrupted references have not been downloaded; browsers may suppress that warning, so keep your own backup. Restored references are checked in batches of at most 12, and any pending or unavailable batch blocks new signing. Without a reference backup, inspect previous submissions in your wallet and wait for finalization. Duplicate chunk indices do not count twice.
6. Independently verify the evidence
- Fetch the commitment transaction at finalized commitment. Require non-null metadata, err = null, exactly one signer, one recognized Memo, and the registry discovery transfer. The Memo account must be the signing fee payer.
- Group finalized reveal chunks by payload hash, total chunk count, and revealing wallet. Require all zero-based indices, canonical base64url, 240 bytes in every non-final chunk, no chunk larger than 240 bytes, and at most 12 chunks. Reassemble and check the payload hash.
- Validate the strict payload schema and exact canonical JSON encoding. Recompute the salted commitment. Compare it with the commitment Memo. Compare the reveal signer against the commitment signer as a separate check.
- Resolve the committed mint on the selected network. Require an initialized SPL Token or Token-2022 mint. Resolve Metaplex metadata or supported Token-2022 metadata. Compare the current on-chain name and ticker, exact artwork-byte hash, website, and X URL independently.
- Report Match, Mismatch, Unavailable, or Not Revealed. Never treat missing fields as successful matches. "Launch commitment verified" requires commitment, reveal hash, wallet, mint, name/ticker, and artwork matches, plus matches for every optional social field that was committed.
Discovery and metadata limits
This MVP scans the latest 16 registry transactions for recent commitments, the latest 48 reveal-index transactions for reveal chunks, and the latest 32 mint-address transactions to discover proofs (up to four candidates). It is not a historical indexer. Old RPC data may be pruned. Missing discoveries never establish that no proof exists. Use the exact proof ID for direct lookup.
Off-chain resources are fetched only from HTTPS gateways on a fixed allowlist: ipfs.io, gateway.pinata.cloud, cloudflare-ipfs.com, arweave.net, gateway.irys.xyz, raw.githubusercontent.com, nftstorage.link, and subdomains of ipfs.dweb.link, mypinata.cloud, and nftstorage.link. Redirects are revalidated, intermediate response bodies are cancelled, and each resource has a single eight-second deadline across all redirect hops. JSON is capped at 1 MB and images at 10 MB, including streamed responses. Other hosts, missing fields, timeouts, unsupported metadata, or inaccessible resources are Unavailable. No visual-similarity claim is made.
Fees and safety boundaries
Public verification is free. Creation fees are configured in lib/config.ts and default to zero. When nonzero, the amount and recipient are shown before signing; network fees are separate. Reveals have no FirstProof fee and pay a network fee per transaction. No FirstProof token is required. Network-fee estimates are queried before signing; wallet simulations are the final transaction review.
A proof records what a wallet committed to and when. It does not establish brand ownership, guarantee originality, prevent copycats, certify token safety, reserve names or addresses, or independently verify launch-creator identity or that the actual launch occurred after the commitment. Block time is the RPC’s available estimate, not a browser timestamp. FirstProof does not launch tokens and has no Pump.fun partnership. Never supply a private key or seed phrase.