GL-36

Provenance and entropy

How a GL-36 collection fixes its content without a secret, and why neither collectors nor the creator can pick tokens in advance.

GL-36 doesn’t store metadata. A token’s content is computed off-chain by a generator — deterministic code published by the creator — from a seed that only exists once the mint is over. Three header fields make this verifiable, and none of them is secret.

Field Set at Purpose
generator_hash init sha256 of the generator. Pins the code that turns seeds into content.
close_slot mint closes The slot in which the mint closed. The entropy comes from a slot after it.
entropy settle The hash of the first slot at or after close_slot + 32, read from the SlotHashes sysvar.

Token seed

The program stores the inputs; the seed is a convention between the generator and the front ends that run it. Once the collection is settled, the seed of token id is

seed(id) = sha256(domain ‖ collection ‖ entropy ‖ id as u16 little-endian)

domain is a string fixed by the generator, such as "genloss/v1". collection is the 32-byte account address. The generator turns the seed into content; nothing else goes in.

Why this is fair

  • Nobody can choose. When the mint closes, the slot whose hash becomes the entropy hasn’t been produced yet. The last minter, the creator and everyone else learn the art at the same moment, after every id already has an owner.
  • Nothing can leak or get lost. There is no secret to commit to, keep offline or publish later. A collection can’t be stuck unrevealed because a key is gone.
  • The code can’t change. generator_hash is fixed at init. Anyone can hash the published generator and compare.

The one party that touches the entropy is the validator that produces the target slot: its hash depends on the block it builds. Steering that hash toward a chosen piece would mean building and discarding many blocks within one 400 ms slot.

Lifecycle

  1. init — the creator stores the generator’s hash as generator_hash.
  2. mint — tokens are minted. Content can’t be computed yet; front ends show a placeholder.
  3. close — the last mint that reaches max_supply sets CLOSED and records close_slot. The creator can close early with close, which also lowers max_supply to minted.
  4. settle — once slot close_slot + 32 has passed (about 13 seconds), anyone calls settle. It writes the entropy and sets SETTLED. From then on every token’s content is fixed.
import { settleIx } from "@gl-36/sdk";

await send(anyone, [settleIx(PROGRAM, COLLECTION)]);

SlotHashes keeps the last 512 slots, about three and a half minutes. If the target slot has already dropped out when settle runs, it re-arms instead: it moves close_slot to the current slot and logs rearm. Call settle again 32 slots later. A front end can settle as soon as it sees a closed collection.

Generators

A generator is any deterministic program — JavaScript, WebAssembly, a shader — that maps a 32-byte seed to content. To be verifiable it must produce identical output on every machine:

  • No Math.random, no time, no network, no fonts, no Intl.
  • No floating-point functions whose results differ between engines — Math.sin, cos, exp, pow, log, sqrt. Use tables and integer arithmetic.
  • No canvas or GPU in the computation itself; draw only the finished pixels.
  • Define a canonical output — for images, sha256 of the raw pixels — and publish test vectors for a few ids.

Serve the generator byte-for-byte as published so that front ends can hash it and compare with generator_hash.

Esc

Suggested