# How to verify the PCAT 702 draw Everything that decides which cat a payment gets is public. You need Python 3 (standard library only), the files in this folder and read access to a Parano1d block explorer. ## Files | File | What it is | |---|---| | `../pot.json` | The pot list: all 690 mystery cats plus the 8 direct Epics and 4 direct Ultra Rares, each with its on-chain metadata hash. The file is canonical JSON, so `sha256sum pot.json` prints the fingerprint. | | `../pot.pretty.json` | The same list, indented for reading. | | `sale.json` | The published rules: founder address, start block, prices, refund rule and the entropy parameters (K = 1, finality depth 24, drand quicknet, 1800 s margin). | | `draw.py` | The reference draw: pot list + payments in canonical order → assignments and refunds. Pure function, no network. | | `verify.py` | Reads the chain, resolves the entropy of every payment and runs `draw.py`. Compares with the published ledger if you give it one. | Fingerprint of the pot list: `e6b640206edf7f58092d891210987152f4409f2f230d1a98b9f3eb76373ed364` ## The draw in one paragraph Payments are taken in the order the blockchain commits them: block height, then position inside the block. For a payment in block P the seed is `SHA-256("PCAT702/draw/v1" ‖ lp(fingerprint) ‖ lp(txid) ‖ lp(hash of block P+1) ‖ lp(drand value))`, where `lp(x)` is the 4-byte big-endian length of `x` followed by `x`. The drand value is the randomness of the first [drand quicknet](https://drand.love) round whose time is at or after the timestamp of block P+1 plus 1800 seconds, so it does not exist yet when block P+1 is mined. The draw happens only once block P+1 has 24 blocks on top of it. From the seed, each cat index is taken by rejection sampling from a SHA-256 stream (no modulo bias) out of the cats still free, without replacement. 23 NOID per mystery cat (1 to 10 cats per payment), exactly 223 NOID for one of the remaining direct Epics, exactly 523 NOID for one of the remaining direct Ultra Rares. Any other amount, or a group that is already empty, is refunded minus the network fee. Native transactions towards the founder address are never payments: they are listed as 'unattributable' for manual handling, except the settlements of the founder's own buyback trades (trade batches whose trades all belong to the founder), which are ignored. If fewer cats are left than paid for, the remaining ones are drawn and the rest is refunded. ## Run it ``` python3 verify.py --config sale.json --pot ../pot.json --source explorer --published ledger.json ``` The tool refuses to run with a config or pot list that deviates from the published rules (you can override that with `--allow-nonspec` for experiments). Exit code 0 means every payment was recomputed and the ledger matches; 1 means the published ledger differs; 3 means it matches so far but some payments are still pending (not final yet) or need manual handling (native transactions to the founder address). For an independent anchor point the same command with `--explorer http:///api/v1` against your own node. ## Where the published files are The service publishes its results next to this folder on the website, refreshed about every two minutes: `/buyback/assets/data/ledger.json` (the ledger this tool compares against), `/buyback/assets/data/payments.json` (every payment it saw, including the ones still pending) and `/buyback/assets/data/collection/pot.json` (the pot list). Save `ledger.json` and pass it as `--published`. ## What the ledger contains For every drawn payment the ledger archives the hash of block P+1, the drand round and its value (`entropy` section), so the draw stays reproducible even if the drand network or the explorer disappear. `ledger_digest` is the SHA-256 of the canonical ledger body; `verify.py` recomputes it from the published body before comparing.