charms 13.0.0

Programmable assets on Bitcoin and beyond
Documentation
use bitcoin::{
    ScriptBuf, XOnlyPublicKey,
    constants::MAX_SCRIPT_ELEMENT_SIZE,
    opcodes::{
        OP_FALSE,
        all::{OP_CHECKSIG, OP_ENDIF, OP_IF},
    },
    script::{Builder, PushBytes},
    secp256k1::Secp256k1,
    taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo},
};

pub fn control_block(public_key: XOnlyPublicKey, script: ScriptBuf) -> ControlBlock {
    taproot_spend_info(public_key, script.clone())
        .control_block(&(script, LeafVersion::TapScript))
        .unwrap()
}

pub fn data_script(public_key: XOnlyPublicKey, data: &[u8]) -> ScriptBuf {
    let builder = ScriptBuf::builder();
    push_envelope(builder, data)
        .push_slice(public_key.serialize())
        .push_opcode(OP_CHECKSIG)
        .into_script()
}

fn push_envelope(builder: Builder, data: &[u8]) -> Builder {
    let mut builder = builder
        .push_opcode(OP_FALSE)
        .push_opcode(OP_IF)
        .push_slice(b"spell");
    for chunk in data.chunks(MAX_SCRIPT_ELEMENT_SIZE) {
        builder = builder.push_slice::<&PushBytes>(chunk.try_into().unwrap());
    }
    builder.push_opcode(OP_ENDIF)
}

pub fn taproot_spend_info(public_key: XOnlyPublicKey, script: ScriptBuf) -> TaprootSpendInfo {
    let secp256k1 = Secp256k1::new();
    TaprootBuilder::new()
        .add_leaf(0, script)
        .unwrap()
        .finalize(&secp256k1, public_key)
        .unwrap()
}