Normative specification, version 1.0.0
OP_DROP specification
This document defines the OP_DROP carrier and the token ledger carried on it. Rules are numbered OD-x.y and are normative. Everything else on this page is explanation.
Status. Experimental. Bitcoin, on mainnet, testnet, signet, and regtest. The rules below match the reference implementation operated by Bitcoin Universe as of 2026-09-01. Where the carrier layer and the ledger layer disagree, both outcomes are stated, because a leaf can parse correctly and still change no balance.
1. Scope and layering
OP_DROP is specified in two layers. Implementations may adopt the carrier without the ledger, but the ledger is meaningless without the carrier.
- OD-1.1
The carrier layer defines a Taproot leaf script grammar that commits a payload to the blockchain. Its selector is the fixed ASCII string
bip110-op-drop. This string appears only inside the script; it is never a user-facing protocol name and is never serialized into the payload. - OD-1.2
The ledger layer defines what the carried payload means. Its public identifier is the JSON field
"p":"op-drop". This is the name that applications, routes, and users see. - OD-1.3
A leaf that satisfies the carrier layer but fails a ledger rule is recorded as an observed event with status
invalidand a reason. It changes no supply, no balance, and no holder count. - OD-1.4
OP_DROP does not require, propose, or depend on any change to Bitcoin consensus. It uses
OP_DROP(0x75) andOP_CHECKSIG(0xac) inside a BIP-341 script-path spend with a BIP-342 tapscript leaf. - OD-1.5
Each network is evaluated independently. A ticker deployed on one network establishes nothing on another.
2. Notation and terminology
| Term | Meaning |
|---|---|
| Leaf script | The tapscript revealed in a script-path spend, tapleaf version 0xc0. |
| Commit transaction | Any transaction creating the P2TR output that commits to the leaf. |
| Reveal transaction | The transaction that spends that output along the script path, exposing the leaf in its witness. |
| Anchor | Output index 0 of the reveal transaction, written {txid}:0. Its address owns the event. |
| Event | One accepted or rejected protocol action derived from one reveal input, or one transfer settlement. |
| Payload | The compact UTF-8 JSON object carried in script element 7. |
| Available | Confirmed units an address may spend into a new transfer. |
| Reserved | Confirmed units held by an unsettled transfer. The API field name is transferable. |
Byte values are hexadecimal. Sizes are in bytes unless a unit is given. "Must" and "must not" are requirements; a violation makes the described thing invalid.
3. Transaction anatomy
OP_DROP uses the commit and reveal pattern that Taproot script paths require. The commitment is created first as an ordinary payment, and the payload becomes visible only when that output is spent.
- OD-3.1
A reveal input's witness stack must contain exactly three items, in this order: a Schnorr signature of 64 or 65 bytes, the leaf script, and a control block. A witness with two items, four items, or a Taproot annex is not an OP_DROP reveal.
- OD-3.2
The control block must be exactly 33 bytes, and its first byte must not be
0x50. A 33-byte control block means the leaf is the only leaf in the tree, so the script tree has depth zero. - OD-3.3
The spent previous output must be a P2TR scriptPubKey: 34 bytes beginning
0x51 0x20. - OD-3.4
Output index 0 of the reveal transaction is the anchor. The address derived from its scriptPubKey is the owner of every event produced by that transaction. Outputs at index 1 and above have no protocol meaning.
- OD-3.5
A transaction may contain more than one reveal input. Each input that satisfies OD-3.1 through OD-3.3 produces its own event, and all of them share the same anchor and owner address.
- OD-3.6
A transfer settlement is signalled by spending the anchor outpoint
{revealTxid}:0. The settlement transaction requires no OP_DROP leaf. The address of its output 0 is the destination. No later output, no change output, and no witness-derived address may become the destination.
4. Leaf script grammar
The leaf script is a fixed sequence of ten elements. Nothing is optional, nothing may be reordered, and no alternate encoding is accepted.
PUSH "bip110-op-drop" <- 14 bytes, ASCII
OP_DROP
PUSH "application/json" <- 16 bytes, ASCII
OP_DROP
PUSH <sha256(payload)> <- exactly 32 bytes
OP_DROP
PUSH <payload> <- 1 to 256 bytes, UTF-8 JSON
OP_DROP
PUSH <x-only public key> <- exactly 32 bytes
OP_CHECKSIG
- OD-4.1
Element 1 must be a data push of the exact ASCII bytes
bip110-op-drop(14 bytes, hex6269703131302d6f702d64726f70). - OD-4.2
Element 3 must be a data push of the exact ASCII bytes
application/json(16 bytes). - OD-4.3
Element 5 must be a data push of exactly 32 bytes: the SHA-256 digest of the payload bytes in element 7. A mismatch invalidates the leaf.
- OD-4.4
Element 7 must be a data push of the payload. It must be valid UTF-8 and must satisfy section 6.
- OD-4.5
Element 9 must be a data push of exactly 32 bytes: an x-only public key.
- OD-4.6
Elements 2, 4, 6, and 8 must each be
OP_DROP(0x75). Element 10 must beOP_CHECKSIG(0xac). - OD-4.7
No data push may exceed 256 bytes.
- OD-4.8
Every push must use the shortest encoding for its length: a direct push opcode for 1 to 75 bytes,
OP_PUSHDATA1for 76 to 255 bytes,OP_PUSHDATA2for 256 bytes. A decoder must verify this by recompiling the leaf from its decoded fields and comparing the result byte for byte with the script it was given. Any difference invalidates the leaf. - OD-4.9
The script must contain no conditional opcode, no
OP_SUCCESSopcode, and no element beyond element 10, except the optional media attachment defined in section 12.
OD-4.8 is what makes look-alike scripts worthless. Re-encoding the same 14-byte marker with OP_PUSHDATA1 instead of a direct push produces a different script that fails the rebuild check, even though every field decodes identically.
5. Taproot commitment proof
A witness item that merely looks like an OP_DROP leaf proves nothing. The leaf counts only when the control block proves the spent output committed to it.
- OD-5.1
The leaf version is
0xc0. It is read ascontrolBlock[0] & 0xfeand must equal0xc0. - OD-5.2
Compute the BIP-341 tapleaf hash of the script at version
0xc0, derive the Merkle root from the control block path (empty, because the control block is 33 bytes), and tweak the internal key fromcontrolBlock[1..33]with that root. - OD-5.3
The parity of the resulting output key must equal
controlBlock[0] & 1. - OD-5.4
The x coordinate of the resulting output key must equal bytes 2 to 33 of the spent previous output's scriptPubKey. If it does not, the leaf did not belong to that output and the event is
invalid_taproot_commitment.
6. Payload encoding
The payload is a compact JSON object. Its exact bytes are the event: any change to spacing, key order, or value type produces a different, and almost always invalid, event.
- OD-6.1
The payload must be valid UTF-8 and must parse as a JSON object (not an array, not a scalar, not null).
- OD-6.2
Every value must be a JSON string. Numbers, booleans, nulls, arrays, and nested objects are rejected.
- OD-6.3
The field
pmust be exactlyop-drop. - OD-6.4
The field
opmust be exactlydeploy,mint, ortransfer. - OD-6.5
The field
tickmust match^[a-z0-9]{4}$: exactly four lowercase ASCII letters or digits. - OD-6.6
Keys must be exactly the set for the operation, in exactly this order. Extra keys, missing keys, duplicate keys, and reordered keys are all rejected.
Operation Required key order deployp,op,tick,max,limdeploywith self mintp,op,tick,max,lim,self_mintmintp,op,tick,amttransferp,op,tick,amt - OD-6.7
A field named
vis rejected outright. OP_DROP payloads carry no version field; the grammar itself is the version. - OD-6.8
Numeric fields (
max,lim,amt) must match^[1-9][0-9]*$: a positive base-10 integer string with no sign, decimal point, exponent, whitespace, or leading zero. Zero is not a valid value. - OD-6.9
maxmust not exceed 18446744073709551615 (264 minus 1).limandamtmust not exceed 340282366920938463463374607431768211455 (2128 minus 1). - OD-6.10
On
deploy,limmust not exceedmax. - OD-6.11
When
self_mintis present it must be the exact stringtrue. The carrier accepts it; the ledger profile in OD-8.7 rejects it. - OD-6.12
The payload bytes must equal the compact serialization of the parsed object with no whitespace outside string values. A decoder verifies this by re-serializing the parsed object and comparing it with the original bytes.
- OD-6.13
There are no decimals. All quantities are whole units and are transported and displayed as decimal strings so large values stay exact.
The three shapes, exactly as they appear on chain:
{"p":"op-drop","op":"deploy","tick":"drop","max":"21000000","lim":"1000"}
{"p":"op-drop","op":"mint","tick":"drop","amt":"1000"}
{"p":"op-drop","op":"transfer","tick":"drop","amt":"250"}
The largest possible deploy payload is 101 bytes and the largest possible transfer payload is 93 bytes, so a token payload never approaches the 256-byte push ceiling. That ceiling binds only on the media attachment in section 12.
7. Identifiers
- OD-7.1
A reveal event id is
{txid}:i{vinIndex}:w1, wherevinIndexis the zero-based input index carrying the leaf andw1is the witness position of the script. Example:a1b2…:i0:w1. - OD-7.2
A settlement event id is
{settlementTxid}:s{vinIndex}:{transferEventId}, wherevinIndexis the input of the settlement transaction that spent the anchor. - OD-7.3
An anchor is written
{txid}:{vout}andvoutis always 0 for a reveal. - OD-7.4
A deployment is identified by the pair (network,
tick). A display name such as$DROPis presentation only; the wire ticker is the identifier. - OD-7.5
Event ids are unique per network. An indexer must ignore a second observation of an id it already holds.
8. Operations
- OD-8.1
Deploy establishes the rules for one ticker: a maximum supply
maxand a per-mint limitlim. The first valid deploy for a ticker in ordering order wins. - OD-8.2
A later deploy for a ticker that already has a valid deployment is
duplicate_deploy. It cannot replace, extend, or amend the first deployment. - OD-8.3
An invalid deploy reserves nothing. The ticker remains available to a later valid deploy.
- OD-8.4
Mint requests
amtunits of a deployed ticker. Withremaining = max - mintedmeasured before the event:if amt > lim -> invalid, mint_limit_exceeded if remaining <= 0 -> invalid, supply_exhausted otherwise -> credited = min(amt, remaining)The credited amount becomes available balance at the anchor address. A mint that requests more than the remaining supply, but no more than
lim, is valid and receives the remainder. Mints after the supply reaches zero are invalid. - OD-8.5
A mint for a ticker with no valid deployment is
unknown_tick. - OD-8.6
Transfer is a two-stage operation described in section 10.
- OD-8.7
The ledger profile is narrower than the carrier. A payload whose
tickis not exactly four characters, whosemaxexceeds 264 minus 1, whoselimoramtexceeds 2128 minus 1, or whoselimexceedsmax, isunsupported_profile. A deploy carryingself_mintisunsupported_self_mint. There is no self-mint mode in this ledger.
9. Deterministic ordering
Two implementations must agree on which deploy wins, which mint takes the last of the supply, and which transfer settles first. Ordering is therefore total and fully determined by chain data.
- OD-9.1
Events are applied in ascending order of, in priority order: block height, then transaction index within the block, then operation index within the transaction.
- OD-9.2
The operation index is
phase × 1000000 + vinIndex × 1000 + witnessIndex. Phase 0 is a transfer settlement, phase 1 is a reveal leaf. Settlements therefore apply before reveals within the same transaction, so units arriving by settlement are usable by a later operation in that same transaction. - OD-9.3
Within a phase, ordering follows the input index, then the witness position.
- OD-9.4
Ordering never depends on wall-clock time, on the order in which an indexer discovered transactions, or on mempool arrival.
10. State transitions
Each address holds a per-ticker balance with two parts. total is always available + reserved and is never stored independently.
reserved are settlement to a destination or return to the sender.- OD-10.1
A valid mint adds its credited amount to
availableat the anchor address and adds the same amount to the deployment's minted supply. - OD-10.2
A transfer is valid only when the anchor address holds at least
amtinavailableat the moment the event is applied. Otherwise it isinsufficient_available_balance. - OD-10.3
On a valid transfer,
amtmoves fromavailabletoreservedat the sender, the event status becomestransfer_pending, and a transfer record is opened against the anchor. No recipient has received anything at this point. - OD-10.4
When the anchor outpoint is first spent in a confirmed transaction, the transfer settles. If that transaction's output 0 yields an address, the amount leaves the sender's
reservedand is added to the destination'savailable. The settlement event status issettled. - OD-10.5
If output 0 of the settling transaction yields no address (for example an
OP_RETURNor a script the network's address encoding cannot represent), the amount returns fromreservedtoavailableat the sender. The settlement event status isinvalidwith reasoninvalid_transfer_destination. Nothing is burned. - OD-10.6
Only the first confirmed spend of an anchor settles it. Later observations of the same anchor produce nothing.
- OD-10.7
An address is a holder of a ticker when its
availableorreservedbalance for that ticker is non-zero. An address with zero in both is not a holder. - OD-10.8
Invalid events never change any balance, any minted supply, or any holder count. They are recorded so the ledger is auditable.
Event statuses
| Status | Applies to | Meaning |
|---|---|---|
valid | deploy, mint | Every applicable rule passed and state changed. |
transfer_pending | transfer | Units are reserved and the anchor is waiting to be spent. |
settled | transfer_settle | Reserved units were credited to a destination. |
invalid | any | A required rule failed. A reason accompanies it. |
11. Invalid conditions
Every rejection carries exactly one reason code. These are the complete set.
| Reason | Layer | Exact condition |
|---|---|---|
invalid_taproot_commitment | Carrier | The control block does not prove the leaf belongs to the spent P2TR output: wrong leaf version, parity mismatch, or an output key that does not match the previous output. |
invalid_anchor | Carrier | A transfer whose reveal transaction has no usable output 0, or whose output 0 yields no address. |
ambiguous_transfer_anchor | Carrier | More than one otherwise-valid transfer leaf appears in the same transaction. They would all claim the same single anchor, so every one of them is rejected. Deploys and mints in the same transaction are unaffected. |
missing_transfer_source_authorization | Carrier | At or above the configured activation height, a transfer whose transaction does not also spend another input whose previous output script equals the anchor output script. This proves the sender controls the address the units are debited from. |
invalid_transfer_destination | Ledger | The anchor was spent, but output 0 of the settling transaction yields no address. Reserved units return to the sender. |
unsupported_profile | Ledger | A payload that parses as a carrier payload but breaks the ledger profile: a ticker that is not exactly four characters, or a value outside the ranges in OD-6.9, or lim greater than max. |
unsupported_self_mint | Ledger | A deploy carrying self_mint. |
duplicate_deploy | Ledger | A deploy for a ticker that already has a valid deployment on this network. |
unknown_tick | Ledger | A mint or transfer for a ticker with no valid deployment. |
mint_limit_exceeded | Ledger | amt greater than the deployment's lim. |
supply_exhausted | Ledger | Remaining supply is zero or less when the mint is applied. |
insufficient_available_balance | Ledger | The anchor address does not hold amt in available balance when the transfer is applied. |
invalid_bip110_transaction | Construction | The transaction breaks the reduced-data construction rules while a node reports those rules as enforced. Every event in that transaction, including any settlement, is invalidated. This reason is unreachable while the reduced-data deployment is inactive, which is its state on Bitcoin mainnet today. |
A script that fails section 4 or section 5 before any of the above is not recorded at all. It is not an OP_DROP event, it is an unrelated Taproot spend.
12. Optional media attachment
A deploy, and only a deploy, may append an image to the same leaf. The attachment uses the same push-then-drop pattern and is appended after OP_CHECKSIG.
PUSH "drops-media" OP_DROP
PUSH "op-drop-token-image" OP_DROP
PUSH <mime type, ASCII> OP_DROP
PUSH <sha256(image), 32 B> OP_DROP
PUSH <uint32 big-endian size, 4 B> OP_DROP
PUSH <chunk> OP_DROP (repeated)
- OD-12.1
An attachment may accompany only a
deploypayload. Attaching one to a mint or a transfer invalidates the leaf. - OD-12.2
The MIME type must be one of
image/png,image/jpeg,image/webp,image/gif, and the image bytes must begin with the file signature for that type. - OD-12.3
The image must be at least 17 bytes and at most 262144 bytes (256 KiB). The declared 32-byte digest and 4-byte size must both match the reassembled image.
- OD-12.4
Each chunk must be at least 17 bytes and at most 256 bytes. An encoder must not leave a final chunk shorter than 17 bytes; it must shorten the preceding chunk instead.
- OD-12.5
Every field and every chunk must be followed by
OP_DROP, so the attachment adds nothing to the stack either. - OD-12.6
The attachment does not change the token payload, the digest in element 5, or any ledger outcome.
A 256 KiB image needs at least 1024 chunks, each with its own push header and OP_DROP. At 256 bytes per chunk the attachment carries roughly 1.2 percent overhead in script bytes, and it makes the reveal transaction large. Attach a small image or none at all.
13. BIP-110 construction profile
BIP-110 is a published proposal for a temporary set of reduced-data consensus limits. It is marked complete as a document. It is not active on Bitcoin. OP_DROP is built to stay inside its limits so that the carrier would keep working if those limits ever applied. That is a design constraint, not a claim.
| # | Limit | OP_DROP construction |
|---|---|---|
| 1 | An output script is at most 34 bytes, or 83 bytes for an OP_RETURN output. | Every OP_DROP output is a 34-byte P2TR script. |
| 2 | Every witness argument and data push is at most 256 bytes. | OD-4.7 enforces exactly this bound. |
| 3 | Undefined witness versions and undefined tapleaf versions cannot be spent. | Witness version 1 and tapleaf version 0xc0 only. |
| 4 | No Taproot annex. | OD-3.1 requires exactly three witness items, which leaves no room for an annex. |
| 5 | A control block is at most 257 bytes. | OD-3.2 requires exactly 33 bytes, the minimum possible. |
| 6 | No OP_SUCCESS opcode. | The grammar admits only OP_DROP, OP_CHECKSIG, and data pushes. |
| 7 | No executed OP_IF or OP_NOTIF. | The grammar contains no conditional opcode at all, which is the difference from a witness envelope. |
- OD-13.1
When an indexer's Bitcoin node reports the reduced-data deployment as active for a block, and a transaction in that block breaks any of the seven limits, every OP_DROP event in that transaction is
invalid_bip110_transaction. - OD-13.2
When the deployment is inactive, which is the current state of Bitcoin mainnet, the seven limits are a construction policy only. They do not invalidate anything.
- OD-13.3
An indexer must not project state for a block whose reduced-data status it cannot determine. It must stop rather than guess.
A "BIP-110 ready" label in a Bitcoin Universe interface means the application is enforcing this construction profile before it shows activity. It does not mean BIP-110 is active, that a transaction will relay or be mined, or that another wallet or indexer recognises OP_DROP.
14. Conformance
An implementation conforms when it produces the same accept or reject decision, the same reason code, and the same resulting balances as the rules above, for every case on the test vectors page.
- OD-14.1
An encoder conforms when, for any payload it emits, recompiling the leaf from its decoded fields reproduces the same bytes (OD-4.8), and the digest in element 5 matches element 7.
- OD-14.2
A decoder conforms when it rejects every invalid vector for the stated reason and accepts every valid vector with the stated fields.
- OD-14.3
An indexer conforms when it additionally applies sections 9 and 10 in order and reaches the same balances, minted supply, and holder counts from the same chain.
- OD-14.4
An implementation must not derive OP_DROP state from an Ordinals or BRC-20 index. The two are unrelated records.
Relationship to BRC-20
The ledger deliberately borrows accounting ideas that BRC-20 popularised: four-character tickers, first valid deploy wins, a per-mint limit, a partial final mint that receives the remainder, and a two-stage transfer. BRC-20 originated outside Bitcoin Universe. OP_DROP is not BRC-20, produces no Ordinals inscription number, and has no automatic interoperability with either system. The carrier, the identifiers, and the transfer settlement mechanism are OP_DROP's own.