STATUS · Built and tested locally. The launch chain has no public node; a public devnet, pointcast-devnet-2, is open (no value is promised; it may reset, and a reset is dated and recorded, never silent). Mainnet anchoring waits on a funded key. First Mints mint on the devnet once its edition is open; the art certificates are rehearsals.

CHAIN · APP · TIME CAPSULES · PUBLIC DEVNET-2 · NO VALUE · MAY RESET, NEVER SILENTLY

Seal it now. Open it at a block you pick.

Write a message, choose how many blocks to wait, and seal it. The chain keeps only a commitment: a hash that fits your message and a secret salt, and nothing it could be read from. When the block comes, anyone holding your capsule file can reveal it, and it airs as a post of yours. Lose the file and it never opens.

devnet · no value · may reset. A reset erases every sealed capsule, sealed or not. It is dated and recorded, never silent, and it takes the commitments with it; your file would then name a capsule the devnet no longer has. A reset is dated and recorded, never silent: devnet-1 was reset on 2026-10-08 and its recording is still checkable at /chain/yard/devnet-1/, but no capsule survived it. A capsule is a commitment signed by a key, an accountable claim, not a promise that anyone will open it or that this devnet will last until it is due.

seal oneyour capsuleson the devnethow it worksin code

01 · SEAL · YOUR MESSAGE STAYS IN YOUR BROWSER · NOTHING IS SENT UNTIL YOU PRESS SEND

What should wait?

The page reads GET /status and GET /capsules once this section is on screen, then every twenty seconds while the tab is visible.

A capsule waits in blocks, not minutes. The devnet seals a block within a few seconds when something is posted and otherwise one every five minutes, so 100 blocks is anywhere from five minutes to eight hours. The page says what that looks like at the rate the devnet has been keeping, and at both extremes.

Reading the devnet…

Your devnet key

A key made here is a free account on the devnet. It signs the seal in this browser, and only the signatures leave it. It is a play key with no value: anyone who sees its 64 characters can sign as it, so never reuse a key you hold anywhere else.

One key, three apps: if you tick “Keep it on this device”, the Daily Mint, the Notary and Time Capsules all load this same key, so a stamp, a bid and a capsule signed here are linked to one account that anyone can read on the devnet. The 64 characters sit in this browser’s local storage, which every script on pointcast.xyz can read. Leave it unticked and the key lives in this tab only.

No key yet. Make one: it is a new devnet account, free.

Use a key you already have

Only a devnet key. It stays in this tab unless you tick “Keep it on this device”.

Nothing is sent yet.

02 · YOUR CAPSULES · THE FILES YOU HOLD

Capsules you can open.

A capsule you seal appears here. A capsule file someone gave you, or one you saved, can be added: the page checks that the file’s author, channel, title, message and salt hash to the capsule id it names, so a file whose message, title, salt, author or channel was changed is refused. The block it opens at and its wax seal are not part of that hash: where the devnet lists the capsule, the page shows the devnet’s numbers and says when the file differs.

    03 · ON THE DEVNET · EVERY CAPSULE STILL SEALED, AND THE ONES THAT HAVE OPENED

    What the devnet holds.

    Capsules sealed and not yet opened (the devnet never sends a message, a salt or a commitment)
    CapsuleWax sealChannelSealed byOpens atState
    Waiting for the first read.

    Opened capsules

    • Waiting for the first read.

    04 · HOW IT WORKS · AND WHAT IT IS NOT

    A commit and a reveal.

    1. You seal

      The page hashes your message with a random salt into one commitment and signs a seal_capsule transaction with your key. On chain go only the commitment, the channel, the block it may open at, and a short label for the wax seal. Not the message, and not the salt.

    2. You keep the capsule file

      The message and the salt stay in a small file the page hands you. Without it the capsule never opens. With it, anyone can read the message early, and anyone can open the capsule once its block comes.

    3. The block comes

      From the block you chose until the capsule lapses, anyone holding the file may open it. The devnet will not take an open before its block, so a message cannot be forced out early by the chain; but an open you send yourself too early would sit in the mempool in the clear, so the page refuses to send one.

    4. It airs

      Opening stores the message and reveals the salt in a signed open_capsule transaction. The chain checks they hash to the commitment, and the post airs as its author’s, on the channel you chose. A capsule opens once, and then it is public.

    What it is not

    • It is not encryption. The chain does not hide your message with a key; it holds a commitment that cannot be matched to the message without the salt, and the salt is 32 random bytes. Whoever has the file has the message.
    • It does not choose the moment. It chooses a block height, and the devnet decides how long a block takes.
    • It does not make anyone open it. A capsule nobody opens before it lapses is never revealed, and the chain forgets it.
    • It is not a promise. One server runs the devnet, it has no value, and it may reset. A reset is dated and recorded, and the capsules do not survive it.

    05 · THE SAME STEPS, IN CODE

    Seal and open from a terminal.

    Keep the SDK (pointcast-chain.js) beside this file and run it with Node 22 or newer. Any 64-hex seed is a devnet account. The open checks that the capsule is due before it sends anything.

    capsule.mjs · pins this devnet’s genesis

    // capsule.mjs · Node 22+ · keep pointcast-chain.js (the SDK) beside this file
    // usage: SEED=<64 hex> node capsule.mjs seal "a title" "the message" 20    (opens 20 blocks on)
    //        SEED=<64 hex> node capsule.mjs open capsule.json
    import { readFileSync, writeFileSync } from "node:fs";
    import * as pcc from "./pointcast-chain.js";
    const DEVNET = "https://pointcast-devnet.mhoydich.workers.dev", GENESIS = "a720735b473383057ee11e885b2d32e1565470612364f13c0265c1a1c66f4280"; // any ed25519 seed is a tz1 account
    const key = await crypto.subtle.importKey("pkcs8", new Uint8Array([...pcc.hexToBytes("302e020100300506032b657004220420"), ...pcc.hexToBytes(process.env.SEED)]), { name: "Ed25519" }, true, ["sign"]);
    const pub = { scheme: "ed25519", bytes: Buffer.from((await crypto.subtle.exportKey("jwk", key)).x, "base64url").toString("hex") };
    const me = pcc.tezosAddress(pub), chain = await pcc.connect(DEVNET, { expect: { genesisHash: GENESIS } });
    const post = (path, body) => fetch(DEVNET + path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) }).then((r) => r.json());
    const send = async (tx) => post("/tx", { tx, public_key: pub, signature: pcc.bytesToHex(new Uint8Array(await crypto.subtle.sign("Ed25519", key, pcc.hexToBytes(pcc.signingHash(tx, chain.domain))))) });
    const [cmd, a, b, c] = process.argv.slice(2);
    if (cmd === "seal") {
      const open_at = (await chain.status()).height + Number(c), cm = pcc.capsuleCommitment(chain.domain, { author: me, channel: "BOT", title: a, body_hash: pcc.bodyHash(b), media_uri: null });
      console.log("sealed:", (await send(pcc.buildTx("seal_capsule", { sender: me, nonce: await chain.nextNonce(me), channel: "BOT", commitment: cm.commitment, open_at, label: "sealed from a script" }))).tx_hash);
      writeFileSync("capsule.json", JSON.stringify({ capsule: cm.capsule, salt: cm.salt, title: a, body: b, open_at }, null, 2)); // keep it: without the salt it never opens
    } else {
      const f = JSON.parse(readFileSync(a, "utf8")), row = (await (await fetch(DEVNET + "/capsules")).json()).capsules.find((x) => x.id === f.capsule);
      if (!row || !row.due) throw new Error("not open yet (or not listed): it opens at block " + f.open_at); // sending early would burn the salt
      await post("/body", { body: f.body });
      const tx = pcc.buildTx("open_capsule", { sender: me, nonce: await chain.nextNonce(me), capsule: f.capsule, salt: f.salt, title: f.title, body_hash: pcc.bodyHash(f.body) });
      console.log("opened:", (await send(tx)).tx_hash);
    }