A follow-up to Universal Asset Protocol announcement
Whippetcoin Do Not Use Blockchain version 1.2.0 is available. This is a mandatory upgrade.
The original UAP post promised that “with OP_MINT and OP_INSPECT, you
actually can build token systems that enforce conservation and covenants at
the consensus level.” I’ve since then spent more time analyzing the code and the intent
and have made a new Whippetcoin release that makes this more true.
OP_MINT didn’t require a signature
I first implemented OP_MINT as a scriptPubKey opcode that validated its own
conditions (entry fee, salt length, overflow) and then unconditionally
succeeded without requiring any scriptSig requirement at all. In practice
that meant any real WHIP value locked in a mint output could be spent by anyone
who saw it, not just its intended owner.
Two of the five safety properties described in my original design doc were also unimplemented: “one-shot” (an input can’t already carry a UAP asset) and “strict script” (outputs must match an enforced template).
Why did this show up now? I spent some AI tokens to write better, more comprehensive end-to-end tests.
What changed
OP_MINT now requires the recipient’s signature. The script format gained
a recipient pubkey (<pubkey> <multiplier> <salt> OP_MINT), and spending now
requires a valid signature from that key, checked unconditionally. The core now
enforces encoding strictness for that signature and pubkey (DER form, low-S,
defined hashtype, pubkey format), rather than applying them only with the
policy SCRIPT_VERIFY_STRICTENC-style flags in place. Those flags govern
mempool-policy only, and they’re not required for consensus, so relying on them
here would have let a miner include a malformed-encoding signature or pubkey
directly in a block.
A new OP_MINT_TRANSFER opcode replaces the old, unenforced covenant
convention. Previously, “covenant” outputs were just a suggested script
pattern. Nothing forced a spending transaction to actually respect the
convention. Now, spending a OP_MINT/OP_MINT_TRANSFER position requires the
transaction to produce at least one continuing OP_MINT_TRANSFER output
carrying the same multiplier, with total output value bounded by the input’s
value. This strengthens the rule of token conservation.
One-shot enforcement is real, by checking that no sibling input in a mint transaction is itself an unspent UAP position. This was the second most invasive code change in this whole effort, extending the script-checker interface to see prevout scripts at all, plumbed through from the actual coins view at the validation call site.
Two independent mint lineages can’t be merged, and it costs nothing extra to prove it. This turned out to be a free consequence of how the conservation check works (it runs once per UAP input, each demanding the transaction’s total covenant-output value fit within that input’s own value) rather than something built and verified separately. Same-multiplier positions get scarce, traceable-to-a-single-mint identity without any token-ID bookkeeping.
Non-covenant outputs are now allowed alongside a covenant continuation. This is a relaxation of the rules needed to make an atomic token-for-WHIP swap possible in a single transaction (token input + buyer’s payment input → covenant to buyer + payment to seller + change). Verified this doesn’t reopen the merge-prevention property above.
Activation is height-gated. All of this used to be live from genesis with no activation mechanism at all. It now activates at block 80,000 on mainnet and testnet. Before that height, the opcodes fail closed, not silently continue under the old, unsigned behavior.
While I have no expectation that anyone will merge mine, I realized that the previous releases re-used Dogecoin’s merge mining chain ID, so I’ve corrected that at block 80,000 as well, bundling both changes into the same activation height.
Features Built on this Foundation
contrib/uap-js is a dependency-free JavaScript library for building and
signing UAP transactions client-side, in a browser or Node, with no build step.
It never talks to the network. Instead, you supply it UTXO details and it hands
you signed transaction hex.
contrib/uap-indexer is a small Go service and tiny HTTP API that watches
a node’s RPC and answers the question “which UTXOs are UAP positions”. It also
hosts a genuinely non-custodial order relay: makers sign standing sell orders
with SIGHASH_SINGLE|ANYONECANPAY (committing only to their own input and
their own payment, not the token’s eventual destination), and any taker can
fill one later with zero live coordination. The relay never holds funds or
keys, and independently-run instances can mirror each other’s order books with
no shared trust. Validation of mirrored orders operates exactly like
locally-submitted orders.
Docker image and operator’s guide is documentation for anyone who wants to
run their own indexer/relay instance. You need to know enough to use the
commands docker build and docker run and provide credentials via
environment variables.
How we know this actually works
I’ve tested every claim against a live whippetd on regtest, as well as via
unit tests in isolation: mint, transfer, wrong-signer rejection,
value-inflation rejection, an atomic swap, a maker/taker order filled by a
party with no back-channel to the maker, and cross-relay mirroring between two
independently-run indexer instances. This caught several real bugs.
If you’re running your own UAP tooling: this changes the mint script format,
requires a recipient pubkey where there wasn’t one before, and changes what a
valid spend of an existing OP_MINT output looks like. See
doc/uap-minting-guide.md for the updated format and
doc/uap-marketplace-design.md / doc/uap-marketplace-operators-guide.md for
everything built on top.