@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
Maintainers
Readme
@lazysuperheroes/hedera-multisig
Production-grade multi-signature transaction management library for Hedera blockchain
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,
protobufjsarbitrary-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.mdwalks 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-multisigBasic 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 signersStep 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.jsonStep 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)
Get Session Info from coordinator:
- Server URL (e.g.,
wss://example.ngrok.io) - Session ID
- 6-digit PIN
- Server URL (e.g.,
Open the dApp: Navigate to deployed dApp URL
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 appComplete: 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
- User Guide: docs/WALLETCONNECT.md - Complete WalletConnect guide
- Offline Signing: docs/OFFLINE_SIGNING_GUIDE.md - Air-gapped signing workflow
- Roadmap: docs/ROADMAP.md - Future plans and architecture decisions
- dApp Setup: dapp/README.md - Developer setup and deployment
- Testing: dapp/INTEGRATION_TESTING.md - End-to-end testing guide
- Quick Test: dapp/QUICKSTART.md - 5-minute local test
- Deployment: dapp/DEPLOYMENT.md - Vercel deployment guide
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 --helpAvailable 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 initThe wizard will guide you through:
- Project Directory - Create in current directory or new folder
- Network Selection - Testnet (development), Mainnet (production), or Previewnet
- Operator Account - Account ID and private key for paying transaction fees
- Server Configuration - WebSocket server port
- 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 exampleAfter 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-logsA 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.7added 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:
- You want the coordinator to survive restarts mid-ceremony as a hard requirement (not just "nice to have"), or
- 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 >> $PROFILEExample: 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
ContractExecuteTransactioninternally" and produced signatures that didn't verify against the coordinator's stored bytes. The actual root cause was upstream:@hashgraph/hedera-wallet-connect'sDAppSigner.signTransactionrebuilds theTransactionBodyfrom the parsedTransactionobject 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); forContractExecuteTransactionit diverges (default-value handling, proto field ordering). v2.2.0 bypassesDAppSigner.signTransactionentirely (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
Prompt Input (Highest Security)
- Keys entered at runtime
- Never stored on disk
- Recommended for production
Encrypted Files (High Security)
- AES-256-GCM encryption
- PBKDF2 key derivation (100,000 iterations)
- Passphrase protected
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.jsUse 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 fileexportDir(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-auditSecurity Best Practices
- Production: Use
PromptKeyProviderorEncryptedFileProvider - File Permissions: Set encrypted files to 0600 (owner read/write only)
- Passphrases: Use strong passphrases (12+ characters)
- Audit Logs: Enable and monitor audit logging
- Environment Variables: Never use in production
- 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 typesCustom 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 failuresBatch 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:
- Install package:
npm install @lazysuperheroes/hedera-multisig - Update imports in all files
- Remove local
lib/multiSig/copy - 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 signingExample 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
- Documentation: Full Guides
- Offline Signing Guide - Air-gapped signing workflow
- Security Architecture - Security model details
- Roadmap - Future plans and decisions
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: [email protected]
🗺️ 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
