Multi-Signature Wallets
Complete guide to multi-signature wallets with MSA API, including setup, execution, and best practices.
Multi-signature (multisig) wallets require multiple signatures to approve transactions, providing enhanced security through distributed control.
Overview
MSA supports two multisig custody types:
- MULTISIG_VALIDATOR (Type 4): Traditional M-of-N multisig
- MULTISIG_PASSKEY_VALIDATOR (Type 5): Multisig with passkey support
Understanding Thresholds
The threshold parameter determines how many signatures are required:
- 1-of-N: Any signer can approve (least secure)
- M-of-N: M signatures required (balanced)
- N-of-N: All signers must approve (most secure)
Creating Multisig Wallets
Standard Multisig (Type 4)
// Using API HTTP (fetch) for wallet creation
const response = await fetch('https://api.msa.omnes.tech/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
accounts: [{
walletCustody: 4, // MULTISIG_VALIDATOR
salt: 'org@example.com',
signers: [
'0x742d35Cc6676C461fAb7E06dcA6e1A1BB2b7d0Fd', // Signer 1
'0x8ba1f109551bD432803012645Hac136c0bf1E1A5', // Signer 2
'0x9D86b1BEE4F24C5F5e4B15c2C3d2F0f6Ff2F5f5E' // Signer 3
],
threshold: '2' // Require 2 of 3 signatures
}],
settings: {
rpc: 'https://rpc-amoy.polygon.technology/',
factory: '0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4',
validator: '0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a',
entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789',
beaconAdminAddress: '0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618',
signer: {
clientId: process.env.MSA_CLIENT_ID!,
versionId: process.env.MSA_VERSION_ID!
}
}
})
});
const result = await response.json();
const multisigWallet = result.returnData[0]['0'];
console.log('Multisig wallet:', multisigWallet.wallet);import requests
def create_multisig_wallet():
url = "https://api.msa.omnes.tech/create"
payload = {
"accounts": [{
"walletCustody": 4, # MULTISIG_VALIDATOR
"salt": "org@example.com",
"signers": [
"0x742d35Cc6676C461fAb7E06dcA6e1A1BB2b7d0Fd",
"0x8ba1f109551bD432803012645Hac136c0bf1E1A5",
"0x9D86b1BEE4F24C5F5e4B15c2C3d2F0f6Ff2F5f5E"
],
"threshold": "2"
}],
"settings": {
"rpc": "https://rpc-amoy.polygon.technology/",
"factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
"validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
"entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618",
"beaconAdminCreationCode": "0x60a060405260405161059d...",
"signer": {
"clientId": "your-client-id",
"versionId": "1"
}
}
}
response = requests.post(url, json=payload)
return response.json()
create_multisig_wallet()curl -X POST "https://api.msa.omnes.tech/create" \
-H "Content-Type: application/json" \
-d '{
"accounts": [{
"walletCustody": 4,
"salt": "org@example.com",
"signers": [
"0x742d35Cc6676C461fAb7E06dcA6e1A1BB2b7d0Fd",
"0x8ba1f109551bD432803012645Hac136c0bf1E1A5",
"0x9D86b1BEE4F24C5F5e4B15c2C3d2F0f6Ff2F5f5E"
],
"threshold": "2"
}],
"settings": {
"rpc": "https://rpc-amoy.polygon.technology/",
"factory": "0xb09Fd1134553a43A3E02182a6B04F4dEBa7476F4",
"validator": "0x9bD18Da66990F80d598dE02d5143dC9A4422eC3a",
"entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
"beaconAdminAddress": "0x99Ee7725D6a8f691d8B375e0aD33d1Aff2236618",
"beaconAdminCreationCode": "0x60a060405260405161059d...",
"signer": {
"clientId": "your-client-id",
"versionId": "1"
}
}
}'Multisig + Passkey (Type 5)
Combine traditional signers with passkeys:
const enterpriseWallet = await client.createWallet({
walletCustody: CustodyType.MULTISIG_PASSKEY_VALIDATOR,
salt: 'enterprise@example.com',
signers: [
'0x742d35Cc6676C461fAb7E06dcA6e1A1BB2b7d0Fd', // ECDSA signer 1
'0x8ba1f109551bD432803012645Hac136c0bf1E1A5' // ECDSA signer 2
],
passkeyPubKey: [
'base64-url-key-1', // Passkey 1
'base64-url-key-2' // Passkey 2
],
threshold: '2' // Require 2 total (could be 1 signer + 1 passkey)
});Threshold Configuration Examples
2-of-3 (Recommended)
Balanced security and flexibility:
{
signers: [signer1, signer2, signer3],
threshold: '2'
}Use Cases: Most organizational wallets, shared custody scenarios
3-of-5 (Higher Security)
Requires majority approval:
{
signers: [signer1, signer2, signer3, signer4, signer5],
threshold: '3'
}Use Cases: High-value wallets, compliance requirements
All-of-N (Maximum Security)
Requires all signatures:
{
signers: [signer1, signer2, signer3],
threshold: '3' // All must approve
}Use Cases: Critical operations, maximum security requirements
Executing Transactions
Transactions from multisig wallets require signatures from multiple signers. The MSA API handles this automatically if you provide multiple signers in your configuration.
Standard Execution
// Execute transaction - API will collect required signatures
const result = await client.execute({
operations: [{
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'org@example.com',
to: tokenAddress,
funcSignature: 'transfer(address,uint256)',
funcParams: [recipient, amount]
}]
});Manual Signature Collection
For custom signature flows:
import { SmartWallet, PKSigner, AccountOperations } from '@omnes/smartwallet-ts-sdk';
// Create signers for each party
const signer1 = await PKSigner.create(privateKey1);
const signer2 = await PKSigner.create(privateKey2);
const signer3 = await PKSigner.create(privateKey3);
// Build UserOperations
const smartWallet = await SmartWallet.create(
signer1.signMessage, // Primary signer
signer1.signMessage,
signer1.getEVMAddress(),
rpcURL,
apiKey
);
const result = await smartWallet.buildUserOperations(accountOperations, [], []);
// Collect signatures from required signers
const signatures: `0x${string}`[] = [];
const requiredSigners = [signer1, signer2]; // 2 of 3
for (const userOp of result.userOps) {
// Collect signatures from required signers
const sigs = await Promise.all(
requiredSigners.map(signer => signer.signMessage(toBytes(userOp.userOpHash)))
);
// Combine signatures (multisig format)
signatures.push(combineMultisigSignatures(sigs));
}
// Execute with collected signatures
await smartWallet.provideSignaturesAndRequestSendUserOperations(
result.userOps,
result.accessList,
signatures
);Best Practices
- Choose Threshold Carefully: Balance security and convenience
- Distribute Signers: Don't store all keys in one place
- Use Different Key Types: Mix HSM, software, and passkeys
- Plan for Key Loss: Have recovery procedures
- Document Signers: Keep records of all signer addresses
- Test Thresholds: Test different threshold configurations
Common Patterns
Treasury Management
// 3-of-5 treasury wallet
const treasury = await client.createWallet({
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'treasury@example.com',
signers: [
'0x...', // CEO
'0x...', // CFO
'0x...', // CTO
'0x...', // Legal
'0x...' // Operations
],
threshold: '3'
});Escrow Services
// 2-of-3 escrow wallet
const escrow = await client.createWallet({
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'escrow-12345',
signers: [
'0x...', // Buyer
'0x...', // Seller
'0x...' // Escrow service
],
threshold: '2'
});Adding/Removing Signers
To modify signers, you need to execute a transaction on the wallet contract:
// Add new signer
await client.execute({
operations: [{
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'org@example.com',
to: walletAddress,
funcSignature: 'addSigner(address,(bool,bool,bool,bool))',
funcParams: [newSignerAddress, [true, true, true, true]]
}]
});
// Remove signer
await client.execute({
operations: [{
walletCustody: CustodyType.MULTISIG_VALIDATOR,
salt: 'org@example.com',
to: walletAddress,
funcSignature: 'removeSigner(address)',
funcParams: [signerToRemove]
}]
});Security Considerations
- Key Distribution: Store signer keys in different locations
- Backup Procedures: Have recovery plans for lost keys
- Access Control: Limit access to signer keys
- Monitoring: Track all multisig transactions
- Audit Trails: Maintain records of all approvals
Next Steps
- Passkey Wallets - Learn about passkey integration
- Troubleshooting - Common issues and solutions
- Custody Types - Understand all custody types
🔐 Enhanced Security: Multisig wallets provide distributed control and enhanced security through multiple signature requirements.