pull down to refresh

TL;DR: MiniScript is a structured way of writing spending conditions in Bitcoin (signatures, timelocks, etc.) that can be analyzed, verified, and composed easily. Thanks to this, modern wallets can offer time-based recovery, inheritance, flexible multisigs, and auditable secure procedures.
Base sources:

What Problem Does It Solve?

  • Bitcoin Script is powerful but complex and full of edge cases. It’s hard to ensure a script is correct and non-malleable, and even harder to reason about its risks. MiniScript restricts and organizes that power to make it auditable and composable.
  • For wallets, this allows clear descriptors and generic signing over many policies (e.g., multisig + timelock), improving tracking and compatibility with PSBT.

The Concept (Simply)

  • MiniScript is a structured subset of Script with rules that allow static analysis (knowing in advance if a policy can always spend, how much it may cost in fees, if it’s non-malleable, etc.).
  • On top of MiniScript there is a readable “policy language” (like and(), or(), thresh(), after(), older()) that describes what you want, and the compiler generates how it’s implemented in Script.

Mini Mental Glossary

  • pk(A): spend with signature of key A.
  • thresh(2, pk(A), pk(B), pk(C)): requires 2 of 3 signatures.
  • after(T): absolute timelock (cannot spend until height/date X).
  • older(T): relative timelock (T blocks must pass after funds entered).
  • and(X,Y), or(X,Y): boolean logic to combine conditions.

Three Useful Policies (and What They Mean)

  1. Basic inheritance with delay (rescue path):
    or( pk(Holder), and( after(height_or_date), pk(Heir) ) )
    • Holder spends immediately.
    • If the Holder does not spend and timelock passes, the Heir can spend.
    • Pattern used by recovery/legacy wallets.
  2. 2-of-3 with emergency key after 90 days:
    or( thresh(2, pk(A), pk(B), pk(C)), and( older(12960), pk(Emergency) ) )
    • Normally 2 of 3 keys required.
    • If ~90 days pass (≈12960 blocks), an Emergency key can move funds alone.
  3. Spending with “cold key” + delay (secure daily ops):
    or( and( pk(Mobile), pk(HW) ), and( older(2016), pk(Cold) ) )
    • Daily: need Mobile + Hardware.
    • Plan B: after ~2 weeks, the Cold key can spend alone (useful if a device is lost).
Practical note: Mixing timelocks requires caution to avoid surprises (e.g., paths that block each other). Good guides warn against bad mixing of different timelock types.

Minimal Step by Step (On Paper, Before Touching a Wallet)

  1. Write your goal clearly.
    Example: “I want to spend alone, but if in 6 months I don’t touch the wallet, my spouse should be able to move the funds.”
  2. Translate into MiniScript policy.
    or( pk(Me), and( after(6_month_date), pk(Spouse) ) )
  3. Technical check (static reading):
    Ensure that:
    • there is always at least one spending path,
    • the timelock is reachable (realistic date/height),
    • no conflicts exist between paths (e.g., competing UTXO spending routes).
  4. Think about real operations:
    • How do you test the “plan B” without moving all sats?
    • What happens if one key is lost? Define procedures (rotation, quarterly tests, evidence for heirs).
    • What fee cost will each path have (witness size)? MiniScript helps estimate.

Best Practices and Common Mistakes

  • Start on testnet. Try each path (main and rescue).
  • Document the policy in human language + MiniScript/descriptor form.
  • Avoid confusing mixes of timelocks; use well-understood templates.
  • ❌ Don’t rely on memory: keep procedures (what to do if X fails).
  • ❌ Don’t use policies that nobody else can audit: stick to known patterns.

Mental Demo / Real Case

“Inheritance with silent fallback”:
  • Policy: or( pk(Holder), and( after(6m), pk(Heir) ) )
  • Daily ops: Holder spends normally.
  • If 6 months pass with no activity (e.g., death or total loss), the Heir can move funds with their key, no custodians or external papers, because the rule lives in consensus (Script).

Useful Resources


Closing

  • Action (today): Write your policy clearly and translate it into MiniScript with pk(), after(), older(), and(), or() (use resource examples).
  • Question: Which scenario do you want to cover next: inheritance, 2-of-3 with emergency, or daily ops + cold key?
Next posts: Nunchuk (social multisig, inheritance, and daily ops) and Liana (timelock templates and rescue paths), then Ashigaru (practical privacy).
Thank you for such a useful article!
reply