Provable Fairness
Pachiverse Machines is a generative collection of 500 NFTs on Polygon. This page explains — and lets anyone independently verify — that we did not and cannot manipulate what comes out of a pack.
Pachiverse Machines (PVM) is a generative collection of 500 NFTs on Polygon. This page explains — and lets anyone independently verify — that we did not and cannot manipulate what comes out of a pack.
It is written in two parts: a plain-language explanation, and a technical appendix with commands you can run yourself.
Nothing is drawn at the moment you open a pack. Both the contents of all 500 Machines and the pack-to-Machine assignment table were finalized and frozen before the reveal opened.
When we froze them, we published a SHA-256 fingerprint of each — a 64-character value computed from the entire data set.
| Commitment | SHA-256 | Frozen at |
|---|---|---|
| Artwork Commitment The artwork, rarity, and the eight trait layers of all 500 Machines, plus the SHA-256 of every image and metadata file |
024a9f74b6f2a695fd6f6a4afa35489dd0aa9fa2d9fcae0eae59a924342ea6da | 2026-09-06 00:05 JST (2026-09-05 15:05:48 UTC) |
| Note (re-commit on 2026-09-06): Before the reveal opened, the images and metadata of all 500 Machines were replaced with the final designs and the artwork manifest was regenerated. The Artwork Commitment was therefore updated from aacc48d0f736925054fd4f9e5acdb5299b3ba6f5830a81483a0daab59cc77efc (frozen 2026-09-02 08:30 JST) to the value above. The Allocation Commitment (which pack contains which Machine), the rarity of every Machine and every Machine name are unchanged. The previous hash is kept here for the record, and the base URI on the PVM contract was updated to the new metadata CID on the same day, before finalizeMinting() and freezeMetadata(). | ||
| Allocation Commitment Which pack contains which Machine, for all 500 packs |
87ebeb172cc6fa7004d664ef3922c06e034eada5ebadcaf4c1647d580f3208be | 2026-09-02 09:37 JST (2026-09-02 00:37:34 UTC) |
The assignment was derived from a fixed seed that was chosen and recorded before the commitment was frozen. That seed is now published in full, together with the manifests, so that the assignment can be reproduced from scratch:
Pachiverse_Pack_Reveal_v2026-03-25
All 500 Machines were minted on-chain before the reveal began. They are not minted on demand.
| Network | Polygon mainnet (chain ID 137) |
| Pachiverse Machines (ERC-721) | 0x55E3A05eaAc41aAeB596227CD4076e91033541b3 |
| Pachiverse Mystery Packs (ERC-1155) | 0x2B5DaC082f664986e77b4f075617D1908BBd109C |
| Image CID (IPFS) | bafybeiarlh4sssrtpvzrrgmrnfowfrcych22qryee6ngxvbqnvr56qca2y |
| Metadata CID (IPFS) | bafybeiazx7onunhlxvkxhfp4gv5iuvrqxzv3st6xfajrgjnebsoz2bkjwy |
What you get is not decided when you open a pack — the full assignment table was fixed before the reveal opened, and we published a SHA-256 fingerprint of that table at the moment we froze it. Changing even one character of the contents or the assignments would produce a completely different fingerprint, and matching the published one while altering the data underneath is not computationally feasible. The table itself is now published in full, so anyone can recompute the fingerprint and confirm that nothing was swapped in between. The table also identifies each pack by an anonymous, permanent reference rather than by its owner, so “give this particular Machine to this particular person” is not an operation the system can express in the first place — transferring a pack to a different holder does not change the committed hash at all.
The table also identifies each pack by an anonymous, permanent reference rather than by its owner, so “give this particular Machine to this particular person” is not an operation the system can express in the first place — transferring a pack to a different holder does not change the committed hash at all.
All 500 Machines break down as follows. This distribution is part of the frozen allocation data.
| Rarity | Total | Pool A (token 1101, 300 packs) | Pool B (token 1202, 200 packs) |
|---|---|---|---|
| R | 270 | 229 | 41 |
| SR | 120 | 40 | 80 |
| SSR | 60 | 20 | 40 |
| SSSR | 30 | 10 | 20 |
| UR | 15 | 1 | 14 |
| LEGEND | 5 | 0 | 5 |
| Total | 500 | 300 | 200 |
The five LEGEND Machines are one-of-one pieces, each with its own name.
- One Machine is assigned to you immediately. Its image, name, rarity, and traits appear on your member page right away.
- Your claim to that Machine is settled at that moment. It persists across reloads.
- The Machine is held on your behalf at this stage. It does not yet appear in your own wallet (MetaMask, OpenSea, and so on).
- To move it into a wallet you control, a separate withdrawal request is required. Withdrawal requests will open at a later date after launch; until then, Machines stay safely in the custody wallet and are fully visible on your member page.
- Opened packs are burned on-chain in periodic batches. Because batches run on a schedule, there is a delay — but your claim to the Machine is settled without waiting for the burn.
| Contract | Standard | Status |
|---|---|---|
| Pachiverse Machines (PVM) | ERC-721 | Verified |
| Pachiverse Mystery Packs | ERC-1155 | Verified |
| Companion NFT Collection | ERC-721 | Scheduled Q4 2026 |
Everything below can be done without trusting or querying our systems. The steps that use the seed and the full manifests are A.6 to A.8.
- A Polygon mainnet RPC endpoint (export POLYGON_RPC_URL=...)
- cast (Foundry), or any Web3 client
- Python 3, for recomputing hashes
- An IPFS gateway — the examples below use https://ipfs.filebase.io/ipfs/; substitute your own gateway or node
Both contracts are verified on Polygonscan.
- PVM (ERC-721): polygonscan.com/address/0x55E3A05eaAc41aAeB596227CD4076e91033541b3
- Mystery Packs (ERC-1155): polygonscan.com/address/0x2B5DaC082f664986e77b4f075617D1908BBd109C
Total supply minted — expected 500:
cast call 0x55E3A05eaAc41aAeB596227CD4076e91033541b3 "totalMinted()(uint256)" --rpc-url "$POLYGON_RPC_URL"
Token URI (<n> = 1..500) — expected ipfs://bafybeiazx7onunhlxvkxhfp4gv5iuvrqxzv3st6xfajrgjnebsoz2bkjwy/1.json:
cast call 0x55E3A05eaAc41aAeB596227CD4076e91033541b3 "tokenURI(uint256)(string)" 1 --rpc-url "$POLYGON_RPC_URL"
Two further locks are applied on a published schedule: finalizeMinting() was executed on 2026-09-08 (before the reveal opened), and freezeMetadata() follows on 2026-09-10 (after the first day of reveals has confirmed that images and metadata display correctly). Until each is executed, the corresponding call below returns false; afterwards it returns true permanently. If you read this page before 2026-09-10, metadataFrozen() may still return false. The base URI was updated on 2026-09-06 together with the artwork re-commit (see the note in the commitments table) and is committed by the Artwork Commitment above.
cast call 0x55E3A05eaAc41aAeB596227CD4076e91033541b3 "mintingFinalized()(bool)" --rpc-url "$POLYGON_RPC_URL"
cast call 0x55E3A05eaAc41aAeB596227CD4076e91033541b3 "metadataFrozen()(bool)" --rpc-url "$POLYGON_RPC_URL"
curl -sS https://ipfs.filebase.io/ipfs/bafybeiazx7onunhlxvkxhfp4gv5iuvrqxzv3st6xfajrgjnebsoz2bkjwy/1.json
Each metadata file contains name, a lore description, external_url, an image field of the form ipfs://bafybeiarlh4.../<filename>, and attributes covering Rarity plus eight trait layers: Background, Body, Frame, Reel, Light, Effect, Logo, Overlay.
Logo and Overlay are optional layers and are omitted for Machines that do not have them. The five LEGEND Machines additionally carry a Legend trait (the piece’s own name) and Edition: 1 of 1.
You can hash any file and compare it against the metadata_sha256 / image_sha256 recorded for the same token in the artwork manifest (A.6).
curl -sS https://ipfs.filebase.io/ipfs/bafybeiazx7onunhlxvkxhfp4gv5iuvrqxzv3st6xfajrgjnebsoz2bkjwy/1.json | shasum -a 256
Each commitment is the SHA-256 of one canonical JSON string — the manifest. The Artwork Commitment covers a manifest listing all 500 Machines (token id, serial, rarity, the eight trait codes, the image and metadata filenames, the SHA-256 of each file, and the IPFS URIs). The Allocation Commitment covers a manifest listing all 500 packs and the Machine each one contains.
Artwork Commitment = SHA256( compact_json(artwork_manifest) )
Allocation Commitment = SHA256( compact_json(allocation_manifest) )
Canonicalization is fixed in advance so the hash is reproducible: keys appear in a defined order, entries are sorted by a defined field, numbers and strings have defined types, and the JSON is serialized compactly — no whitespace, no newlines (separators , and :), with forward slashes unescaped and non-ASCII emitted as UTF-8 rather than \uXXXX. The complete rules, and the manifests themselves, are in A.6 below.
python3 -c "import json,hashlib;m=json.load(open('artwork-manifest.json'))['manifest'];print(hashlib.sha256(json.dumps(m,separators=(',',':'),ensure_ascii=False).encode('utf-8')).hexdigest())"
The result must equal the corresponding value in the commitments table above. The published file wraps the manifest in a small metadata envelope, so hash the inner manifest object rather than the whole file — see A.6. An important property: the allocation manifest identifies packs only by an anonymous, immutable reference. No user identity is included — so transferring a pack from our reserve to a member does not change the Allocation Commitment hash.
Opened packs are burned in batches via burnBatchFromCustody on the Mystery Packs contract. For Pool A (1101), remaining + burned = 300. For Pool B (1202), remaining + burned = 200. Because burns are batched, there is a lag between a reveal and its on-chain burn.
cast call 0x2B5DaC082f664986e77b4f075617D1908BBd109C "balanceOf(address,uint256)(uint256)" \
0x502cef1173c162a39d8b23fa69579d862c2c728a 1101 --rpc-url "$POLYGON_RPC_URL"
cast call 0x2B5DaC082f664986e77b4f075617D1908BBd109C "burnedOf(uint256)(uint256)" 1101 --rpc-url "$POLYGON_RPC_URL"
Both manifests are published here as downloadable JSON. Once you have the files, every step below runs offline — none of them queries our systems.
- pachiverse.com/transparency/allocation-manifest.json
The allocation manifest — all 500 packs and the Machine each one contains — with the artwork manifest carried alongside it under the artwork key. - pachiverse.com/transparency/artwork-manifest.json
The artwork manifest — all 500 Machines — on its own.
Each file is a small metadata envelope around the committed manifest. committed_at is UTC. The artwork key is present only in allocation-manifest.json; artwork-manifest.json has the same shape without it, and its manifest is the artwork manifest.
{
"disclosure": "full",
"committed_manifest_hash": "87ebeb17...",
"current_manifest_hash": "87ebeb17...",
"matches_commitment": true,
"committed_at": "2026-09-02 00:37:34",
"manifest": { ...allocation manifest... },
"artwork": {
"committed_manifest_hash": "024a9f74...",
"current_manifest_hash": "024a9f74...",
"committed_at": "2026-09-05 15:05:48",
"manifest": { ...artwork manifest... }
}
}
- Hash the inner objects, never the envelope. In allocation-manifest.json those are manifest (allocation) and artwork.manifest (artwork); in artwork-manifest.json it is manifest. The envelope fields are not part of either commitment.
- The files are distributed pretty-printed. The indentation and newlines you see are not part of the hash — re-serialize the inner object compactly, exactly as A.4 describes and as the rules below spell out, before hashing.
- matches_commitment is our computation. Do not rely on it — recompute it yourself.
python3 - <<'PY'
import json, hashlib
w = json.load(open("allocation-manifest.json"))
def h(m):
return hashlib.sha256(json.dumps(m, separators=(',', ':'), ensure_ascii=False).encode("utf-8")).hexdigest()
print("allocation:", h(w["manifest"]))
print("artwork: ", h(w["artwork"]["manifest"]))
PY
Expected — the two values in the commitments table at the top of this page:
allocation: 87ebeb172cc6fa7004d664ef3922c06e034eada5ebadcaf4c1647d580f3208be
artwork: 024a9f74b6f2a695fd6f6a4afa35489dd0aa9fa2d9fcae0eae59a924342ea6da
Python’s json.load preserves key order, so loading the published manifest and re-serializing it as above already satisfies the canonicalization rules. The full rules are below, for anyone rebuilding a manifest from scratch.
All six must match or the hash will not reproduce.
- Top-level keys in this fixed order: manifest_version, manifest_type, total, entries.
- entries sorted by erc721_token_id ascending.
- Each entry’s 17 keys in this fixed order: erc721_token_id, serial_no, rarity_code, background_code, body_code, frame_code, reel_code, light_code, effect_code, logo_code, overlay_code, image_filename, metadata_filename, image_sha256, metadata_sha256, ipfs_image_uri, ipfs_metadata_uri.
- erc721_token_id and serial_no are JSON numbers; the other 15 fields are JSON strings (logo_code / overlay_code are the empty string "" when the layer is absent).
- Serialized compact — no whitespace, no newlines (separators , and :).
- Forward slashes are not escaped, and non-ASCII characters are emitted as UTF-8, not \uXXXX.
- Top-level keys in this fixed order: manifest_version, seed, algorithm, assignment_mode, pool_specs, total, entries.
- entries sorted by public_pack_ref ascending.
- Each entry’s keys in this fixed order: public_pack_ref, pool_type, allocated_machine_id, allocated_erc721_token_id, rarity_code.
- allocated_machine_id and allocated_erc721_token_id are JSON numbers; the rest are JSON strings.
- Serialization follows rules 5 and 6 of the artwork manifest above.
Which serial number carries which rarity is fully determined by the published seed. The seed and the algorithm are recorded verbatim in the allocation manifest — this is the algorithm string exactly as it appears in the committed file:
"seed": "Pachiverse_Pack_Reveal_v2026-03-25",
"algorithm": "sort_key = sha256(seed | pool_type | rarity_code | index); ascending sort by sort_key, tie-break by rarity_code; queue_position = rank starting at 1; machine_id = erc721_token_id = serial_no. Allocation identity is public_pack_ref (immutable, holder-independent); entries are sorted by public_pack_ref."
In procedural form:
for each pool (A, B):
for each rarity and its count:
for i = 1..count:
sort_key = SHA256_hex(seed + "|" + pool_type + "|" + rarity + "|" + i)
sort the (sort_key, rarity) list ascending by sort_key, tie-broken by rarity_code
assign queue_position = 1, 2, 3, ... in that order
Pool A (token 1101) takes machine_id 1..300; Pool B (token 1202) takes 301..500.
machine_id = erc721_token_id = serial_no
The rarity produced here must match the rarity_code of the same erc721_token_id in the artwork manifest — for all 500 entries:
python3 - <<'PY'
import hashlib, json
seed = "Pachiverse_Pack_Reveal_v2026-03-25"
specs = {
"A": {"token_id": 1101, "rarities": {"R": 229, "SR": 40, "SSR": 20, "SSSR": 10, "UR": 1, "LEGEND": 0}},
"B": {"token_id": 1202, "rarities": {"R": 41, "SR": 80, "SSR": 40, "SSSR": 20, "UR": 14, "LEGEND": 5}},
}
machine_id = 1
out = {}
for pool_type, spec in specs.items():
rows = []
for rarity, count in spec["rarities"].items():
for i in range(1, count + 1):
key = hashlib.sha256(f"{seed}|{pool_type}|{rarity}|{i}".encode("utf-8")).hexdigest()
rows.append((key, rarity))
rows.sort(key=lambda r: (r[0], r[1]))
for pos, (_key, rarity) in enumerate(rows, start=1):
out[machine_id] = (spec["token_id"], pool_type, rarity, pos)
machine_id += 1
art = json.load(open("artwork-manifest.json"))["manifest"]["entries"]
bad = [e["erc721_token_id"] for e in art
if e["rarity_code"] != out[e["erc721_token_id"]][2]]
print("machines:", len(out), " mismatches:", len(bad))
PY
Expected:
machines: 500 mismatches: 0
The last check reads the two manifests against each other: every pack maps to exactly one Machine, no Machine appears twice, and the rarity recorded in the allocation manifest matches the rarity of that Machine in the artwork manifest.
python3 - <<'PY'
import json, collections
w = json.load(open("allocation-manifest.json"))
alloc = w["manifest"]
art = {e["erc721_token_id"]: e for e in w["artwork"]["manifest"]["entries"]}
assert alloc["total"] == 500 and len(alloc["entries"]) == 500
seen, counts = set(), collections.Counter()
for e in alloc["entries"]:
assert e["allocated_machine_id"] == e["allocated_erc721_token_id"], e
tid = e["allocated_erc721_token_id"]
assert tid not in seen, f"duplicate token {tid}"
seen.add(tid)
assert art[tid]["rarity_code"] == e["rarity_code"], (tid, e["rarity_code"])
counts[(e["pool_type"], e["rarity_code"])] += 1
print("unique tokens:", len(seen))
for k in sorted(counts):
print(k, counts[k])
PY
Expected: unique tokens: 500, and per-pool counts matching the rarity distribution table above — Pool A 229/40/20/10/1/0 and Pool B 41/80/40/20/14/5 for R / SR / SSR / SSSR / UR / LEGEND.
An important property, once more: the allocation manifest identifies packs only by public_pack_ref — an anonymous, immutable reference. No user identity is included, so transferring a pack from our reserve to a member does not change the Allocation Commitment hash, and “give this particular Machine to this particular person” is not an operation the committed data can express.
- Opening a pack is irreversible. A pack cannot be un-opened, and a reveal cannot be re-rolled.
- Withdrawal to your own wallet is irreversible. If you supply an incorrect destination address, we cannot recover, restore, or re-issue the NFT. Please verify the address yourself.
- Withdrawal is request-based and processed manually. It is not instant.
- No fees for members. Gas for the withdrawal transaction is paid by the operator’s custody wallet; we do not charge a withdrawal fee.
- Withdrawal requests open at a later date after launch, and each request is reviewed and approved by the operator before the transfer is sent.
- Images are stored off-chain on IPFS. Display may be delayed or temporarily unavailable depending on gateway conditions. Your ownership is not affected.
- We take no part in, and accept no responsibility for, secondary-market pricing or trading.
- Every value published on this page (SHA-256 commitments, CIDs, contract addresses) is frozen and will not change. Should circumstances ever require a change, we will disclose the change and the reason for it.
| Term | Meaning |
|---|---|
| SHA-256 | A one-way function producing a 64-character hex value. A single-bit change in the input produces a completely different output. |
| Commitment | Publishing only the SHA-256 of a data set up front. Releasing the data later and matching the published hash proves nothing was substituted. |
| Manifest | The full data set (500 Machines, or 500 packs) that the SHA-256 is computed over. |
| Seed | The fixed string used to derive the assignment. It was chosen before the commitment was frozen and is published on this page: Pachiverse_Pack_Reveal_v2026-03-25. |
| IPFS / CID | Distributed file storage, and the identifier for a set of files within it. The same CID always means the same content. |
| ERC-721 / ERC-1155 | NFT standards for one-of-a-kind items and for multi-copy items, respectively. |
| Burn | Permanently destroying a token. Here, applied to opened packs. |