Skip to content

Script Opcodes & Macros

In addition to Bitcoin's native opcodes, Minsc also ships with some built-in composite opcodes for common multi-opcode operations, as well as function macros that generate dynamic Script.

Also see:

Composite Opcodes

Minsc's custom opcodes are prefixed with OP::, to differentiate them from native opcodes.

OP::NOT_EQ_VERIFY Script

OP::NOT_EQ_VERIFY = `OP_EQUAL OP_NOT OP_VERIFY`

Verify that the two top stack elements are not equal

stack in: <a> <b> stack out: (none) (or fail)

OP::MINIMAL_BOOL Script

OP::MINIMAL_BOOL = `OP_DUP OP_SIZE OP_EQUALVERIFY`

Verify that the top stack element is exactly 1 or 0 (0x01 or the empty byte-array 0x)

stack in: <n> stack out: <n> (or fail)

OP::PICK_BOTTOM Script

PICK (copy) from the bottom of the stack (1 for the bottom-most stack element, not 0)

OP::ROLL_BOTTOM Script

ROLL (move) from the bottom of the stack (1 for the bottom-most stack element, not 0)

OP::SHIFT Script

OP::SHIFT = `OP_DEPTH OP_1SUB OP_ROLL` // rollBottom(1)

Shift the bottom-most stack element to the top of the stack

Sort the top 2 stack elements (higher placed on top)

OP::𝘯MUL

OP::2MUL-OP::9MUL

MUL for small constant numbers, composed of OP_DUP/OP_ADD's

Minsc source code: src/stdlib/btc.minsc:N/A

Script Macros

Loop Unrolling

unrollLoop()

unrollLoop(max_iterations: Int, condition: Script, body: Script|Function) -> Script

Run the body script as long as the condition is met, up to max_iterations times. If max_iterations is reached but the condition is still met, execution fails.

The body can be a Script or a Function that takes the iteration count and returns a Script.

For example, this will count from <num> down to 0 (for numbers up to 10):

num = 5; // snip
`<num> unrollLoop(10, `OP_DUP 0 OP_GREATERTHANOREQUAL`, OP_1SUB)`

A more advanced example that sums the total inputs amount using the Liquid introspection opcodes is available here.

Minsc source code: src/stdlib/btc.minsc:N/A

unrollFor()

unrollFor(max_iterations: Int, body: Script|Function) -> Script

Pop the top stack element as the number of times to run the script body, up to max_iterations.

For example, this will sum the numbers between 1 and <num> (for numbers up to 10):

num = 5; // snip
`0 <num> unrollFor(10, `OP_DUP OP_ROT OP_ADD OP_SWAP`)`

Minsc source code: src/stdlib/btc.minsc:N/A

Control Structures

ifelseif()

ifelseif(Array<(Script|default):Script>) -> Script

Check a series of nested OP_IF..OP_ELSE conditions, running the script associated with the first match or the optional default branch. If there's no match and no default, execution fails.

Given an array of clauses, where each clause is a tuple of the Script checking the condition (or default), plus the Script to execute as the clause body.

For example, to match the number on the top of the stack and run some code accordingly:

ifelseif[
  `OP_DUP 0 OP_EQUAL`: `OP_DROP $alice OP_CHECKSIG`,
  `OP_DUP 1 OP_EQUAL`: `OP_DROP <6 months> OP_CSV`,
  default:             `OP_DROP $bob OP_CHECKSIG`,
]

Minsc source code: src/stdlib/btc.minsc:N/A

match()

Match the element at the top of the stack against the clauses and run the first match, keeping the item being matched around as necessary (without requiring manual OP_DUP/OP_DROP). If there's no match and no default, execution fails.

For example, this is equivalent to the ifelseif example above:

match[
  `0 OP_EQUAL`: `$alice OP_CHECKSIG`,
  `1 OP_EQUAL`: `<6 months> OP_CSV`,
  default:      `OP_DROP $bob OP_CHECKSIG`,
]

Minsc source code: src/stdlib/btc.minsc:N/A

switch()

switch(Array<(Value|default):Script>) -> Script

Match the item at the top of the stack for equality.

Given an array of clauses, where each clause is a tuple of the Value to match against (any Bytes-coercible) or default, plus the Script to execute as the clause body.

For example, this is equvalent to the ifelseif/match examples above:

switch[
  0: `$alice OP_CHECKSIG`,
  1: `<6 months> OP_CSV`,
  default: `OP_DROP $bob OP_CHECKSIG`,
]

Minsc source code: src/stdlib/btc.minsc:N/A

select()

select(scripts: Array<Script>) -> Script

Pop an index number off the stack and execute the scripts branch with that index.

Does not support a default branch.

This can typically be better accomplished with separate Taproot leaves for the script branches, but branching within a single Script may be preferable in some cases.

For example:

select[ `$alice OP_CHECKSIG`, `<6 months> OP_CSV` ]

Optimized to a simple OP_IF..OP_ELSE..OP_ENDIF when there are only 2 branches. This relies on MINIMALIF for non-malleability, which is consensus-enforced in Taproot but only a standardness policy for Segwitv0/P2SH, where OP::MINIMAL_BOOL is required to ensure non-malleability.

Minsc source code: src/stdlib/btc.minsc:N/A

(Alt)Stack Manipulation

pickBottom()

pickBottom(depth: Int) -> Script

PICK (copy) from the bottom of the stack, for statically known depth (1 for the bottom-most stack element, not 0)

Like OP::PICK_BOTTOM, but more weight-efficient when the depth is static.

Minsc source code: src/stdlib/btc.minsc:N/A

rollBottom()

rollBottom(depth: Int) -> Script

ROLL (move) from the bottom of the stack, for statically known depth (1 for the bottom-most stack element, not 0)

Like OP::ROLL_BOTTOM, but more weight-efficient when the depth is static.

Minsc source code: src/stdlib/btc.minsc:N/A

pickAlt()

pickAlt(depth: Int) -> Script

PICK (copy) from the altstack, for statically known depth

Minsc source code: src/stdlib/btc.minsc:N/A

rollAlt()

rollAlt(depth: Int) -> Script

ROLL (move) from the altstack, for statically known depth

Minsc source code: src/stdlib/btc.minsc:N/A

nPickAlt()

nPickAlt(max_depth: Int) -> Script

PICK (copy) from the altstack, using the number at the top of the stack as the depth (loop unrolled up to max_depth)

Minsc source code: src/stdlib/btc.minsc:N/A

nRollAlt()

nRollAlt(max_depth: Int) -> Script

ROLL (move) from the altstack, using the number at the top of the stack as the depth (loop unrolled up to max_elements)

Minsc source code: src/stdlib/btc.minsc:N/A

nToAlt()

nToAlt(max_elements: Int)

Send multiple stack elements the the altstack, using the number at the top of the stack as the number of elements to send (loop unrolled up to max_elements). nFromAlt() can be used to bring them back.

stack in: <el1> <el2> .. <elN> <N total> stack out: (none)
altstack out: <elN> .. <el2> <el1> <N total>

When the number of elements to send is static, this can be done much more efficiently using simple Script repetition, e.g. OP_TOALTSTACK*5

Minsc source code: src/stdlib/btc.minsc:N/A

nFromAlt()

nFromAlt(max_elements: Int) -> Script

Bring back multiple stack elements from the altstack, using the number at the top of the altstack as the number of elements to bring (loop unrolled up to max_elements). The opposite of nToAlt().

altstack in: <elN> .. <el2> <el1> <N total> altstack out: (none)
stack out: <el1> <el2> .. <elN> <N total>

When the number of elements to bring is static, this can be done much more efficiently using simple Script repetition, e.g. OP_FROMALTSTACK*5

Minsc source code: src/stdlib/btc.minsc:N/A

dropStack()

dropStack(num_elements: Int) -> Script

Drop num_elements from the stack, using the minimal number of OP_2DROP/OP_DROP's

Minsc source code: src/stdlib/btc.minsc:N/A

dropAlt()

dropAlt(num_elements: Int) -> Script

Drop num_elements from the altstack

Minsc source code: src/stdlib/btc.minsc:N/A

Native Opcodes

OP_PUSHNUM_𝘯 Script

OP_PUSHNUM_1-OP_PUSHNUM_16

OP_PUSHBYTES_𝘯 Script

OP_PUSHBYTES_0-OP_PUSHBYTES_75

OP_PUSHDATA𝘯 Script

OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4

OP_PUSHNUM_NEG1 Script

OP_0 Script

Alias of: OP_PUSHBYTES_0

OP_0NOTEQUAL Script

OP_1ADD Script

OP_1SUB Script

OP_2DROP Script

OP_2DUP Script

OP_2OVER Script

OP_2ROT Script

OP_2SWAP Script

OP_3DUP Script

OP_ABS Script

OP_ADD Script

OP_BOOLAND Script

OP_BOOLOR Script

OP_CHECKMULTISIG Script

OP_CHECKMULTISIGVERIFY Script

OP_CHECKSIG Script

OP_CHECKSIGADD Script

OP_CHECKSIGVERIFY Script

OP_CSV Script

Aliased as: OP_CHECKSEQUENCEVERIFY

OP_CLTV Script

OP_CODESEPARATOR Script

OP_DEPTH Script

OP_DROP Script

OP_DUP Script

OP_ELSE Script

OP_ENDIF Script

OP_EQUAL Script

OP_EQUALVERIFY Script

OP_FALSE Script

OP_FROMALTSTACK Script

OP_GREATERTHAN Script

OP_GREATERTHANOREQUAL Script

OP_HASH160 Script

OP_HASH256 Script

OP_IF Script

OP_IFDUP Script

OP_LESSTHAN Script

OP_LESSTHANOREQUAL Script

OP_MAX Script

OP_MIN Script

OP_NEGATE Script

OP_NIP Script

OP_NOT Script

OP_NOTIF Script

OP_NUMEQUAL Script

OP_NUMEQUALVERIFY Script

OP_NUMNOTEQUAL Script

OP_OVER Script

OP_PICK Script

OP_RESERVED Script

OP_RESERVED1 Script

OP_RESERVED2 Script

OP_RIPEMD160 Script

OP_ROLL Script

OP_ROT Script

OP_SHA1 Script

OP_SHA256 Script

OP_SIZE Script

OP_SUB Script

OP_SWAP Script

OP_TOALTSTACK Script

OP_TRUE Script

OP_TUCK Script

OP_VER Script

OP_VERIF Script

OP_VERIFY Script

OP_VERNOTIF Script

OP_WITHIN Script

OP_INVALIDOPCODE Script

OP_NOP Script

OP_NOP𝘯 Script

OP_NOP1-OP_NOP10

OP_RETURN Script

OP_RETURN_𝘯 Script

OP_RETURN_187-OP_RETURN_254

Disabled Opcodes

OP_CAT Script

OP_MUL Script

OP_DIV Script

OP_MOD Script

OP_2MUL Script

OP_2DIV Script

OP_OR Script

OP_AND Script

OP_XOR Script

OP_INVERT Script

OP_LSHIFT Script

OP_RSHIFT Script

OP_LEFT Script

OP_RIGHT Script

OP_SUBSTR Script

Proposed Opcodes

OP_CTV Script

Aliased as: OP_CHECKTEMPLATEVERIFY

Also see: the CTV reference

OP_CSFS Script

OP_PAIRCOMMIT Script

OP_INTERNALKEY Script

Elements/Liquid

OP_TWEAKVERIFY Script

OP_SHA256INITIALIZE Script

OP_SHA256UPDATE Script

OP_SHA256FINALIZE Script

OP_SUBSTR_LAZY Script

OP_DETERMINISTICRANDOM Script

64-bit Arithmetic

OP_SUB64 Script

OP_MUL64 Script

OP_NEG64 Script

OP_DIV64 Script

OP_ADD64 Script

OP_GREATERTHANOREQUAL64 Script

OP_LESSTHANOREQUAL64 Script

OP_LESSTHAN64 Script

OP_GREATERTHAN64 Script

OP_SCRIPTNUMTOLE64 Script

OP_LE64TOSCRIPTNUM Script

OP_LE32TOLE64 Script

Introspection

OP_INSPECTVERSION Script

OP_INSPECTLOCKTIME Script

OP_INSPECTNUMINPUTS Script

OP_INSPECTNUMOUTPUTS Script

OP_TXWEIGHT Script

OP_INSPECTINPUTASSET Script

OP_INSPECTINPUTISSUANCE Script

OP_INSPECTINPUTOUTPOINT Script

OP_INSPECTINPUTSCRIPTPUBKEY Script

OP_INSPECTINPUTSEQUENCE Script

OP_INSPECTINPUTVALUE Script

OP_PUSHCURRENTINPUTINDEX Script

OP_INSPECTOUTPUTASSET Script

OP_INSPECTOUTPUTNONCE Script

OP_INSPECTOUTPUTSCRIPTPUBKEY Script

OP_INSPECTOUTPUTVALUE Script