Why commit-first
A fair NFT drop has two opposing requirements: buyers must not be able to read which token IDs are rare during the mint (or they snipe them), but they must be able to confirm afterward that the rarity was not rearranged once the rare IDs were known. Commit-first resolves both:1
Commit
Before mint opens, the creator computes the provenance hash locally and writes it on-chain with
set_provenance_hash(hash). This is a one-way write. From this point the token-to-trait assignment is locked.2
Mint
The rarity-revealing per-token metadata stays held back during the mint. Buyers cannot read which IDs are rare.
3
Reveal
The creator publishes the byte-exact metadata the hash was computed from. The collection flips to revealed.
4
Verify (anyone, forever)
Recompute the hash from the now-public metadata and compare it to
get_provenance_hash(). A match proves the assignment is the one committed before mint.The hash
The provenance hash is a 64-character lowercase hex string, stored on the collection contract:- N is
max_supply, nottotal_minted. Every token JSON must exist before the hash can be set, so a collection cannot be frozen with metadata missing. - Hashes are over the exact stored bytes. No re-serialization, no field stripping.
ipfs://media is not byte-hashed (the CID inside the token JSON is already a content hash).https://media cannot appear in a frozen collection at all.- Avatar and banner are deliberately excluded; they are cosmetic and may be refreshed without breaking provenance.
Verification flow
An indexer or any third party verifies a collection like this:- Read
get_provenance_hash(). An empty string means not yet committed (no badge). - If a
collection.contract_addressis recorded, confirm it equals the deploying contract. A mismatch rejects the collection. - Recompute the hash from the public metadata per the canonical construction.
- Match and
mutability == "frozen_by_provenance"shows Provenance Verified. - A mismatch shows a Provenance Mismatch warning.
xpress verify <collection_address>).
Provenance covers source bytes. Composed pixel output is not hashed, because compositor implementations can differ; verifying a composed render’s pixels requires a stable compositor spec, which is a future extension.
