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::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 an empty byte array), without consuming it
stack in: <n> stack out: <n> (or fail)
Minsc source code: src/stdlib/btc.minsc:139
Sort the top 2 stack elements (higher placed on top)
stack in: <a> <b> stack out: <a> <b> or <b> <a>
Minsc source code: src/stdlib/btc.minsc:142
OP::PICK_BOTTOM
Script
¶
OP::PICK_BOTTOM = `OP_TOALTSTACK OP_DEPTH OP_FROMALTSTACK OP_SUB OP_PICK`
PICK (copy) from the bottom of the stack (1 for the bottom-most stack element, not 0)
Minsc source code: src/stdlib/btc.minsc:129
OP::ROLL_BOTTOM
Script
¶
OP::ROLL_BOTTOM = `OP_TOALTSTACK OP_DEPTH OP_FROMALTSTACK OP_SUB OP_ROLL`
ROLL (move) from the bottom of the stack (1 for the bottom-most stack element, not 0)
Minsc source code: src/stdlib/btc.minsc:130
Shift the bottom-most stack element to the top of the stack
stack in: <a> <b> <c> <d> stack out: <b> <c> <d> <a>
Minsc source code: src/stdlib/btc.minsc:136
Verify that the two top stack elements are not equal
stack in: <a> <b> stack out: (none) (or fail)
Minsc source code: src/stdlib/btc.minsc:125
OP::๐ฏMUL
¶
OP::2MUL-OP::9MUL
MUL for small constant numbers, composed of OP_DUP/OP_ADD's
stack in: <x> stack out: <x*n>
Minsc source code: src/stdlib/btc.minsc:153
Script Macros¶
Loop Unrolling¶
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> unrollLoop(10, `OP_DUP 0 OP_GREATERTHANOREQUAL`, OP_1SUB)`
`
<5>
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_IF
OP_1SUB
OP_DUP
<0>
OP_GREATERTHANOREQUAL
OP_NOT
OP_VERIFY
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
`
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:171
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):
`
<0>
<5>
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_IF
OP_DUP
OP_ROT
OP_ADD
OP_SWAP
OP_1SUB
OP_DUP
OP_0NOTEQUAL
OP_NOT
OP_VERIFY
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_ENDIF
OP_DROP
`
Minsc source code: src/stdlib/btc.minsc:183
Control Structures¶
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:
`
OP_DUP
<0>
OP_EQUAL
OP_IF
OP_DROP
<0x022a46eb3296a185c5887405fe4ff8ff2cb5003980c624b173520cacb37e958e3d>
OP_CHECKSIG
OP_ELSE
OP_DUP
<1>
OP_EQUAL
OP_IF
OP_DROP
<0x627840>
OP_CHECKSEQUENCEVERIFY
OP_ELSE
OP_DROP
<0x034d14a48fa6c307d9c79e8a7c3164c6cb6279d2369cae32b4e1deebbb3c0b971c>
OP_CHECKSIG
OP_ENDIF
OP_ENDIF
`
Minsc source code: src/stdlib/btc.minsc:253
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`,
]
`
OP_DUP
<0>
OP_EQUAL
OP_IF
OP_DROP
<0x022a46eb3296a185c5887405fe4ff8ff2cb5003980c624b173520cacb37e958e3d>
OP_CHECKSIG
OP_ELSE
OP_DUP
<1>
OP_EQUAL
OP_IF
OP_DROP
<0x627840>
OP_CHECKSEQUENCEVERIFY
OP_ELSE
OP_DROP
<0x034d14a48fa6c307d9c79e8a7c3164c6cb6279d2369cae32b4e1deebbb3c0b971c>
OP_CHECKSIG
OP_ENDIF
OP_ENDIF
`
Minsc source code: src/stdlib/btc.minsc:270
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`,
]
`
OP_DUP
<0>
OP_EQUAL
OP_IF
OP_DROP
<0x022a46eb3296a185c5887405fe4ff8ff2cb5003980c624b173520cacb37e958e3d>
OP_CHECKSIG
OP_ELSE
OP_DUP
<1>
OP_EQUAL
OP_IF
OP_DROP
<0x627840>
OP_CHECKSEQUENCEVERIFY
OP_ELSE
OP_DROP
<0x034d14a48fa6c307d9c79e8a7c3164c6cb6279d2369cae32b4e1deebbb3c0b971c>
OP_CHECKSIG
OP_ENDIF
OP_ENDIF
`
Minsc source code: src/stdlib/btc.minsc:283
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`, `$bob OP_CHECKSIG` ]
`
OP_DUP
<0>
OP_EQUAL
OP_IF
OP_DROP
<0x022a46eb3296a185c5887405fe4ff8ff2cb5003980c624b173520cacb37e958e3d>
OP_CHECKSIG
OP_ELSE
OP_DUP
<1>
OP_EQUAL
OP_IF
OP_DROP
<0x627840>
OP_CHECKSEQUENCEVERIFY
OP_ELSE
<2>
OP_EQUAL
OP_VERIFY
<0x034d14a48fa6c307d9c79e8a7c3164c6cb6279d2369cae32b4e1deebbb3c0b971c>
OP_CHECKSIG
OP_ENDIF
OP_ENDIF
`
Optimized to a simple
OP_IF..OP_ELSE..OP_ENDIFwhen there are only 2 branches. This relies onMINIMALIFfor non-malleability, which is consensus-enforced in Taproot but only a standardness policy for Segwitv0/P2SH, whereOP::MINIMAL_BOOLis required to ensure non-malleability.
Minsc source code: src/stdlib/btc.minsc:293
(Alt)Stack Manipulation¶
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:134
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:133
PICK (copy) from the altstack, for statically known depth
Minsc source code: src/stdlib/btc.minsc:200
ROLL (move) from the altstack, for statically known depth
Minsc source code: src/stdlib/btc.minsc:196
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:213
ROLL (move) 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:207
Send multiple stack elements to 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:223
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:233
Drop num_elements from the stack, using the minimal number of OP_2DROP/OP_DROP's
Minsc source code: src/stdlib/btc.minsc:150
Drop num_elements from the altstack
Minsc source code: src/stdlib/btc.minsc:151
Native Opcodes¶
OP_PUSHNUM_1-OP_PUSHNUM_16
OP_PUSHBYTES_0-OP_PUSHBYTES_75
Alias of: OP_PUSHBYTES_0
Aliased as: OP_CHECKSEQUENCEVERIFY
OP_NOP1-OP_NOP10
OP_RETURN_187-OP_RETURN_254
Disabled Opcodes¶
Proposed Opcodes¶
Aliased as: OP_CHECKTEMPLATEVERIFY
Also see: the CTV reference