SDK for compiling, deploying, and spending Simplicity programs on Elements/Liquid networks.
Musk provides a high-level Rust interface for working with Simplicity programs. It wraps the SimplicityHL compiler and provides utilities for:
- Program compilation and instantiation
- Taproot address generation
- Transaction construction and signing
- Witness value management
- Node connectivity via RPC
Add musk to your Cargo.toml:
[dependencies]
musk = { path = "../musk" }Musk provides an RpcClient for connecting to Elements/Liquid nodes:
use musk::{NodeConfig, RpcClient};
// Method 1: Load from config file
let client = RpcClient::from_config_file("musk.toml")?;
// Method 2: Create programmatically
let config = NodeConfig::regtest()
.with_rpc("http://localhost:18884", "user", "password");
let client = RpcClient::new(config)?;
// Method 3: Quick URL-based setup
let client = RpcClient::from_url("http://localhost:18884", "user", "pass")?;
// Test connection
client.test_connection()?;[network]
network = "regtest" # or "testnet", "liquidv1"
[rpc]
url = "http://127.0.0.1:18884"
user = "user"
password = "password"
[chain]
genesis_hash = "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"use musk::{Program, Arguments, RpcClient, NodeConfig};
use musk::client::NodeClient;
// Connect to node
let client = RpcClient::new(NodeConfig::regtest())?;
// Load and compile a program
let program = Program::from_file("my_program.simf")?;
let compiled = program.instantiate(Arguments::default())?;
// Generate an address (uses network-appropriate params)
let address = compiled.address(client.address_params());
println!("Program address: {}", address);
// Fund the program
let txid = client.send_to_address(&address, 100_000_000)?; // 1 BTC
client.generate_blocks(1)?; // Confirm (regtest only)use musk::{SpendBuilder, WitnessValues};
// Build a spending transaction
let mut builder = SpendBuilder::new(compiled, utxo)
.genesis_hash(client.genesis_hash()?);
// Add outputs
builder.add_output_simple(destination, amount, asset);
builder.add_fee(3000, asset);
// Compute sighash for signature generation
let sighash = builder.sighash_all()?;
// Create witness values (with signatures)
let witness = WitnessValues::default();
// Finalize and broadcast
let tx = builder.finalize(witness)?;
let txid = client.broadcast(&tx)?;use musk::{Program, Arguments, Value, WitnessName};
use std::collections::HashMap;
// Load program with parameters
let program = Program::from_file("p2pk.simf")?;
// Provide arguments
let mut args = HashMap::new();
args.insert(
WitnessName::from_str_unchecked("ALICE_PUBLIC_KEY"),
Value::u256(pubkey),
);
let compiled = program.instantiate(Arguments::from(args))?;
// Create witness with signature
let mut witness = HashMap::new();
witness.insert(
WitnessName::from_str_unchecked("ALICE_SIGNATURE"),
Value::byte_array(signature),
);
let tx = builder.finalize(WitnessValues::from(witness))?;Musk is designed to be network-agnostic through the NodeClient trait:
┌─────────────────────────────────────────────────────────────┐
│ Your App │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Musk │
│ ┌─────────────┐ ┌────────────────────┐ ┌──────────────┐ │
│ │ Program │→ │InstantiatedProgram │→ │ SpendBuilder │ │
│ │ (.simf) │ │ (Address) │ │ (Transaction)│ │
│ └─────────────┘ └────────────────────┘ └──────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ NodeClient trait │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────────┐ │ │
│ │ │ RpcClient │ │ (spray) │ │ (your impl) │ │ │
│ │ │ (built-in)│ │ │ │ │ │ │
│ │ └───────────┘ └───────────┘ └───────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Elements/Liquid Node (RPC) │
│ regtest │ testnet │ liquidv1 (mainnet) │
└─────────────────────────────────────────────────────────────┘
serde: Enable serialization support (default)rpc: Enable RpcClient and config file support (default)
To use without RPC support:
[dependencies]
musk = { path = "../musk", default-features = false, features = ["serde"] }| Network | Default Port | Address Params |
|---|---|---|
| regtest | 18884 | ELEMENTS |
| testnet | 18892 | LIQUID_TESTNET |
| liquidv1 | 7041 | LIQUID |
See the examples/ directory:
basic_usage.rs- Simple program workflowrpc_client.rs- Connecting to nodes with RpcClient
Run examples:
cargo run --example basic_usage
cargo run --example rpc_clientMIT OR Apache-2.0