Welcome to Minsc¶
A mini scripting language, library and experimentation playground for Bitcoin ¶
Minsc is a high-level, domain-specific, embeddable language for Bitcoin scripting that simplifies the creation and fulfillment of complex spending conditions and transaction flows, using a simple, expressive, pseudo-code-like syntax.
The language is dynamically typed, functional and immutable. It can be run as a standalone program, or used as a library within an embedded host environment (currently JS/WASM or Rust).
Why Minsc?¶
- Learn Bitcoin concepts, data structures and contract design patterns
- Build & Prototype apps with advanced Bitcoin contracts and multi-transaction spending flows
- Integrate into your codebase as an embedded library (JS/WASM, Python or Rust)
- Communicate scripting ideas clearly and succinctly β for education, research and collaboration
- Experiment with new features, opcodes and covenant designs β like vaults, payment pools and more
- Inspect & Manipulate transactions, scripts, descriptors and other Bitcoin primitives on the live playground
Code Examples¶
// Generate address from wpkh() descriptor
$sk = xprv9s21ZrQH143K2oa8UwybFKopmuLYDP9Qsvs18L1r14f23cDbjhCon777JEE83Rp88h2fqqZdEem5uG2qN9bhRJyNJMZW5LNy8xXiq39LL8b;
$address = address(wpkh($sk/0'/0/0)); // first receive address at m/0'/0/0
// Create, sign, finalize & extract PSBT
$psbt = psbt[
"input": [
"prevout": b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c:1,
"utxo": wpkh($sk/0'/0/0):0.3 BTC,
],
"outputs": [
tb1qs2xpw2sc6vrl8u0x5mw2l9ff2tj4tsca82nq9w:0.0499 BTC,
wpkh($sk/0'/1/0):0.25 BTC, // change to m/0'/1/0
`OP_RETURN "Hello Minsc!"`:0,
],
];
$tx_signed = psbt::sign_extract($psbt, $sk);
$tx_hex = hex($tx_signed);
See the Simple Signing Recipe or explore the other Cookbook Recipes for more complete examples.
$alice_sk = xprv9s21ZrQH143K3cknSUWpHBYiMp2pzLsK2FnyvjQhTmAuDHJxjhbtgmRsfic8KGpfBhJK5TJ9TXj6QRCHhkaMYSKzfaLAp9REp6qHwQ9t7rq;
$bob_sk = xprv9s21ZrQH143K2ntP27nrDJrZAyCxR6eYbyoJ3YYmwFg7gGsck2gDychpPRjsFSJBjZ3ajDZaYRzJup3UvTWCTsQjxiUt9jESPpUwJb4wwt6;
$alice = pubkey($alice_sk), $bob = pubkey($bob_sk);
// Setup a wsh() descriptor for a 2-of-2 multisig
$multisig = wsh($alice/* && $bob/*);
$address = address($multisig/0); // first address at m/0
// Create PSBT spending from $address
$psbt = psbt[
"input": [
"prevout": a2877bd944be3433d5030ef102922e52f7c40de8b5ca26fa8b7c724d341e936e:1,
"utxo": ($multisig/0):0.5 BTC,
],
"outputs": [
tb1q3x0krlxcmnkfrc70x5xf5zluxtlddlu7dqepxa:0.4 BTC,
($multisig/1):0.099 BTC, // change back to multisig at m/1
],
];
// Sign, combine, finalize & extract
$psbt_signed = psbt::sign($psbt, $alice_sk) + psbt::sign($psbt, $bob_sk);
$tx_signed = psbt::finalize_extract($psbt_signed);
$tx_bytes = bytes($tx_signed);
$alice_sk = xprv9s21ZrQH143K3cknSUWpHBYiMp2pzLsK2FnyvjQhTmAuDHJxjhbtgmRsfic8KGpfBhJK5TJ9TXj6QRCHhkaMYSKzfaLAp9REp6qHwQ9t7rq // seckey
$bob_sk = xprv9s21ZrQH143K2ntP27nrDJrZAyCxR6eYbyoJ3YYmwFg7gGsck2gDychpPRjsFSJBjZ3ajDZaYRzJup3UvTWCTsQjxiUt9jESPpUwJb4wwt6 // seckey
$alice = xpub661MyMwAqRbcG6qFYW3peKVSuqsKPobAPUiaj7pK26ht65e7HEv9EZkMWyxXmEAXAK6uXBafzD7yNCS1FsGiHD3aQxiGhAtRfjtLLwadWUX // pubkey
$bob = xpub661MyMwAqRbcFGxr89KraSoHj13SpZNPyCitqvxPVbD6Z5CmHZzUXR2JEhdaiTsLbeet9tN4cUncZW4WqDb4MzyHgWix2VhTUhRygkDcFUr // pubkey
$multisig = wsh(and_v(v:pk(xpub661MyMwAqRbcG6qFYW3peKVSuqsKPobAPUiaj7pK26ht65e7HEv9EZkMWyxXmEAXAK6uXBafzD7yNCS1FsGiHD3aQxiGhAtRfjtLLwadWUX/*),pk(xpub661MyMwAqRbcFGxr89KraSoHj13SpZNPyCitqvxPVbD6Z5CmHZzUXR2JEhdaiTsLbeet9tN4cUncZW4WqDb4MzyHgWix2VhTUhRygkDcFUr/*))) // descriptor
$address = tb1qhreuv4em88l0xxrpwkpx50qtayx03d6gmw34wy7e3gr4acyxte7qxvjnx4 // address
$psbt = psbt [
"unsigned_tx": tx [
"version": 2,
"inputs": [
a2877bd944be3433d5030ef102922e52f7c40de8b5ca26fa8b7c724d341e936e:1
],
"outputs": [
tb1q3x0krlxcmnkfrc70x5xf5zluxtlddlu7dqepxa:0.4 BTC,
tb1q3tekx7lp00dkcc8mh5le03xrqkmeph4tu9valum6ut3d2zpey82qcglf3g:0.099 BTC
]
],
"version": 0,
"inputs": [
[
"witness_utxo": tb1qhreuv4em88l0xxrpwkpx50qtayx03d6gmw34wy7e3gr4acyxte7qxvjnx4:0.5 BTC,
"witness_script": `<0x02519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4> OP_CHECKSIGVERIFY <0x0203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63d> OP_CHECKSIG`,
"bip32_derivation": [
[45b0d775/0]0203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63d,
[2dc70085/0]02519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4
]
]
],
"outputs": [
[ ],
[
"witness_script": `<0x039327059020f4c03dbe8f2ed28709a90da55c2e3f0636a798565f9555bff04f55> OP_CHECKSIGVERIFY <0x02b1cce860e9285079bc59b61e35d07fc3a75f25ee74abdff1e6894fc9ade617e2> OP_CHECKSIG`,
"bip32_derivation": [
[45b0d775/1]02b1cce860e9285079bc59b61e35d07fc3a75f25ee74abdff1e6894fc9ade617e2,
[2dc70085/1]039327059020f4c03dbe8f2ed28709a90da55c2e3f0636a798565f9555bff04f55
]
]
]
] // psbt
$psbt_signed = psbt [
"unsigned_tx": tx [
"version": 2,
"inputs": [
a2877bd944be3433d5030ef102922e52f7c40de8b5ca26fa8b7c724d341e936e:1
],
"outputs": [
tb1q3x0krlxcmnkfrc70x5xf5zluxtlddlu7dqepxa:0.4 BTC,
tb1q3tekx7lp00dkcc8mh5le03xrqkmeph4tu9valum6ut3d2zpey82qcglf3g:0.099 BTC
]
],
"version": 0,
"inputs": [
[
"witness_utxo": tb1qhreuv4em88l0xxrpwkpx50qtayx03d6gmw34wy7e3gr4acyxte7qxvjnx4:0.5 BTC,
"partial_sigs": [
0203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63d: 0x30440220366da126306d2c66a06bfd94e29a8f61f1bb70ffe42971c73cae846f22dde55e022033c5b295a8d4aa824e04d82ee8853d11007e39d4df1844de8844cda8779d36a401,
02519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4: 0x3044022043560ce2b789b76137e6e86dfa5226f33a527f999a557cab62843c31edce03a402202d9731831ade857b46b01af2911adf75d332054072d31772c9cd666f89c6647101
],
"witness_script": `<0x02519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4> OP_CHECKSIGVERIFY <0x0203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63d> OP_CHECKSIG`,
"bip32_derivation": [
[45b0d775/0]0203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63d,
[2dc70085/0]02519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4
]
]
],
"outputs": [
[ ],
[
"witness_script": `<0x039327059020f4c03dbe8f2ed28709a90da55c2e3f0636a798565f9555bff04f55> OP_CHECKSIGVERIFY <0x02b1cce860e9285079bc59b61e35d07fc3a75f25ee74abdff1e6894fc9ade617e2> OP_CHECKSIG`,
"bip32_derivation": [
[45b0d775/1]02b1cce860e9285079bc59b61e35d07fc3a75f25ee74abdff1e6894fc9ade617e2,
[2dc70085/1]039327059020f4c03dbe8f2ed28709a90da55c2e3f0636a798565f9555bff04f55
]
]
]
] // psbt
$tx_signed = tx [
"version": 2,
"inputs": [
[
"prevout": a2877bd944be3433d5030ef102922e52f7c40de8b5ca26fa8b7c724d341e936e:1,
"witness": [ 0x30440220366da126306d2c66a06bfd94e29a8f61f1bb70ffe42971c73cae846f22dde55e022033c5b295a8d4aa824e04d82ee8853d11007e39d4df1844de8844cda8779d36a401, 0x3044022043560ce2b789b76137e6e86dfa5226f33a527f999a557cab62843c31edce03a402202d9731831ade857b46b01af2911adf75d332054072d31772c9cd666f89c6647101, 0x2102519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4ad210203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63dac ]
]
],
"outputs": [
tb1q3x0krlxcmnkfrc70x5xf5zluxtlddlu7dqepxa:0.4 BTC,
tb1q3tekx7lp00dkcc8mh5le03xrqkmeph4tu9valum6ut3d2zpey82qcglf3g:0.099 BTC
]
] // transaction
$tx_bytes = 0x020000000001016e931e344d727c8bfa26cab5e80dc4f7522e9202f10e03d53334be44d97b87a20100000000ffffffff02005a620200000000160014899f61fcd8dcec91e3cf350c9a0bfc32fed6ff9ee00f9700000000002200208af3637be17bdb6c60fbbd3f97c4c305b790deabe159dff37ae2e2d5083921d4034730440220366da126306d2c66a06bfd94e29a8f61f1bb70ffe42971c73cae846f22dde55e022033c5b295a8d4aa824e04d82ee8853d11007e39d4df1844de8844cda8779d36a401473044022043560ce2b789b76137e6e86dfa5226f33a527f999a557cab62843c31edce03a402202d9731831ade857b46b01af2911adf75d332054072d31772c9cd666f89c6647101462102519b05299ba4380f9158efb7eb053a9e5c4e559d6c49e1cc2bbf98c2503f06c4ad210203e1d6adb63bd3ef8fb92bb3b08cf1d243d999c819c84888469662eb280ce63dac00000000 // bytes
See the Simple Multisig Recipe or explore the other Cookbook Recipes for more complete examples.
// Create a Taproot tree with a CTV script leaf for each possible whitelisted destination address
$tr = tr(NUMS, [
`ctv::hash[ "output": tb1qtk006y5n5y3gljm8vfgfyjj9apuxfahncydrm5:0.01 BTC ] OP_CTV`,
`ctv::hash[ "output": tb1qs2xpw2sc6vrl8u0x5mw2l9ff2tj4tsca82nq9w:0.01 BTC ] OP_CTV`,
`ctv::hash[ "output": tb1qegulj3g6kjg4xslxsh8a6znv78czc993zfdrju:0.01 BTC ] OP_CTV`,
]);
// Funds sent to this address can only be spent to 1 of the 3 whitelisted destinations
$address = address($tr, signet);
// Spend to one of the whitelisted destinations
fn spend_to($prevout, $output) = tx[
"input": [
"prevout": $prevout,
"witness": tr::script_witness($tr, `ctv::hash[ "output": $output ] OP_CTV`),
],
"output": $output,
];
$tx = spend_to(
bb30697cc1444591e65482199b770ff0606895ab1ebee8791a04f6ac6da1e412:1,
tb1qs2xpw2sc6vrl8u0x5mw2l9ff2tj4tsca82nq9w:0.01 BTC
);
$tx_hex = hex($tx);
See the CTV Taproot Whitelist Recipe or explore the other Cookbook Recipes for more complete examples.
$alice = xprv9s21ZrQH143K3TMKbDNpCPQ9m97mb91sXS6KjrPewZuoeNbW2qk7N6QqT9bFpB1X6jhGS8NEBrMADdYZf8QfRMTcJZsfbokCCUyZ7SH8Mzy;
$bob = xprv9s21ZrQH143K3QE9eS1BpBMo44QjHMahavrB23JMyS1eRyij6rhYmq7C7vxZtBe3HUvCVrZcoDZ3vkPT4FxSJaLdyoodJYPzKBxVXRc42Ge;
$secret_preimage = 0x0101010101010101010101010101010101010101010101010101010101010101;
$secret_hash = hash::sha256($secret_preimage);
// HTLC policy in Taproot P2TR (two script leaves)
$redeem = pk($alice) && sha256($secret_hash);
$refund = pk($bob) && older(4 days);
$htlc = tr($redeem || $refund); // NUMS as the internal key
$address = address($htlc);
// Spend via the redeem path, signed by Alice and includes the $secret_preimage
$redeem_tx = psbt::sign_extract([
"input": [
"prevout": a0499e20c8def7c8f5b1c04db191a5fd9ee313300b76c1a63a8281d86c78cf48:1,
"utxo": $htlc:1.5 BTC,
"sha256_preimages": [ $secret_preimage ],
],
"output": wpkh($alice):1.499 BTC,
], $alice);
// Spend via the refund path, signed by Bob after a timeout
$refund_tx = psbt::sign_extract([
"input": [
"prevout": a0499e20c8def7c8f5b1c04db191a5fd9ee313300b76c1a63a8281d86c78cf48:1,
"utxo": $htlc:1.5 BTC,
"sequence": 4 days,
],
"output": tr($bob):1.499 BTC,
], $bob);
See the HTLC Recipe or explore the other Cookbook Recipes for more complete examples.