Conformance vectors, spec 1.0.0
Test vectors
Every byte on this page was produced by the reference OP_DROP encoder and verified by the reference decoder and the reference Taproot commitment check. Paste any leaf hex into the builder and decoder to reproduce the result in your browser.
These are documentation keys. The key pair below is published so the vectors are reproducible. Never send funds to any address on this page. Anyone can spend from them.
Shared setup
| Private key (documentation only) | 4654771a8e22773b5fd328d1ebad41f6c97f637e014984ae03a5d142bf51def1 |
|---|---|
| x-only public key | 8836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3b |
| Taproot internal key | the same x-only key |
| Script tree | single leaf, tapleaf version 0xc0, depth 0 |
| Network | mainnet (leaf bytes are identical on every network; only the address encoding differs) |
V. Valid leaves
V1. Deploy drop
| Payload | {"p":"op-drop","op":"deploy","tick":"drop","max":"21000000","lim":"1000"} |
|---|---|
| Payload bytes | 73 |
| Payload sha256 | f970d478e38939a89f6d9615aef772e21716dc79e2e752de1dd0539c553b74ca |
| Leaf script | 0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e7520f970d478e38939a89f6d9615aef772e21716dc79e2e752de1dd0539c553b74ca75497b2270223a226f702d64726f70222c226f70223a226465706c6f79222c227469636b223a2264726f70222c226d6178223a223231303030303030222c226c696d223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac |
| Leaf script bytes | 177 |
| Leaf script sha256 | 546e1624adf71006b54721e2a005d6c91af513e3e8b09497e3f19c5b0181d1ec |
| Commit scriptPubKey | 5120f865873be28e8ea28d0f6dd018b94a30ec17b569b2cac767eb7f7b5222e43805 |
| Commit address | bc1plpjcwwlz36829rg0dhgp3w22xrkp0dtfkt9vwelt0aa4yghy8qzsnqwgwm |
| Control block | c08836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3b |
| Reveal size estimate | 656 weight units, 164 vB (94 base bytes, 278 witness bytes) |
| Expected outcome | carrier valid; ledger valid if drop has no prior deployment on this network |
V2. Mint 1000 drop
| Payload | {"p":"op-drop","op":"mint","tick":"drop","amt":"1000"} |
|---|---|
| Payload bytes | 54 |
| Payload sha256 | 3c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912e1 |
| Leaf script | 0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e75203c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912e175367b2270223a226f702d64726f70222c226f70223a226d696e74222c227469636b223a2264726f70222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac |
| Leaf script bytes | 158 |
| Leaf script sha256 | f80ecba1d440272ecb76343680714a46c92be62e9a97760e700bccb3f5140bad |
| Commit scriptPubKey | 51209194a35d62f90d352729397e55a85100e092049ce27bcd7202c8388c63559d2c |
| Commit address | bc1pjx22xhtzlyxn2fef89l9t2z3qrsfypyuufau6uszequgcc64n5kqtlwnap |
| Control block | c18836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3b |
| Reveal size estimate | 637 weight units, 160 vB (94 base bytes, 259 witness bytes) |
| Expected outcome | carrier valid; ledger credits 1000 to the anchor address if drop is deployed and supply remains |
The control block for V2 begins c1 rather than c0 because the tweaked output key has odd parity for this leaf. Both are correct; the low bit of the first byte carries the parity.
V3. Transfer 250 drop
| Payload | {"p":"op-drop","op":"transfer","tick":"drop","amt":"250"} |
|---|---|
| Payload bytes | 57 |
| Payload sha256 | 090455d3d8b15ef3d38e202c8c13033362c58e961f078615a1f1f23df256c13e |
| Leaf script | 0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e7520090455d3d8b15ef3d38e202c8c13033362c58e961f078615a1f1f23df256c13e75397b2270223a226f702d64726f70222c226f70223a227472616e73666572222c227469636b223a2264726f70222c22616d74223a22323530227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac |
| Leaf script bytes | 161 |
| Leaf script sha256 | e57210d2444c8e6253da80594070177b0d6564248ff18a7b2881665933b2586e |
| Commit scriptPubKey | 51203cde155d12f33c25f52b796b8c924fb87cc69d41025782cfa877117596be7787 |
| Commit address | bc1p8n0p2hgj7v7ztaft094ceyj0hp7vd82pqftc9nagwught947w7rsvapwql |
| Control block | c18836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3b |
| Reveal size estimate | 640 weight units, 160 vB (94 base bytes, 262 witness bytes) |
| Expected outcome | carrier valid; ledger reserves 250 and opens a transfer against anchor {revealTxid}:0 |
V4. Largest possible deploy payload
Every field at its maximum: a four-character ticker with max and lim both at 264 minus 1. This is the upper bound on a token payload, and it is well below the 256-byte push ceiling.
| Payload | {"p":"op-drop","op":"deploy","tick":"zzzz","max":"18446744073709551615","lim":"18446744073709551615"} |
|---|---|
| Payload bytes | 101 |
| Payload sha256 | d8b26b33fd53926571adbf5ae1c5896662d431405b9ef917d6e3e299e13f51fc |
| Push encoding | OP_PUSHDATA1 (0x4c 0x65), because 101 is above 75 |
| Leaf script bytes | 206 |
| Expected outcome | carrier valid, ledger valid |
T. Commitment vectors
These use the V2 leaf and vary only the proof. They separate "this is not an OP_DROP leaf at all" from "this leaf did not belong to the output that was spent".
| # | Input | Expected result |
|---|---|---|
| T1 | V2 leaf, control block c18836…bf3b, previous output 51209194…9d2c | valid The leaf is committed by the spent output. |
| T2 | V2 leaf, V2 control block, previous output belonging to a different Taproot key | invalid_taproot_commitment Reason text: Taproot leaf does not commit to previous output. |
| T3 | V2 leaf, V2 control block, previous output 0014 followed by 20 zero bytes (P2WPKH) | invalid_taproot_commitment Reason text: previous output is not P2TR. |
| T4 | V2 leaf, control block with first byte changed to c2 | invalid_taproot_commitment Reason text: unsupported Taproot leaf version. |
| T5 | V2 leaf, control block of 65 bytes (a one-level tree path) | not an OP_DROP reveal The witness fails OD-3.2, so no event is recorded at all. |
| T6 | Witness with four items (signature, script, control block, annex) | not an OP_DROP reveal The witness fails OD-3.1. |
I. Invalid leaves
Each of these is a complete script hex. Paste any of them into the decoder to see the same message.
I1. Non-minimal push encoding
The V2 leaf with the 14-byte marker re-encoded using OP_PUSHDATA1 (4c 0e) instead of a direct push. Every field decodes identically. It is still invalid.
4c0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e75203c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912e175367b2270223a226f702d64726f70222c226f70223a226d696e74222c227469636b223a2264726f70222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rule OD-4.8. Not recorded as an event.
I2. Unknown carrier marker
The V2 leaf with the marker changed to bip110-op-drip.
0e6269703131302d6f702d6472697075106170706c69636174696f6e2f6a736f6e75203c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912e175367b2270223a226f702d64726f70222c226f70223a226d696e74222c227469636b223a2264726f70222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rule OD-4.1. Not recorded as an event.
I3. Digest does not match the payload
The V2 leaf with the final byte of the digest field changed from e1 to e0.
0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e75203c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912e075367b2270223a226f702d64726f70222c226f70223a226d696e74222c227469636b223a2264726f70222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rule OD-4.3. Not recorded as an event.
I4. Reordered payload keys
A well-formed leaf whose payload is {"op":"mint","p":"op-drop","tick":"drop","amt":"1000"}. The digest matches the payload; only the key order is wrong.
0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e75202da4f53ea09fdcfa8b20793398294870c00d671c7cd51cbeb949bbfdab3b35a175367b226f70223a226d696e74222c2270223a226f702d64726f70222c227469636b223a2264726f70222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rule OD-6.6. Not recorded as an event.
I5. Whitespace in the payload
Payload {"p": "op-drop", "op": "mint", "tick": "drop", "amt": "1000"}, 61 bytes instead of 54, with a matching digest.
0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e75206dabec6b4ddc3f46f53da8e34ad2f11544c82ec1d1b869b3e44fff35bb3c4280753d7b2270223a20226f702d64726f70222c20226f70223a20226d696e74222c20227469636b223a202264726f70222c2022616d74223a202231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rule OD-6.12. Not recorded as an event.
I6. Five-character ticker
Payload {"p":"op-drop","op":"mint","tick":"drops","amt":"1000"}.
0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e752004ae962007e5de7d7d56494e2181850272c6fb1168a672a86c03bd599e97d23375377b2270223a226f702d64726f70222c226f70223a226d696e74222c227469636b223a2264726f7073222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rule OD-6.5. Not recorded as an event.
I7. A conditional opcode in the grammar
The V2 leaf with the first OP_DROP (75) replaced by OP_IF (63). This is roughly what a witness envelope looks like at that position, and it is exactly what OP_DROP refuses.
0e6269703131302d6f702d64726f7063106170706c69636174696f6e2f6a736f6e75203c0153364dd98ded936f3d29a89959c6ca0e294540746e543037cbcfc33912e175367b2270223a226f702d64726f70222c226f70223a226d696e74222c227469636b223a2264726f70222c22616d74223a2231303030227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac
rejected Rules OD-4.6 and OD-4.9. Not recorded as an event.
I8. Carrier valid, ledger invalid
A deploy carrying self_mint. The leaf parses, the digest matches, the push encoding is minimal, and the Taproot proof would succeed. The ledger still refuses it.
| Payload | {"p":"op-drop","op":"deploy","tick":"demo","max":"21000000","lim":"1000","self_mint":"true"} |
|---|---|
| Payload bytes | 92 (encoded with OP_PUSHDATA1, 0x4c 0x5c) |
| Payload sha256 | b197c20f43a1d8cd3ca7fc7fe1c9c10328efaf4b8656d53f198a134774aa4e72 |
| Leaf script | 0e6269703131302d6f702d64726f7075106170706c69636174696f6e2f6a736f6e7520b197c20f43a1d8cd3ca7fc7fe1c9c10328efaf4b8656d53f198a134774aa4e72754c5c7b2270223a226f702d64726f70222c226f70223a226465706c6f79222c227469636b223a2264656d6f222c226d6178223a223231303030303030222c226c696d223a2231303030222c2273656c665f6d696e74223a2274727565227d75208836f3e74b35d5367eb26b762186393bad3cdf669c822772c0a0ee7398aebf3bac |
| Carrier result | valid |
| Ledger result | invalid reason unsupported_self_mint, recorded as an event, no balance change |
This is the case that shows why the two layers are specified separately. An implementation that only checks the carrier will report this as a successful deploy and be wrong.
L. Ledger sequences
Apply these in order on a fresh network. Each row is one event, in the ordering defined by OD-9.1.
| # | Event | Result | Credited | Minted after |
|---|---|---|---|---|
| 1 | deploy tick=test max=100 lim=30 | valid | - | 0 |
| 2 | deploy tick=test max=999 lim=1 | duplicate_deploy | - | 0 |
| 3 | mint tick=test amt=30 | valid | 30 | 30 |
| 4 | mint tick=test amt=31 | mint_limit_exceeded | 0 | 30 |
| 5 | mint tick=test amt=30 | valid | 30 | 60 |
| 6 | mint tick=test amt=30 | valid | 30 | 90 |
| 7 | mint tick=test amt=30 | valid, partial | 10 | 100 |
| 8 | mint tick=test amt=1 | supply_exhausted | 0 | 100 |
| 9 | mint tick=zzzz amt=1 | unknown_tick | 0 | 100 |
Event 7 is the case implementers most often get wrong. The request is 30, the remaining supply is 10, the request does not exceed lim, so the event is valid and credits 10. It does not fail.
X. Transfer sequences
Start with address A holding 1000 available units of test.
| # | Event | A available | A reserved | B available | Status |
|---|---|---|---|---|---|
| 0 | starting state | 1000 | 0 | 0 | - |
| 1 | reveal at A: transfer amt=250 | 750 | 250 | 0 | transfer_pending |
| 2 | anchor {tx1}:0 spent, output 0 pays B | 750 | 0 | 250 | settled |
| 3 | a second transaction also references {tx1}:0 | 750 | 0 | 250 | no event, already settled |
| # | Event | A available | A reserved | Status |
|---|---|---|---|---|
| 0 | starting state | 1000 | 0 | - |
| 1 | reveal at A: transfer amt=250 | 750 | 250 | transfer_pending |
| 2 | anchor spent, output 0 is an OP_RETURN | 1000 | 0 | invalid, invalid_transfer_destination |
| # | Event | Result |
|---|---|---|
| 1 | reveal at A: transfer amt=2000 while A has 1000 available | insufficient_available_balance |
| 2 | one transaction whose inputs 0 and 1 both carry valid transfer leaves | ambiguous_transfer_anchor on both. They would claim the same anchor, so neither is applied. |
| 3 | one transaction whose input 0 carries a transfer leaf and input 1 carries a mint leaf | The transfer applies normally and the mint applies normally. Only competing transfers are ambiguous. |
| 4 | a transfer whose reveal transaction has no output 0 address | invalid_anchor |
| 5 | at or above the configured activation height, a transfer whose transaction spends no other input with the same script as output 0 | missing_transfer_source_authorization |
Reproducing these
Every leaf script above is a pure function of its payload and the x-only key. To reproduce V2 by hand:
- Serialize the payload as compact JSON in the required key order and encode it as UTF-8. That is 54 bytes.
- Take its SHA-256 digest:
3c0153…12e1. - Concatenate: minimal push of
bip110-op-drop,75, minimal push ofapplication/json,75, minimal push of the 32-byte digest,75, minimal push of the 54 payload bytes,75, minimal push of the 32-byte key,ac. - The result is 158 bytes and must equal the hex in V2 exactly.
- Build the tapleaf hash at version
0xc0, tweak the internal key with it as the sole leaf, and the output key is9194a3…9d2c.
The builder performs steps 1 to 4 in your browser and shows each intermediate value.