4.3 Custody and MPC Integration
Institutional DeFi vaults primarily rely on non-custodial key management solutions, where the underlying assets are secured by the institution itself or a licensed, technology-enabled custodian.
MPC Technology Overview
Multiparty Computation (MPC) allows multiple parties to jointly compute a function over their inputs while keeping those inputs private. For digital asset custody, MPC enables distributed key generation and signing without ever reconstructing the full private key.
MPC-CMP Protocol
Modern MPC implementations use MPC-CMP (Multiparty Computation - Canetti-Makriyannis-Peled), which provides:
- Single-round signing: Low latency for production use
- Threshold signatures: t-of-n signing with configurable threshold
- Proactive security: Key shares can be refreshed without changing the public key
- Robust to node failure: Continues operating with threshold available
Key Requirements
1. Multichain Address Consistency
The custody solution must maintain an identical vault address across all target EVM chains:
Address Derivation:
Private Key → Public Key → Ethereum Address
0x742d... (same on all EVM chains)
Benefits:
✓ Simplified cross-chain management
✓ Unified accounting
✓ Single custody integration
✓ Easier user experience2. Auditability
Beyond policy audit provided by Canton, the MPC system must track all asset movements:
interface CustodyAuditLog {
timestamp: number;
operation: 'sign' | 'transfer' | 'swap';
chain: string;
txHash: string;
vaultAddress: string;
cantonIntentId: string;
signers: string[]; // Which key shares participated
policyValidation: boolean;
}Integration Patterns
Pattern 3: Hybrid Implementation (Recommended)
Canton guarantees policy compliance, while MPC provides custody and execution speed.
┌────────────────────────────────┐
│ Canton Policy Layer │
│ • Enforces VaultPolicy │
│ • Generates signed Intent │
└────────────┬───────────────────┘
│ Verified Intent
│
┌────────────▼───────────────────┐
│ Relayer Service │
│ • Verifies Canton signature │
│ • Prepares raw transaction │
└────────────┬───────────────────┘
│ Unsigned Tx +
│ Canton Intent
┌────────────▼───────────────────┐
│ MPC Cluster │
│ • Validates against policy │
│ • Distributed signing │
│ • Broadcasts transaction │
└────────────┬───────────────────┘
│ Signed Tx
│
┌────────────▼───────────────────┐
│ Public Blockchain │
│ • Executes transaction │
└────────────────────────────────┘MPC Policy Enforcement
The MPC service must mirror Canton policy constraints:
interface MPCPolicyEngine {
// Check transaction against policy
async validateTransaction(
tx: Transaction,
cantonIntent: ExecutionIntent
): Promise<ValidationResult>;
// Enforce limits
checkDailyLimit(amount: BigNumber): Promise<boolean>;
checkWhitelist(address: string): Promise<boolean>;
checkVelocityLimit(timeWindow: number): Promise<boolean>;
}
class MPCService {
async signTransaction(request: SignRequest): Promise<SignedTx> {
// 1. Verify Canton intent
const intentValid = await this.verifyCantonSignature(
request.cantonIntent
);
if (!intentValid) {
throw new Error('Invalid Canton intent');
}
// 2. Validate against MPC policy
const policyCheck = await this.policyEngine.validateTransaction(
request.transaction,
request.cantonIntent
);
if (!policyCheck.valid) {
throw new Error(`Policy violation: ${policyCheck.reason}`);
}
// 3. Execute MPC signing ceremony
const signature = await this.mpcSign(
request.transaction,
this.keyShares
);
// 4. Audit log
await this.auditLog.record({
operation: 'sign',
cantonIntentId: request.cantonIntent.id,
txHash: computeTxHash(request.transaction, signature),
policyValidation: true
});
return {
...request.transaction,
signature
};
}
}MPC Providers
Leading Solutions
| Provider | Features | Use Case |
|---|---|---|
| Fireblocks | Enterprise-grade, insurance, wide chain support | Institutional custody |
| Qredo | Decentralized MPC, Layer 2 settlement | Cross-chain DeFi |
| Sepior | FIPS 140-2 certified, on-premise | Regulated entities |
| Coinbase Prime | Integrated with exchange, prime brokerage | Hedge funds |
| Anchorage Digital | OCC-chartered bank, regulatory clarity | US institutions |
Integration Example: Fireblocks
import { FireblocksSDK } from '@fireblocks/sdk';
class FireblocksCustody implements CustodyProvider {
private fireblocks: FireblocksSDK;
constructor(apiKey: string, privateKeyPath: string) {
this.fireblocks = new FireblocksSDK(
privateKeyPath,
apiKey
);
}
async signAndSubmit(
transaction: Transaction,
cantonIntent: ExecutionIntent
): Promise<string> {
// Create Fireblocks transaction
const txInfo = await this.fireblocks.createTransaction({
operation: 'CONTRACT_CALL',
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultAccountId
},
destination: {
type: 'EXTERNAL_WALLET',
oneTimeAddress: {
address: transaction.to
}
},
assetId: this.getAssetId(transaction.chainId),
amount: transaction.value.toString(),
extraParameters: {
contractCallData: transaction.data
},
note: `Canton Intent: ${cantonIntent.id}`,
externalTxId: cantonIntent.nonce.toString()
});
// Wait for confirmation
const result = await this.waitForConfirmation(txInfo.id);
return result.txHash;
}
}Security Considerations
Threshold Configuration
Conservative (2-of-3):
• 2 signatures required
• Tolerates 1 node failure
• Higher security, moderate availability
Balanced (3-of-5):
• 3 signatures required
• Tolerates 2 node failures
• Balanced security and availability
High Availability (5-of-9):
• 5 signatures required
• Tolerates 4 node failures
• Maximum availabilityKey Share Distribution
Geographic Distribution:
Share 1: US East (AWS)
Share 2: US West (Azure)
Share 3: EU West (GCP)
Share 4: Asia Pacific (Alibaba Cloud)
Share 5: On-premise HSM
Prevents:
✓ Single data center failure
✓ Regional disasters
✓ Cloud provider outages
✓ Regulatory seizure riskOperational Security
// Require multi-person approval for sensitive operations
interface ApprovalPolicy {
operations: {
keyRefresh: { required: 2, timeout: '1h' };
thresholdChange: { required: 3, timeout: '24h' };
emergencyWithdraw: { required: 3, timeout: '15m' };
};
}
// Implement velocity limits
interface VelocityLimits {
hourly: BigNumber; // Max per hour
daily: BigNumber; // Max per day
perTransaction: BigNumber; // Max per tx
}Best Practices
1. Policy Synchronization
Ensure Canton and MPC policies stay synchronized:
async function syncPolicies(): Promise<void> {
// Fetch latest Canton policy
const cantonPolicy = await canton.fetchPolicy(policyId);
// Update MPC policy engine
await mpc.updatePolicy({
maxExposure: cantonPolicy.maxExposurePerc,
allowedProtocols: cantonPolicy.allowedProtocols,
dailyLimit: cantonPolicy.dailyLimit,
whitelistedAddresses: cantonPolicy.allowedContracts
});
// Verify sync
const mpcPolicy = await mpc.getPolicy();
assert.deepEqual(mpcPolicy, cantonPolicy);
}2. Disaster Recovery
Recovery Procedure:
1. Secure key share backups in cold storage
2. Implement Shamir's Secret Sharing for recovery keys
3. Regular DR drills (quarterly)
4. Document recovery procedures
5. 24/7 on-call rotation3. Monitoring
const metrics = {
mpcLatency: new Histogram({
name: 'mpc_signing_latency_seconds',
help: 'Time to complete MPC signing ceremony'
}),
policyViolations: new Counter({
name: 'mpc_policy_violations_total',
help: 'Number of policy violations caught by MPC'
}),
keyShareHealth: new Gauge({
name: 'mpc_key_share_health',
help: 'Health status of each key share',
labelNames: ['share_id', 'location']
})
};4. Audit Trail
Maintain comprehensive custody audit logs:
CREATE TABLE custody_audit_log (
id SERIAL PRIMARY KEY,
timestamp TIMESTAMPTZ NOT NULL,
operation TEXT NOT NULL,
canton_intent_id TEXT NOT NULL,
vault_address TEXT NOT NULL,
chain TEXT NOT NULL,
tx_hash TEXT,
signers JSONB NOT NULL, -- Which key shares signed
policy_validated BOOLEAN NOT NULL,
metadata JSONB
);
-- Index for fast lookups
CREATE INDEX idx_intent ON custody_audit_log(canton_intent_id);
CREATE INDEX idx_timestamp ON custody_audit_log(timestamp DESC);