Skip to content

shesek/minsc

Repository files navigation

Build Status crates.io npm MIT license Pull Requests Welcome

Minsc

A mini scripting language for all things Bitcoin

Minsc is a high-level, domain-specific, embeddable language for Bitcoin scripting that simplifies the creation and fulfillment of complex spending conditions using an expressive pseudo-code-like syntax.

It features built-in support for Descriptors, Miniscript, Script, Transactions, PSBT, Taproot, Xpubs/Xprvs, CTV and more.

The language is dynamically typed, functional and immutable.

Note

The documentation and playground on the min.sc website are currently outdated.

To explore some of Minsc's new abilities, check out the min.sc/v0.3 playground and the following examples:

Descriptors, Miniscript & PSBT

Manual Scripting

Without Descriptors, Miniscript or PSBT

Advanced Scripting

Elements/Liquid Introspection

To learn more about the language internals, you can also check out the Minsc standard library parts implemented in Minsc:

Local installation

Install Rust and:

$ cargo install minsc

# Execute a minsc file
$ minsc examples/htlc.minsc

# Execute from stdin
$ echo 'pk(d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c) && older(1 week)' | minsc -

# Dump AST
$ minsc examples/htlc.minsc --ast

Using the Rust API:

use minsc::eval;

let code = "pk(d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c) && older(1 week)";
let res = eval(&code).unwrap(); // a minsc::Value
println!("{}", res);

// Extract the miniscript::Policy
let policy = res.into_policy().unwrap();

Full documentation for the Rust API is available here.

JavaScript WASM package

Install with npm install minsc and:

import m from 'minsc'

// A multisig between Alice and Bob
const alice_pk = 'xpub661MyMwAqRbcFjVEmr9dDxeGKJznf41v5bEd83wMwu7CJ6PFeqJk3cSECPTh6wzsh32xceVsPvBgJ1q3Cqqie2dvH9nMFdL5865WrtRNhiB'
    , bob_pk = 'xpub661MyMwAqRbcFG1mzmcbw7oZss2Fn9y3d27D1KVjyKQdYGqNsZ8nSvLSexZAtkCNwvhFrAkTWAixvN9wjmnLNR22EsQczTiKccAJoLYW8CK'

const multisig = m`wsh(${alice_pk}/0/* && ${bob_pk}/0/*)`

// Generate receive address #0
const address = m`address(${multisig}/0)`
console.log(`Address: ${address}`)

// An output funding address #0
const prevout = '72877bd944be3433d5030ef102922e52f7c40de8b5ca26fa8b7c724d341e936e:1'
    , amount = '0.5 BTC'

// Create PSBT
const psbt = m`psbt[
  "input": [
    "prevout": ${prevout},
    "utxo": ${multisig}/0:${amount},
  ],
  "outputs": [
    bcrt1ql8nqx3q3v7napchr6ewy4tpyq5y08ywat84pen: 0.4 BTC,
    (${multisig}/1): 0.099 BTC, // change back to multisig
  ],
]`

// Export PSBT for external signing
const psbt_base64 = m.base64(psbt)

// Or sign with Minsc:
const alice_sk = 'xprv9s21ZrQH143K3FQmfpccrphXmHAJFbJ4iNK2KfXkPZaDRJ477HzVVp7kM7RV3ihdLh4Wy163wJahwXcdcrpu4R6xSu6CUvKYwftQYCbowYM'
    , bob_sk = 'xprv9s21ZrQH143K2mwJtk5bZyrqKqBmNhFCFoBcCw68QysefUWEL1pXu81xoeva2ZWpCjsJzzmYqph6vw6FjCMjg3q8obNzxYY9bCVgt9bKoHQ'

const signed = m`psbt::sign(${psbt}, ${[ alice_sk, bob_sk ]})`

// Finalize & Extract
const tx = m`psbt::extract(psbt::finalize(${signed}))`
console.log(m.pretty(tx))
console.log(m.bytes(tx).toString('hex'))

// Alternative style, with Minsc functions as JavaScript methods (translated into the same as above)
const address = m.address(m.wsh(m.and(m`${alice_pk}/0/1`, m`${bob_pk}/0/1`)))
const psbt = m.psbt({ inputs: [ ... ], outputs: [ ... ] })
const signed = m.psbt.sign(psbt, [ alice_sk, bob_sk ])
const tx = m.psbt.extract(m.psbt.finalize(signed))

License

MIT