Skip to main content
Version: 0.14 (unstable)

Rust Multisig SDK

The miden-multisig-client crate provides a high-level Rust SDK for private multisig workflows on Miden. It wraps the on-chain multisig contracts and Guardian coordination into a single API.

Source: crates/miden-multisig-client

Installation

[dependencies]
miden-multisig-client = { git = "https://github.com/OpenZeppelin/private-state-manager", package = "miden-multisig-client" }

Setup

use miden_client::rpc::Endpoint;
use miden_multisig_client::MultisigClient;
use miden_objects::Word;

let signer1: Word = /* RPO Falcon commitment */ Word::default();
let signer2: Word = Word::default();

let mut client = MultisigClient::builder()
.miden_endpoint(Endpoint::new("http://localhost:57291"))
.psm_endpoint("http://localhost:50051")
.account_dir("/tmp/multisig")
.generate_key()
.build()
.await?;

Creating a multisig account

// Create a 2-of-2 multisig account and register it on Guardian
let account = client.create_account(2, vec![signer1, signer2]).await?;

Propose, sign, execute

use miden_multisig_client::TransactionType;
use miden_objects::account::AccountId;

let recipient = AccountId::from_hex("0x...")?;
let faucet = AccountId::from_hex("0x...")?;
let tx = TransactionType::transfer(recipient, faucet, 1_000);

// Proposer creates the transaction proposal on Guardian
let proposal = client.propose_transaction(tx).await?;

// Cosigner lists and signs the proposal
let proposals = client.list_proposals().await?;
let to_sign = proposals.iter().find(|p| p.id == proposal.id).unwrap();
client.sign_proposal(&to_sign.id).await?;

// Once threshold is met, execute
client.execute_proposal(&proposal.id).await?;

Offline fallback

If Guardian is unavailable, the SDK automatically produces an offline proposal:

use miden_multisig_client::{ProposalResult, TransactionType};

let tx = TransactionType::consume_notes(vec![note_id]);
match client.propose_with_fallback(tx).await? {
ProposalResult::Online(p) => {
println!("Proposal {} is live on Guardian", p.id);
}
ProposalResult::Offline(exported) => {
std::fs::write("proposal.json", exported.to_json()?)?;
println!("Share proposal.json with cosigners for offline signing");
}
}

Offline signing and execution

// Cosigner signs an imported proposal
client.sign_imported_proposal(&mut exported)?;
std::fs::write("proposal_signed.json", exported.to_json()?)?;

// Once enough signatures are collected
client.execute_imported_proposal(&exported).await?;

Listing consumable notes

use miden_multisig_client::NoteFilter;

// All consumable notes
let notes = client.list_consumable_notes().await?;

// Filter by faucet and minimum amount
let faucet = AccountId::from_hex("0x...")?;
let filter = NoteFilter::by_faucet_min_amount(faucet, 5_000);
let spendable = client.list_consumable_notes_filtered(filter).await?;

Full reference

See the crates/miden-multisig-client/README.md for the complete API reference.