MezcalProtocol documentation

Walkthrough

Working with Mezcal

Four operations exist: etch an asset, mint from it, transfer balances, and burn. All four are the same Bitcoin transaction shape with a different JSON object in the OP_RETURN. This page walks each one, byte for byte.

The mental model

Mezcal balances live on transaction outputs, the same way satoshis do. Spending an output spends the balance sitting on it. What the transaction does next is decided entirely by the JSON in its OP_RETURN.

One pool

Everything meets in the middle

Balances from the inputs, a premine from an etching, and units from a mint all land in the same unallocated pool before anything is distributed.

One pass

Edicts run in order

Each edict moves an amount to one output. An amount of "0" means everything left. An amount larger than the pool is quietly reduced.

One sweep

The remainder always lands

Whatever the edicts did not move goes to the pointer output, or to the first non-OP_RETURN output. There is no implicit change.

That is the whole model. The rest is field names and limits, which the specification states rule by rule.

Etching an asset

An etching creates the asset and fixes its name, symbol, base-unit scale, premine, and mint terms. The asset's id is decided by where the transaction lands: block height and transaction index.

{"p":"mezcal","etching":{"mezcal":"agave-pot","symbol":"◉","divisibility":6,
"premine":"1000000000","terms":{"amount":"5000000","cap":"2100",
"height":[null,null],"offset":[null,1000]}}}

That object reads: an asset named agave-pot, six decimals, a premine of 1000 display units (1000000000 base units), mints of 5 display units each, at most 2100 mints, open from the etching block until 1000 blocks after it.

Size of the etching example above, as a single OP_RETURN output.
MeasureValue
JSON payload186 bytes
Output script189 bytes (OP_RETURN, a two-byte push prefix, payload)
Whole output198 serialized bytes: 8 for the zero value, 1 for the script length, 189 for the script

Things worth deciding before you sign an etching, because none of them can be changed afterwards:

  • Name. Lowercase letters, digits, and hyphens, at most 15 characters, and unique across the protocol. If someone else's transaction with the same name confirms first, yours silently does nothing.
  • Divisibility. 0 to 18. It fixes the base-unit scale forever.
  • Premine. It enters the pool of this same transaction, so decide which output receives it, with an edict using the self-reference id 0:0 or with a pointer.
  • Terms. "terms": null means the supply is the premine and nothing more will ever be minted.

Flex mints. Set terms.amount to "0" and give exactly one price term, and each mint produces as many units as the payment buys: floor(satoshis paid / price). A flex etching that also carries a cap, or more than one price term, is ignored entirely.

Minting

A mint names the asset by id. That is the whole payload:

{"p":"mezcal","mint":"899284:20"}

33 bytes of JSON, 35 bytes of script. The minted units go into the pool and then follow the same edict and pointer rules as anything else, so a mint with no edicts and no pointer lands on output 0.

A mint produces nothing, without any error, when any of these is true:

  • the id names no asset;
  • the asset is unmintable, or the mint window has not opened or has closed;
  • the cap is already reached;
  • the asset has price terms and this transaction does not pay every one of them in full;
  • the computed amount is zero, which is the usual outcome of underpaying a flex mint.

To mint an asset with price terms, add the payment outputs to the same transaction. Each price term names an address and a satoshi amount, and the sum of your outputs paying that address must reach it.

A priced mint transaction The transaction spends a funding input, pays the price address the required satoshis, writes the mint instruction into an OP_RETURN output, and receives the minted units on the first non OP_RETURN output. Input funding, in satoshis vout 0 your address, receives units vout 1 pay_to address, price in sats vout 2, OP_RETURN {"p":"mezcal","mint":...} terms checked amount computed The price must be paid in the same transaction that carries the mint instruction.
A priced mint is an ordinary payment with an instruction attached. If the payment falls short, the payment still happens and the mint does not.

Transferring

A transfer spends the outputs holding your balance and names where the units should land.

{"p":"https://mezcal.sh","edicts":[["899284:20","2500000000",0]],"pointer":1}

77 bytes of JSON. Read it as: send 25 display units of asset 899284:20 (which has 8 decimals) to output 0, and send everything left over to output 1.

The transaction that payload belongs to.
PositionContentsResult
vin 0Your output holding 100 units of 899284:20Pool starts at 10000000000 base units
vin 1A plain satoshi output for the feeCarries no Mezcal balance
vout 0The recipient's addressReceives 2500000000 base units
vout 1Your own change addressReceives the remaining 7500000000 by the pointer
vout 2OP_RETURN with the payloadCarries the instruction, holds no balance

Drop the pointer from that payload and the remainder still goes to output 0, the first non-OP_RETURN output, which is the recipient. That single omission hands your change to the person you were paying. It is the most expensive mistake in the protocol and it produces a perfectly valid transaction.

Fee inputs are dangerous. Any output you spend for the fee also spends whatever Mezcal balance sits on it. Select fee inputs that are known to be free of Mezcal balances, or add an edict that returns them. Core screens every candidate fee input against the Mezcal authority for exactly this reason, and refuses to build the transaction when the check cannot be answered.

Burning

There is no burn operation. Burning is a destination: an edict, or the remainder, sent to the OP_RETURN output.

{"p":"https://mezcal.sh","edicts":[["899284:20","1000000000",2]]}

If output 2 is the OP_RETURN output, that edict destroys 10 display units and the rest of the pool follows the remainder rule to output 0.

The other way to burn is by accident: a cenotaph. Any unreadable or invalid payload burns every Mezcal balance the transaction was spending. The cenotaph table lists all eight conditions, and the validator checks a payload against them.

Before you sign

  1. Decode the OP_RETURN yourself. It is UTF-8 JSON. Read it in your wallet's raw transaction view, or paste it into the validator.
  2. Check the asset id, not the name shown in an interface. block:tx is what the indexer keys on.
  3. Check the amount scale. Base units, not display units. Multiply by 10^divisibility.
  4. Check the output index of every edict against the output list you are actually signing, and confirm the index is not the OP_RETURN output unless you intend a burn.
  5. Check where the remainder goes. Pointer present? Which output is the first non-OP_RETURN one?
  6. Check the fee inputs for balances you did not mean to spend.
  7. Check the fee itself. A Mezcal payload is a normal Bitcoin output and pays normal fees; see the size and fee notes.

Support matrix

Only support that is visible in the org's own code is listed. Everything else is left out on purpose, including third-party wallets and marketplaces, which this repository cannot verify.

Mezcal support across Bitcoin Universe products, as declared in the Core protocol registry at backend/packages/ecosystem-contracts/lib/protocols.js.
SurfaceOperationStateGrounding
Core marketplaceView markets, collections, activity, transactionsSupportedDiscovery actions are the supported set of the Mezcal marketplace policy.
List, update listing, unlist, buy, settleRead-onlyThe policy sets availability to read-only. Mutations are declared unsupported until authoritative ownership, transferability, builder, signed-transaction validation, broadcast, settlement, and reorg recovery are deployed and proven.
Core walletView, send, receiveDeclaredThe wallet action set for Mezcal in the capability registry.
Inscribe surfaceEtch, mint, transferDeclaredThe inscribe action set for Mezcal in the capability registry.
Token explorer indexingAssets, deployments, mints, transfers, burns, holdersSupportedA Universe-operated Mezcal indexer publishes confirmed state, verified against Bitcoin Core block membership before publication. Coverage is reported as partial: there is no complete mempool feed.
Payment UTXO safetyRefuse to spend asset-bearing outputs for feesEnforcedEvery candidate fee input is classified against the Mezcal authority; an unavailable answer fails closed rather than spending the output.
Third-party walletsAnyNot claimedNot verifiable from this organization's code, so nothing is claimed here.

Bitcoin Universe also constrains the one Mezcal payload it builds for a purchase down to a single byte-exact form. That rule, and the ownership proof behind it, is documented in the reference.