Guide

Lookups and views

get and requirePuzzle by identifier. selectPuzzles by collection and status. stats and the dataset snapshot with its deterministic data version.

By identifier

import { get, requirePuzzle } from "@agntn/puzzles";

await get("b1000/71"); // the puzzle, loading b1000 only
await get("gsmg"); // a singleton, the key is the id
await get("b1000/999"); // undefined
await requirePuzzle("b1000/999"); // throws PuzzleNotFoundError

get reads the collection key off the identifier, loads that collection, and asks it. A bad collection segment loads nothing. peter_todd/sha1 works, because the alias resolves before the load.

Inside a collection

import { b1000 } from "@agntn/puzzles/collections/b1000";
import { zden } from "@agntn/puzzles/collections/zden";

b1000.get(71); // NumericCollection takes numbers, or "71", or "b1000/71"
b1000.require(71); // throws when missing
zden.get("decred_janus"); // NamedCollection takes the name, or the full id
zden.requireId("zden/decred_janus"); // the full id on any collection

b1000.all(); // every puzzle, in list order
b1000.solved(); // status === "solved"
b1000.unsolved(); // status === "unsolved"
b1000.withPubkey(); // a public key is known
b1000.count(); // 256
b1000.solvedCount(); // 83
b1000.unsolvedCount(); // 77

Pick get when a miss is normal. Pick require when a miss is a bug. all() is a frozen array built once. solved(), unsolved() and withPubkey() filter it on every call, so keep the result if you loop.

Across collections

import { all, selectPuzzles, Status } from "@agntn/puzzles";

await all(); // 332 puzzles in manifest order, then list order
await selectPuzzles({ collection: "b1000", status: Status.Unsolved }); // 77
await selectPuzzles({ status: Status.Solved, withPubkey: true }); // every solved puzzle with a known public key

selectPuzzles with a collection loads that collection alone. Without one it loads everything. withPubkey: true keeps the puzzles whose public key is known. That's what a scanner wants: a public key turns a hash search into a discrete log search.

Statistics

import { collectionSummaries, stats } from "@agntn/puzzles";

await stats();
// {
//   total: 332, solved: 130, unsolved: 93, claimed: 11, swept: 96, expired: 2,
//   with_pubkey: 236,
//   total_prize: { AR: 5550, ETH: 14.1337, DAI: 100, BTC: 1058.06884913, LTC: 230.8255, DCR: 460 },
//   unsolved_prize: { AR: 1900, ETH: 1, BTC: 907.88195631 },
// }

await collectionSummaries(); // [{ key, author, total, solved, unsolved }, ...]

Prizes are summed per currency in whole units, the way the records write them, rounded to eight places. Nothing here is a balance. A swept puzzle's prize is what sat on the address when it was swept. An expired one's went back to the author.

The dataset snapshot

import { dataset, datasetCollections, dataVersion } from "@agntn/puzzles";

await dataVersion(); // "c8c77264fe07", the first 12 hex characters of SHA-256 over the serialized collections
await datasetCollections(); // [{ name, author, puzzles: [PuzzleData, ...] }, ...]
await dataset(); // { version, data_version, collections }

dataVersion() changes when a record changes and stays the same across runtimes. Cache a snapshot, compare it later, no build step. No timestamp in it, no environment data. puzzles export prints dataset(). That's what the JSON consumers of the old dataset read now.

const puzzle = await requirePuzzle("zden/decred_janus");

puzzle.explorerUrl(); // "https://dcrdata.decred.org/address/DsRaAja82UvgnqYaBHYFuyCKURFX2rCyEJ8"
puzzle.claimExplorerUrl(); // the claim transaction, when there's one

Explorer bases come from @agntn/chains: blockstream.info for Bitcoin, litecoinspace.org for Litecoin, etherscan.io, dcrdata.decred.org and viewblock.io for Arweave. Need a link for something that isn't a puzzle? addressExplorerUrl(chain, address) and transactionExplorerUrl(chain, txid) are exported too.

@agntn/puzzles·MIT license· Public data about public puzzles. Balances come from the chains' explorers through the worker, cached for five minutes. Every key here was public before it landed in a record.