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.
```minsc-exec linenums="1" source="tabs-below" $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); ```
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.