npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lazysuperheroes/hedera-multisig

v2.2.0

Published

Production-grade multi-signature transaction management library for Hedera blockchain with M-of-N threshold support, WalletConnect browser dApp, encrypted key storage, and comprehensive audit logging

Readme

@lazysuperheroes/hedera-multisig

Production-grade multi-signature transaction management library for Hedera blockchain

npm version License: MIT Node.js CI

Pick your path

| Want to… | Path | Time | |---|---|---| | Try the dApp without installing anything | Open testnet-multisig.lazysuperheroes.com and join an existing session | 2 min | | Run a real multi-sig session | npx hedera-multisig server -t 2 -k "key1,key2,key3" then connect via the hosted dApp or CLI (guide) | 5–15 min | | Walk a 2-of-3 HBAR transfer end-to-end (CLI signers) | examples/walkthrough-hbar/ — keys, threshold account, coordinator, CLI participants, mirror verify | 30 min | | Walk the same flow but signing in your browser via HashPack | examples/walkthrough-dapp/ — hosted testnet dApp + WalletConnect wallet | 30 min | | Walk an async multi-sig (no 120s window — sign over hours/days) | examples/walkthrough-scheduled/ — HIP-423 scheduled transactions, 24h+ expiration, mirror-node verification | 25 min | | Walk a 2-of-3 ceremony with ECDSA (secp256k1) keys | examples/walkthrough-ecdsa/ — same shape as the dApp walkthrough, but with EVM-curve keys; validates the stack is genuinely curve-agnostic | 30 min | | Walk a smart-contract multi-sig (deploy → convert → ceremony) | examples/walkthrough-contract/Counter.sol, EOA-then-convert, multi-sig increment() + withdraw() | 45 min | | Embed in your app | npm install @lazysuperheroes/hedera-multisig (library docs below) | varies | | Automate signing with policies | Build an agent with the Agent Signing SDK (PolicyEngine + composable rules) | 30+ min |

Architecture: We host the dApp UI on Vercel, but Vercel does not host a coordinator process. The WebSocket server that holds session state is always run by you (or a teammate) — locally or self-hosted. Private keys never leave the signer's device. Only frozen transaction bytes and signatures flow over the wire.

Why this exists

Multi-sig on Hedera is a recurring pain point: developers either roll their own coordination ad-hoc (insecure), rely on a single signer (defeats the purpose), or skip threshold keys entirely. This library is a community gift that makes M-of-N threshold signing on Hedera reliable, secure, and ergonomic across every common workflow.

Three signing patterns, five workflows

| Pattern | Workflow | When to use | |---|---|---| | Treasury management | Interactive, Offline, or Networked | DAO/team multi-sig spending. Coordinator builds a transaction, M-of-N signers approve. | | Agent-to-agent automation | Networked + AgentSigningClient | Bots and policy-driven services that auto-sign within configured rules. | | Long-window async signing | Scheduled (HIP-423, up to ~62 days) | Cross-timezone treasury ops, governance, time-locked approvals. Network executes when threshold is met. |

Five workflows total: Interactive (real-time, <110s), Offline (air-gapped, file-based), Networked (WebSocket-coordinated), Scheduled (HIP-423 async), and Flora (HCS-16 prep, Phase 6).

Highlights

  • M-of-N threshold signatures (2-of-3, 3-of-5, …) with mixed Ed25519 + ECDSA
  • Scheduled transactions up to ~62 days (HIP-423) — the killer feature for cross-timezone teams
  • Agent Signing SDK with a composable PolicyEngine (amount limits, recipient allowlists, time windows, rate limits)
  • WalletConnect dApp with hardware-wallet support and ABI-verified contract review
  • Mirror-node confirmation of execution — receipt success is not enough; the network must actually externalize the transaction
  • Server-side cryptographic signature verification — the coordinator can't accept invalid signatures even if compromised
  • Three security tiers for keys: interactive prompt, encrypted files, env vars
  • TLS/WSS WebSocket encryption + per-IP and per-session rate limiting
  • Optional Redis session persistence for the rare case you're horizontally scaling the coordinator (read the note before reaching for this — most deployments don't want it)
  • TypeScript declarations included; Commander.js CLI with shell completions; structured logging; comprehensive audit log

Security note: v2.1.0 closed three CRITICALs found in the v2.0 review (post-AUTH coordinator role, protobufjs arbitrary-code-execution CVE, reconnection-token public-key binding). Read SECURITY.md for the threat model and disclosure policy. The library is unaudited — recommended workflow for high-value mainnet treasuries is offline / air-gapped, not the hosted dApp.

New to threshold keys? docs/THRESHOLD_GUIDE.md walks through how M-of-N works, how to choose M and N for your use case, and what nested key-lists look like — including what this library can and can't coordinate today.


🚀 Quick Start

Installation

npm install @lazysuperheroes/hedera-multisig

Basic Usage - Interactive Workflow

const {
  Client,
  TransferTransaction,
  Hbar
} = require('@hashgraph/sdk');

const {
  WorkflowOrchestrator,
  PromptKeyProvider
} = require('@lazysuperheroes/hedera-multisig');

async function multiSigTransfer() {
  // Set up Hedera client
  const client = Client.forTestnet();

  // Create transaction
  const transaction = new TransferTransaction()
    .addHbarTransfer('0.0.123', Hbar.fromTinybars(-1000))
    .addHbarTransfer('0.0.456', Hbar.fromTinybars(1000));

  // Configure multi-sig
  const orchestrator = new WorkflowOrchestrator(client);

  // Execute with 2-of-3 signatures
  const result = await orchestrator.execute(transaction, {
    workflow: 'interactive',
    keyProviders: [
      new PromptKeyProvider({ label: 'Signer 1' }),
      new PromptKeyProvider({ label: 'Signer 2' }),
      new PromptKeyProvider({ label: 'Signer 3' })
    ],
    threshold: 2,
    signerLabels: ['Alice', 'Bob', 'Charlie']
  });

  console.log('Transaction ID:', result.transactionId);
  console.log('Status:', result.receipt.status.toString());
}

multiSigTransfer();

Offline Workflow (Air-Gapped Signing)

Step 1: Freeze and Export (on connected machine)

const result = await orchestrator.freezeAndExport(transaction, {
  threshold: 2,
  signerLabels: ['Alice', 'Bob'],
  exportDir: './transactions'
});

console.log('Transaction file:', result.transactionFile);
// Share this file with signers

Step 2: Sign (on air-gapped machines)

# Each signer runs this on their secure machine
node node_modules/@lazysuperheroes/hedera-multisig/cli/sign.js transaction-file.txt

# Outputs: signature-Alice-timestamp.json

Step 3: Collect and Execute (on connected machine)

const result = await orchestrator.collectAndExecute(
  frozenTransaction,
  ['signature-Alice.json', 'signature-Bob.json'],
  2
);

console.log('Transaction executed:', result.transactionId);

🌐 Web-Based Signing (WalletConnect)

NEW! Sign multi-signature transactions directly in your browser using WalletConnect-compatible wallets.

Features

  • 🔐 Hardware Wallet Support - Sign with Ledger through HashPack or Blade wallet
  • 🌐 Browser-Based - No software installation required
  • 📱 Mobile-Friendly - Works on desktop and mobile devices
  • 🔑 Private Keys Stay in Wallet - Keys never leave your wallet app
  • Mixed Sessions - CLI and Web participants can sign together
  • 🎯 Same Security Model - VERIFIED vs UNVERIFIED transaction review

Quick Start (Web Participant)

  1. Get Session Info from coordinator:

    • Server URL (e.g., wss://example.ngrok.io)
    • Session ID
    • 6-digit PIN
  2. Open the dApp: Navigate to deployed dApp URL

  3. Join Session:

    1. Click "Join session"
    2. Enter Server URL, Session ID, PIN
    3. Connect your wallet (HashPack or Blade)
    4. Review transaction details
    5. Sign in your wallet app
  4. Complete: Transaction executes when threshold met

Setup for Web Signing

For Participants:

  • Install HashPack or Blade wallet
  • Fund your account (testnet faucet for testing)
  • Share your public key with coordinator

For Coordinators:

  • Deploy the dApp (see dapp/README.md)
  • Or use locally with cd dapp && npm run dev
  • Create session with web participant public keys
  • Share session credentials

Documentation

Supported Wallets

| Wallet | Browser Ext | Mobile | Ledger | Status | |--------|-------------|--------|--------|--------| | HashPack | ✅ | ✅ | ✅ | Recommended | | Blade | ✅ | ✅ | ⚠️ | Supported |


💻 CLI Usage

The package includes a unified CLI with subcommands for all operations:

# Install globally
npm install -g @lazysuperheroes/hedera-multisig

# Or use via npx
npx hedera-multisig --help

Available Commands

| Command | Description | |---------|-------------| | hedera-multisig init | Initialize a new multi-sig project | | hedera-multisig server | Start the multi-sig WebSocket server | | hedera-multisig participant | Join a signing session as participant | | hedera-multisig sign | Sign a frozen transaction file | | hedera-multisig keys | Key management (create, test, audit) | | hedera-multisig audit | Run security audit | | hedera-multisig account | Hedera account management | | hedera-multisig completions | Generate shell completions |

Quick Start with Init Wizard

The fastest way to get started is with the initialization wizard:

npx @lazysuperheroes/hedera-multisig init

The wizard will guide you through:

  1. Project Directory - Create in current directory or new folder
  2. Network Selection - Testnet (development), Mainnet (production), or Previewnet
  3. Operator Account - Account ID and private key for paying transaction fees
  4. Server Configuration - WebSocket server port
  5. Security Options - Create directories for keys and logs

Generated Project Structure:

my-multisig/
├── .env                 # Configuration (network, operator, port)
├── .env.example         # Template for team members
├── .gitignore           # Security-aware gitignore
├── package.json         # npm scripts for common operations
├── keys/                # Encrypted key file storage
├── logs/                # Audit log storage
└── examples/
    ├── transfer.js          # Interactive 2-of-3 transfer example
    └── networked-session.js # WebSocket session example

After initialization:

cd my-multisig
npm install
npm run server -- --threshold 2 --keys "key1,key2,key3"

Server Command Options

# Start server with TLS
hedera-multisig server \
  --port 3001 \
  --threshold 2 \
  --keys "key1,key2,key3" \
  --tls --cert cert.pem --key key.pem

# With Redis persistence (you probably don't need this — see below)
hedera-multisig server \
  --redis \
  --redis-host localhost \
  --redis-port 6379

# With structured logging
hedera-multisig server \
  --log-level debug \
  --log-file ./logs/server.log \
  --export-logs

A note on --redis

The Redis session store is in optionalDependencies and the server falls back to in-memory automatically if Redis is unreachable. You probably don't need it. Reasons:

  • Sessions are short-lived. Realtime ceremonies finish in minutes; scheduled ceremonies stretch to days but the coordinator process is rarely the long-lived component.
  • Coordinator restarts during a ceremony are uncommon, and when they happen, participants can rejoin via PIN cleanly (2.1.7 added the stale-token fallback).
  • Centralizing session state in Redis introduces a third-party trust surface (Redis sees eligible keys, signatures during the window, transaction bodies) — at odds with this project's "no central trusted intermediary" framing.

You'd reach for --redis only if:

  1. You want the coordinator to survive restarts mid-ceremony as a hard requirement (not just "nice to have"), or
  2. You're horizontally scaling the coordinator behind a load balancer (multiple Node processes sharing session state).

For everything else — your laptop, a single VPS, or a docker-on-fly.io deploy — the in-memory store is the right choice.

Shell Completions

# Bash
hedera-multisig completions bash >> ~/.bashrc

# Zsh
hedera-multisig completions zsh >> ~/.zshrc

# Fish
hedera-multisig completions fish > ~/.config/fish/completions/hedera-multisig.fish

# PowerShell
hedera-multisig completions powershell >> $PROFILE

Example: Mixed CLI + Web Session

// Coordinator creates session with mixed keys
const eligiblePublicKeys = [
  'CLI_PARTICIPANT_KEY_1',      // CLI with file-based key
  'CLI_PARTICIPANT_KEY_2',      // CLI with file-based key
  'WEB_PARTICIPANT_KEY_1',      // Web with HashPack wallet
  'WEB_PARTICIPANT_KEY_2',      // Web with Ledger via HashPack
];

const session = await sessionManager.createSession(null, {
  threshold: 3,                 // Need 3 out of 4 signatures
  eligiblePublicKeys,
  expectedParticipants: 4
});

// CLI participants join via terminal
// Web participants join via browser dApp
// Both signature types work seamlessly together!

🌐 Node freeze defaults — read this if you're integrating

TL;DR: The library defaults to a single-node freeze (subsetSize: 1). If you only have CLI / SDK signers and want resilience against per-node downtime, opt up to multi-node by passing subsetSize: 6 to selectNodeAccountIds().

Why single-node by default

Multi-node freeze is the canonical Hedera multi-sig pattern: sign every node body up front so execute() can rotate to any healthy node if the first is busy.

We default to single-node anyway because the WalletConnect SignTransaction RPC method signs one body per wallet popup. Multi-node freeze with N bodies would either need N popups (poor UX) or fall back to body[0]-only signing — which the server already supports via its trim-to-body[0] fallback at execute time. Single-node sidesteps the multi-popup problem and keeps the ceremony tight.

Historical note (resolved in v2.2.0). Earlier versions described a wallet bug where HashPack / Kabila "re-froze ContractExecuteTransaction internally" and produced signatures that didn't verify against the coordinator's stored bytes. The actual root cause was upstream: @hashgraph/hedera-wallet-connect's DAppSigner.signTransaction rebuilds the TransactionBody from the parsed Transaction object before sending to the wallet, then reattaches the wallet's signature to the original preserved bodyBytes. For HBAR / token transfers the rebuild is byte-identical (verify works); for ContractExecuteTransaction it diverges (default-value handling, proto field ordering). v2.2.0 bypasses DAppSigner.signTransaction entirely (dapp/lib/walletconnect.ts) and sends the original bodyBytes directly via the RPC method. Both HashPack and Kabila now sign contract calls successfully in multi-sig ceremonies. Upstream issue: hashgraph/hedera-wallet-connect#694.

When to opt up

const { selectNodeAccountIds } = require('@lazysuperheroes/hedera-multisig');

// Default — single body, single wallet popup, works for any tx type
const nodes = selectNodeAccountIds(client);

// CLI-only treasury workflow with no wallet signers? Opt up for
// multi-node resilience — CLI signers sign every body so execute()
// can rotate to any healthy node:
const nodes = selectNodeAccountIds(client, { subsetSize: 6 });

CLI signers (cli/, client/) produce a full per-body signature array because they sign the SDK's bodyBytes directly. They get the full multi-node resilience: if one node is busy, execute() retries against the others.

Cost of the default

Single-node = if the chosen node is busy or unhealthy at submit time, the ceremony's submission can fail with no fanout. We mitigate by biasing the picker toward healthy / recently-active nodes (see shared/node-selection.js#orderByHealth and MirrorNodeClient), but it's a real downside vs the multi-node ideal.

A future enhancement could iterate the wallet popup N times to collect per-body signatures for multi-node ceremonies — tracked in docs/ROADMAP.md.


📚 Documentation

Core Concepts

M-of-N Threshold Signatures

Require M signatures from N authorized signers. Examples:

  • 2-of-3: Any 2 of 3 signers can authorize (recommended for small teams)
  • 3-of-5: Any 3 of 5 signers can authorize (recommended for larger teams)
  • 5-of-7: Any 5 of 7 signers can authorize (high-security operations)

Two Workflow Modes

Interactive Workflow (Real-Time):

  • All signers coordinate in real-time
  • < 110-second timeout
  • Best for: Quick operations, collocated teams

Offline Workflow (Asynchronous):

  • Transaction frozen and exported
  • Signers sign independently (air-gapped machines supported)
  • No timeout
  • Best for: High-security operations, distributed teams

Three Security Tiers

  1. Prompt Input (Highest Security)

    • Keys entered at runtime
    • Never stored on disk
    • Recommended for production
  2. Encrypted Files (High Security)

    • AES-256-GCM encryption
    • PBKDF2 key derivation (100,000 iterations)
    • Passphrase protected
  3. Environment Variables (Development Only)

    • Convenient for testing
    • NOT recommended for production

🔑 Key Management

Create Encrypted Key File

# Interactive CLI wizard
npm run create-key-file

# Or
node node_modules/@lazysuperheroes/hedera-multisig/cli/createKeyFile.js

Use Encrypted Key Files

const { EncryptedFileProvider } = require('@lazysuperheroes/hedera-multisig');

const keyProvider = new EncryptedFileProvider({
  filePath: './keys/signer1.enc',
  passphrase: process.env.KEY_PASSPHRASE // Or prompt
});

const result = await orchestrator.execute(transaction, {
  workflow: 'interactive',
  keyProviders: [keyProvider],
  threshold: 1
});

Test Key File

npm run test-key-file keys/signer1.enc

🛠️ API Reference

WorkflowOrchestrator

Main entry point for multi-sig operations.

const orchestrator = new WorkflowOrchestrator(client, options);

Options:

  • verbose (boolean): Enable detailed logging (default: true)
  • defaultWorkflow (string): 'interactive' or 'offline' (default: 'interactive')
  • auditLogPath (string): Path to audit log file
  • exportDir (string): Directory for offline workflow exports

Methods:

execute(transaction, config)

Execute a transaction with multi-sig.

const result = await orchestrator.execute(transaction, {
  workflow: 'interactive' | 'offline',
  keyProviders: [KeyProvider, ...],
  threshold: 2,
  signerLabels: ['Alice', 'Bob', 'Charlie']
});

freezeAndExport(transaction, metadata)

Freeze transaction and export for offline signing.

const result = await orchestrator.freezeAndExport(transaction, {
  threshold: 2,
  signerLabels: ['Alice', 'Bob'],
  exportDir: './transactions'
});
// Returns: { transactionFile, metadataFile, frozenTransaction }

collectAndExecute(frozenTransaction, signatureFiles, threshold)

Collect signatures and execute.

const result = await orchestrator.collectAndExecute(
  frozenTransaction,
  ['sig1.json', 'sig2.json'],
  2
);

Key Providers

PromptKeyProvider

Interactive key input (highest security).

const provider = new PromptKeyProvider({
  label: 'Signer 1',
  count: 1,
  hideInput: true,
  confirmKeys: true
});

EncryptedFileProvider

AES-256-GCM encrypted key storage.

const provider = new EncryptedFileProvider({
  filePath: './keys/signer.enc',
  passphrase: 'your-strong-passphrase',
  promptIfMissing: true
});

EnvKeyProvider

Environment variable keys (development only).

const provider = new EnvKeyProvider({
  keyVarName: 'PRIVATE_KEY'
});

Workflows

InteractiveWorkflow

Real-time multi-sig coordination.

const workflow = new InteractiveWorkflow(client, {
  verbose: true,
  showTimer: true
});

const result = await workflow.execute(transaction, {
  keyProviders: [provider1, provider2, provider3],
  threshold: 2
});

OfflineWorkflow

Asynchronous air-gapped signing.

const workflow = new OfflineWorkflow(client, {
  exportDir: './transactions',
  verbose: true
});

// Phase 1: Freeze
const frozen = await workflow.freezeAndExport(transaction, metadata);

// Phase 2: Sign (on other machines)
// ...signatures collected...

// Phase 3: Execute
const result = await workflow.collectAndExecute(
  frozen.frozenTransaction,
  signatureFiles,
  threshold
);

🔐 Security

Security Features

  • No Key Storage: Prompt-based provider never stores keys
  • Strong Encryption: AES-256-GCM with PBKDF2 (100k iterations)
  • Input Hiding: All key inputs use hideEchoBack
  • Audit Logging: Comprehensive operation tracking
  • Sanitized Logs: No private keys in logs
  • Signature Validation: Cryptographic verification
  • Timeout Protection: 110-second limit (9s buffer)

Security Audit

Run automated security audit:

npm run security-audit

Security Best Practices

  1. Production: Use PromptKeyProvider or EncryptedFileProvider
  2. File Permissions: Set encrypted files to 0600 (owner read/write only)
  3. Passphrases: Use strong passphrases (12+ characters)
  4. Audit Logs: Enable and monitor audit logging
  5. Environment Variables: Never use in production
  6. Key Rotation: Implement regular key rotation schedule

What's Safe to Share

Safe:

  • This package (no keys in code)
  • Transaction files (frozen transactions)
  • Public keys (last 8 characters displayed)
  • Audit logs (sanitized)

Never Share:

  • Private keys
  • Encrypted key files without passphrase rotation
  • Passphrases
  • .env files
  • Signature files (contain cryptographic signatures)

🧪 Testing

# Run all tests
npm test

# Run specific test suites
npm run test:unit      # Key management tests
npm run test:workflows # Workflow tests

# With coverage
npm test -- --coverage

📖 Advanced Usage

Mixed Key Types (Ed25519 + ECDSA)

// Automatically detected - just provide keys
// Key 1: Ed25519 (Hedera native)
// Key 2: ECDSA secp256k1 (Ethereum-compatible)
// Key 3: Ed25519

const result = await orchestrator.execute(transaction, {
  workflow: 'interactive',
  keyProviders: [
    new PromptKeyProvider({ label: 'Ed25519 Key' }),
    new PromptKeyProvider({ label: 'ECDSA Key' }),
    new PromptKeyProvider({ label: 'Ed25519 Key' })
  ],
  threshold: 2
});
// System automatically detects and handles key types

Custom Audit Logging

const orchestrator = new WorkflowOrchestrator(client, {
  auditLogPath: './logs/multi-sig-audit.log',
  verbose: true
});

// All operations are logged:
// - Transaction creation
// - Signature collection
// - Execution results
// - Errors and failures

Batch Operations

const transactions = [tx1, tx2, tx3];

for (const tx of transactions) {
  const result = await orchestrator.execute(tx, config);
  console.log(`Executed: ${result.transactionId}`);
}

Error Handling

try {
  const result = await orchestrator.execute(transaction, config);
  console.log('Success:', result.transactionId);
} catch (error) {
  if (error.message.includes('Insufficient signatures')) {
    console.error('Not enough signers provided signatures');
  } else if (error.message.includes('expired')) {
    console.error('Transaction timed out');
  } else {
    console.error('Unexpected error:', error.message);
  }
}

🔄 Migration from Local Copy

If you were previously copying the lib/multiSig/ folder:

// Before:
const { WorkflowOrchestrator } = require('../../lib/multiSig');

// After:
const { WorkflowOrchestrator } = require('@lazysuperheroes/hedera-multisig');

Steps:

  1. Install package: npm install @lazysuperheroes/hedera-multisig
  2. Update imports in all files
  3. Remove local lib/multiSig/ copy
  4. Test everything works

💡 Examples

Example 1: Treasury Multi-Sig (2-of-3)

const { WorkflowOrchestrator, PromptKeyProvider } = require('@lazysuperheroes/hedera-multisig');

async function treasuryWithdrawal() {
  const orchestrator = new WorkflowOrchestrator(Client.forMainnet());

  const withdrawal = new TransferTransaction()
    .addHbarTransfer(treasuryAccount, Hbar.from(-10000))
    .addHbarTransfer(recipientAccount, Hbar.from(10000));

  const result = await orchestrator.execute(withdrawal, {
    workflow: 'interactive',
    keyProviders: [
      new PromptKeyProvider({ label: 'CFO' }),
      new PromptKeyProvider({ label: 'CTO' }),
      new PromptKeyProvider({ label: 'CEO' })
    ],
    threshold: 2,
    signerLabels: ['CFO', 'CTO', 'CEO']
  });

  return result;
}

Example 2: High-Security Contract Call (3-of-5)

const contractCall = new ContractExecuteTransaction()
  .setContractId('0.0.123456')
  .setGas(100000)
  .setFunction('criticalOperation', params);

const result = await orchestrator.execute(contractCall, {
  workflow: 'offline', // Air-gapped signing for high security
  exportDir: './high-security-transactions'
});

console.log('Transaction frozen:', result.transactionFile);
// Distribute to 5 signers for signing

Example 3: Emergency Pause with Encrypted Keys

const { EncryptedFileProvider } = require('@lazysuperheroes/hedera-multisig');

const pause = new ContractExecuteTransaction()
  .setContractId(contractId)
  .setGas(50000)
  .setFunction('pause');

const result = await orchestrator.execute(pause, {
  workflow: 'interactive',
  keyProviders: [
    new EncryptedFileProvider({ filePath: './keys/security1.enc' }),
    new EncryptedFileProvider({ filePath: './keys/security2.enc' })
  ],
  threshold: 2,
  signerLabels: ['Security Lead', 'Operations Lead']
});

🤝 Contributing

Contributions welcome! Please see CONTRIBUTING.md for details.

Development Setup

# Clone repository
git clone https://github.com/lazysuperheroes/hedera-multisig.git
cd hedera-multisig

# Install dependencies
npm install

# Run tests
npm test

# Run linter
npm run lint

📄 License

MIT License - see LICENSE file for details.


🙏 Acknowledgments

Built with ❤️ by Lazy Superheroes for the Hedera community.

Special thanks to:

  • Hedera Hashgraph team for the excellent SDK
  • The cryptocurrency security community
  • All contributors and testers

📬 Support


🗺️ Roadmap

Shipped in v2.1.0 (current)

  • ✅ M-of-N threshold signatures with mixed Ed25519 + ECDSA
  • ✅ Five workflows: Interactive, Offline, Networked, Scheduled (HIP-423, ~62 days), Flora-prep
  • ✅ Agent Signing SDK with PolicyEngine (5 composable rules)
  • ✅ Mirror-node post-execution confirmation
  • ✅ WalletConnect dApp with ABI-verified contract review
  • ✅ TLS/WSS encryption, per-IP + per-session rate limiting
  • ✅ Redis session persistence (Phase A8 field parity)
  • ✅ TypeScript definitions, Commander.js CLI, structured logging, audit logging
  • ✅ Three security CRITICALs closed (post-AUTH coordinator role, protobufjs CVE, reconnection-token key binding)

v2.2 / Future

  • HCS-16 Flora workflow (on-chain coordination)
  • Public hosted demo instance (currently: testnet dApp UI is hosted; coordinator is self-hosted)
  • Multi-language SDK (Python, Go)
  • Hierarchical deterministic (HD) keys
  • Shamir Secret Sharing integration
  • Cumulative-amount limits in PolicyEngine
  • HCS-26 agent skills registry integration

See docs/ROADMAP.md for detail.


Made with care for the Hedera community by Lazy Superheroes