EU MiCA CASP Client Asset Safeguarding 2026: Art.70 Segregation, Proof-of-Reserves, and Insurance Requirements
Post #1381 in the sota.io EU Cyber Compliance Series
When a CASP holds client funds — whether crypto-assets or fiat — those assets belong to clients, not to the platform. MiCA Article 70 translates this principle into hard legal obligations: strict segregation, continuous proof-of-holdings, and mandatory insurance coverage. This is post #3/5 in the EU-MICA-CASP-DEVELOPER-2026 series.
The June 30, 2026 grace period is less than five weeks away. If your platform custodies client assets, your engineering and compliance teams need to understand exactly what Art.70 demands — and what the technical architecture to meet it looks like.
What MiCA Art.70 Actually Requires
Article 70 of Regulation (EU) 2023/1114 (MiCA) establishes the client asset protection framework for CASPs. The obligations apply to:
- Crypto-asset custodians (Art.70 fully applies)
- Exchanges holding client assets between trades
- Portfolio managers managing client crypto
- Brokers with temporary custody during settlement
Art.70(1): Prohibition on Commingling
CASPs shall not use client crypto-assets for their own account. This sounds obvious, but the engineering implications are severe:
| Prohibited Action | Why It Violates Art.70(1) |
|---|---|
| Using client BTC as liquidity for market-making | Own-account use of client assets |
| Pooling client ETH in a single hot wallet with operating funds | Commingling, balance attribution impossible |
| Using client stablecoins to cover exchange fees | Direct own-account use |
| Rehypothecating client positions for DeFi yield | Use without explicit written consent |
The only exception: CASPs may use client crypto-assets for their own account if the client has given prior, explicit, written consent — and this must be documented with a clear record of which assets, for what period, and with what risk disclosure.
Art.70(2): Segregation Architecture
Client crypto-assets must be held separately from CASP's own crypto-assets. The practical requirement is wallet-level segregation, not just accounting-level:
CASP Wallet Architecture (Art.70(2) Compliant):
┌─────────────────────────────────────────────────────┐
│ CASP OWN FUNDS │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ Operating Wallet│ │ Reserve / Capital Wallet │ │
│ │ (Hot — Ops) │ │ (Cold — Capital Adequacy) │ │
│ └─────────────────┘ └──────────────────────────┘ │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ CLIENT ASSETS (Segregated) │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ Client Hot │ │ Client Cold │ │
│ │ Wallet Pool │ │ Storage (≥95%)│ │
│ │ (< 5% total) │ │ │ │
│ └───────────────┘ └───────────────┘ │
│ Per-client accounting: individual balance ledger │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ CLIENT FIAT (Bank Accounts) │
│ Separate bank account(s) designated "CLIENT FUNDS" │
│ Ring-fenced: CASP bankruptcy remote │
└─────────────────────────────────────────────────────┘
The "95/5 Rule" (Industry Standard for Art.70 Compliance): While MiCA does not specify exact percentages, ESMA's technical guidance and NCA supervisory expectations have converged on keeping at least 95% of client crypto in cold storage and at most 5% in hot wallets for operational liquidity.
Art.70(3): Client Consent for Asset Use
If your platform uses client assets (e.g., for DeFi yield products), you need:
- Explicit written consent per client, per use case
- Risk disclosure covering counterparty risk, volatility, liquidation scenarios
- Revocability: Client can withdraw consent within 30 days
- Accounting separation: Clear ledger entry distinguishing consented vs. non-consented balances
- Return guarantee: Clear mechanism to return equivalent assets
Art.70(4)–(6): Fiat Fund Investment
When CASPs hold client fiat (EUR, GBP, etc.), they may invest it only in:
| Asset Class | Permitted | Conditions |
|---|---|---|
| Government bonds (EU/EEA sovereign) | ✅ Yes | Liquid, investment grade |
| Money market funds (UCITS) | ✅ Yes | Daily liquidity |
| Central bank deposits | ✅ Yes | Preferred |
| Corporate bonds | ⚠️ Limited | Must be investment grade, ≤1 year maturity |
| Crypto-assets | ❌ No | Art.70(4) prohibits fiat → crypto investment |
| Equities | ❌ No | Not permitted under Art.70 |
Any returns from these investments belong to clients unless the CASP discloses and clients consent to a different arrangement.
Technical Implementation: Wallet Segregation Architecture
Hot/Cold Wallet Separation
# Conceptual wallet segregation tracker
from dataclasses import dataclass, field
from decimal import Decimal
from enum import Enum
from typing import Dict, List
class WalletType(Enum):
CASP_OPERATING = "casp_operating"
CASP_CAPITAL = "casp_capital"
CLIENT_HOT = "client_hot"
CLIENT_COLD = "client_cold"
@dataclass
class AssetBalance:
asset: str # "BTC", "ETH", "USDC"
amount: Decimal
wallet_type: WalletType
wallet_address: str
is_client_owned: bool
class Art70SegregationChecker:
"""Validates MiCA Art.70 segregation compliance at each state change."""
def check_hot_ratio(
self,
client_hot: Decimal,
client_cold: Decimal,
asset: str
) -> dict:
total = client_hot + client_cold
if total == 0:
return {"compliant": True, "ratio": 0}
hot_ratio = float(client_hot / total)
return {
"asset": asset,
"hot_ratio": hot_ratio,
"compliant": hot_ratio <= 0.05, # 95% cold floor
"warning": hot_ratio > 0.03,
"client_hot": str(client_hot),
"client_cold": str(client_cold),
}
def check_commingling(
self,
wallet_address: str,
balances: List[AssetBalance]
) -> bool:
"""Returns False if wallet contains both client and CASP assets."""
wallet_balances = [b for b in balances if b.wallet_address == wallet_address]
has_client = any(b.is_client_owned for b in wallet_balances)
has_casp = any(not b.is_client_owned for b in wallet_balances)
return not (has_client and has_casp)
def get_segregation_report(self, balances: List[AssetBalance]) -> dict:
"""Full Art.70(2) segregation compliance report."""
violations = []
# Check for commingling
addresses = set(b.wallet_address for b in balances)
for addr in addresses:
if not self.check_commingling(addr, balances):
violations.append(f"Commingling detected at {addr}")
# Check hot ratios per asset
hot_ratios = {}
for balance in balances:
asset = balance.asset
if asset not in hot_ratios:
hot_ratios[asset] = {"hot": Decimal(0), "cold": Decimal(0)}
if balance.wallet_type == WalletType.CLIENT_HOT:
hot_ratios[asset]["hot"] += balance.amount
elif balance.wallet_type == WalletType.CLIENT_COLD:
hot_ratios[asset]["cold"] += balance.amount
ratio_checks = [
self.check_hot_ratio(v["hot"], v["cold"], asset)
for asset, v in hot_ratios.items()
]
non_compliant = [r for r in ratio_checks if not r["compliant"]]
return {
"commingling_violations": violations,
"hot_ratio_violations": non_compliant,
"overall_compliant": len(violations) == 0 and len(non_compliant) == 0,
}
Per-Client Ledger Architecture
Art.70 requires that each client's exact holdings can be reconstructed at any moment. This means:
-- Client asset ledger schema (Art.70(2) compliant)
CREATE TABLE client_asset_ledger (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
client_id UUID NOT NULL REFERENCES clients(id),
asset_symbol VARCHAR(20) NOT NULL, -- "BTC", "ETH", "USDC"
amount NUMERIC(38,18) NOT NULL, -- Precise to 18 decimal places
wallet_type VARCHAR(30) NOT NULL, -- "hot", "cold", "pending_withdrawal"
on_chain_address VARCHAR(255), -- Actual wallet address holding the asset
on_chain_txhash VARCHAR(255), -- Deposit/withdrawal transaction
created_at TIMESTAMPTZ DEFAULT NOW(),
event_type VARCHAR(50) NOT NULL, -- "deposit", "withdrawal", "trade", "fee"
balance_after NUMERIC(38,18) NOT NULL -- Running balance (for audit)
);
-- Ensure per-client balance is always reconstructable
CREATE INDEX idx_client_asset ON client_asset_ledger(client_id, asset_symbol, created_at);
-- Regulatory view: real-time client holdings
CREATE VIEW client_current_holdings AS
SELECT
client_id,
asset_symbol,
SUM(amount) AS total_balance,
MAX(created_at) AS last_updated
FROM client_asset_ledger
GROUP BY client_id, asset_symbol
HAVING SUM(amount) > 0;
Multi-Signature Key Management
For cold storage, MiCA's governance and systems-security requirements (Art.68, covered in post #2) combined with Art.70 create a practical requirement for multi-signature (multisig) custody:
| Setup | Threshold | Use Case |
|---|---|---|
| 2-of-3 multisig | 2 of 3 keys | Small/medium CASP cold storage |
| 3-of-5 multisig | 3 of 5 keys | Enterprise custody |
| MPC (Multi-Party Computation) | Threshold depends on implementation | Institutional grade |
Key storage standards:
- At least one key shard in an HSM (Hardware Security Module) certified to FIPS 140-3 Level 3
- Geographic distribution of key shards (minimum 2 EU jurisdictions)
- Key ceremony documentation (required for NCA audit)
- Annual key rotation for operational keys; cold storage keys reviewed annually
DLT Proof-of-Reserves
MiCA does not explicitly mandate proof-of-reserves, but NCAs — particularly BaFin (Germany), AMF (France), and CSSF (Luxembourg) — have signaled through supervisory guidance that CASPs should be able to demonstrate asset sufficiency on demand. The industry standard is a Merkle tree proof-of-reserves system.
How Merkle Proof-of-Reserves Works
Root Hash (H_root)
/ \
H_AB (left) H_CD (right)
/ \ / \
H_A (client 1) H_B (client 2) H_C (client 3) H_D (client 4)
balance: 1 BTC balance: 0.5 BTC balance: 2 BTC balance: 0.1 BTC
Total client liability: 3.6 BTC
On-chain wallet holdings: ≥ 3.6 BTC (verified via blockchain explorer)
Each client can verify their balance is included without seeing other clients' balances.
Implementation Architecture
import hashlib
from typing import List, Tuple, Optional
class MerkleProofOfReserves:
"""
Generates Merkle proof-of-reserves attestations per MiCA Art.70
supervisory expectations.
"""
def _hash_leaf(self, client_id: str, asset: str, balance: str) -> str:
"""Hash a single client balance entry."""
data = f"{client_id}:{asset}:{balance}"
return hashlib.sha256(data.encode()).hexdigest()
def _hash_pair(self, left: str, right: str) -> str:
combined = left + right
return hashlib.sha256(combined.encode()).hexdigest()
def build_tree(self, leaves: List[Tuple[str, str, str]]) -> List[List[str]]:
"""
Build Merkle tree from (client_id, asset, balance) tuples.
Returns tree levels for proof generation.
"""
# Create leaf layer
layer = [self._hash_leaf(c, a, b) for c, a, b in leaves]
# Pad to even number
if len(layer) % 2 != 0:
layer.append(layer[-1])
tree = [layer]
while len(layer) > 1:
next_layer = []
for i in range(0, len(layer), 2):
next_layer.append(self._hash_pair(layer[i], layer[i+1]))
if len(next_layer) % 2 != 0 and len(next_layer) > 1:
next_layer.append(next_layer[-1])
tree.append(next_layer)
layer = next_layer
return tree
def generate_client_proof(
self,
client_id: str,
asset: str,
balance: str,
all_leaves: List[Tuple[str, str, str]]
) -> dict:
"""Generate proof that allows client to verify their balance is included."""
tree = self.build_tree(all_leaves)
leaf_hash = self._hash_leaf(client_id, asset, balance)
# Find index
idx = tree[0].index(leaf_hash) if leaf_hash in tree[0] else -1
if idx == -1:
return {"error": "Client not found in tree"}
# Generate sibling path
proof_path = []
for level in tree[:-1]:
sibling_idx = idx + 1 if idx % 2 == 0 else idx - 1
if sibling_idx < len(level):
proof_path.append({
"hash": level[sibling_idx],
"direction": "right" if idx % 2 == 0 else "left"
})
idx //= 2
return {
"client_id": client_id,
"asset": asset,
"balance": balance,
"leaf_hash": leaf_hash,
"root": tree[-1][0],
"proof": proof_path,
}
def get_total_liability(
self,
leaves: List[Tuple[str, str, str]]
) -> dict:
"""Aggregate client liabilities per asset for reserve check."""
from decimal import Decimal
totals: dict[str, Decimal] = {}
for _, asset, balance in leaves:
totals[asset] = totals.get(asset, Decimal(0)) + Decimal(balance)
return {asset: str(total) for asset, total in totals.items()}
Publishing Proof-of-Reserves
Best practice (following Kraken, Binance.US, and EU-native exchanges):
- Monthly attestation cycle: Publish root hash + total liabilities
- On-chain anchoring: Anchor the Merkle root in an Ethereum/Bitcoin OP_RETURN transaction for immutability
- Third-party auditor: Independent auditor verifies wallet addresses hold ≥ declared liabilities
- Client self-verification portal: Clients can verify their balance is included without seeing others'
- NCA reporting: Include latest attestation hash in monthly regulatory report
Insurance and Professional Indemnity Requirements
MiCA Article 67 (Prudential requirements) requires CASPs to maintain own funds that may be satisfied via professional indemnity insurance (PII) or a comparable guarantee. The specific requirements:
Minimum Coverage Thresholds
| CASP Size | Minimum PII Coverage |
|---|---|
| Annual revenue < €1M | €500,000 per claim |
| Annual revenue €1M–€10M | €1,000,000 per claim |
| Annual revenue > €10M | 10% of annual revenue (min €2M) |
| Custodians with client assets > €100M | €5,000,000+ (NCA discretion) |
What Must Be Covered
The insurance policy must cover losses arising from:
- Operational failures: System downtime, processing errors, incorrect transactions
- Cyber incidents: Hacks, key compromise, theft of client assets
- Employee misconduct: Fraud, unauthorized access, insider attacks
- Third-party vendor failures: Cloud provider outages affecting client assets
- Smart contract failures: Bugs in CASP-deployed contracts holding client funds
Insurance vs. Capital Adequacy (Art.67)
CASPs can satisfy Art.67 via either:
| Option | Mechanism | Trade-Off |
|---|---|---|
| Professional indemnity insurance | Third-party insurer | Lower capital lock-up, annual renewal risk |
| Own capital reserve | Additional capital ≥ Art.67 minimum | Capital tied up, no annual renewal risk |
| Hybrid (partial insurance + partial capital) | Mixed | Flexibility, regulatory approval needed |
Practical note: Most EU NCAs prefer a hybrid approach for custodians — minimum own capital (Art.67) plus PII for tail risks. Pure insurance-only arrangements have faced pushback from BaFin and CSSF during authorization reviews.
Acceptable Insurance Providers
Not every insurer is acceptable. MiCA-compliant PII should come from:
- Insurers licensed in the EU (Solvency II compliant)
- Lloyd's of London syndicates (specifically for crypto risks)
- Specialty cyber/fintech insurers: Hiscox, Markel, AXA XL (crypto division)
Document requirement for NCA submission: Policy declaration page + coverage schedule must be submitted during authorization and updated annually.
Bankruptcy Remoteness for Client Assets
One of the most important Art.70 principles: client assets must be bankruptcy remote — i.e., if the CASP becomes insolvent, client assets cannot be claimed by CASP creditors.
Legal Structure Requirements
Compliant Structure:
┌────────────────────────────────┐
│ CASP Entity (Licensed) │
│ - Authorization holder │
│ - Operates exchange/custody │
│ - Has own capital (Art.67) │
└──────────┬─────────────────────┘
│ Holds client assets AS TRUSTEE
│ (not as owner)
▼
┌────────────────────────────────┐
│ Client Asset Custodial Account │
│ - Designated "CLIENT FUNDS" │
│ - Ring-fenced bank account │
│ - Not available to CASP │
│ creditors in insolvency │
│ - Separate from CASP's own │
│ capital accounts │
└────────────────────────────────┘
For crypto-assets specifically, the trust/custodial structure must be reflected in:
- Wallet naming/labeling conventions in blockchain explorer metadata
- Internal accounting systems (balance sheet must show client assets as liabilities, not assets)
- Terms of service / client agreement (CASP acts as custodian/trustee, not owner)
- NCA registration documentation
Key Engineering Controls for Bankruptcy Remoteness
| Control | Implementation |
|---|---|
| Separate database schema for client assets | Client funds table isolated from CASP treasury |
| Dual authorization for fund movements | No single employee can move client funds alone |
| Regular reconciliation against on-chain | Automated daily reconciliation with alerts on discrepancy >0.01% |
| Audit logs with immutable storage | Write-once audit trail (S3 Object Lock or WORM storage) |
| Emergency freeze capability | Admin can halt withdrawals in <60 seconds if suspicious activity detected |
Compliance Checklist: MiCA Art.70 Client Asset Safeguarding
Part A — Wallet Architecture
- Client crypto-assets held in wallets separate from CASP own funds
- ≥95% of client crypto in cold storage at all times
- Hot wallet contains ≤5% of total client crypto holdings
- Multisig (2-of-3 minimum) or MPC implemented for all wallets
- HSM-based key storage certified to FIPS 140-3 Level 3
- Geographic distribution of key shards across ≥2 EU jurisdictions
- Key ceremony documented and available for NCA audit
- Per-client balance ledger allows full reconstruction at any time
Part B — Fiat Fund Segregation
- Client fiat held in designated "CLIENT FUNDS" bank account(s)
- Separate bank account(s) cannot be claimed by CASP creditors
- Client fiat invested only in permitted assets (Art.70(4))
- Investment returns allocated per Art.70 (client-owned unless disclosed)
- Daily reconciliation of bank account balance vs. client ledger
Part C — Proof-of-Reserves
- Merkle tree proof-of-reserves implemented or roadmapped
- Monthly internal attestation cycle documented
- Third-party auditor engaged for annual reserve verification
- On-chain wallet addresses disclosed to NCA
- Client self-verification portal available (optional but recommended)
Part D — Insurance and Capital
- Professional indemnity insurance obtained from EU-licensed insurer
- PII coverage meets Art.67 minimum thresholds for your revenue tier
- Policy covers cyber incidents, employee misconduct, operational failures
- PII policy submitted to NCA during authorization (and renewed annually)
- Own capital maintained per Art.67 (separate from client assets)
Part E — Operational Controls
- Client consent process documented for any asset use (Art.70(3))
- Bankruptcy-remote legal structure reflected in terms of service
- Internal balance sheet shows client assets as liabilities (not CASP assets)
- Daily automated reconciliation with alert thresholds
- Emergency freeze capability tested and documented
- Write-once audit logs for all asset movements
Part F — Governance
- Designated "custody officer" or equivalent responsible for Art.70 compliance
- Board-level oversight of custody risk framework
- Annual third-party custody audit (separate from financial audit)
- Incident response runbook specific to client asset loss scenarios
Common Art.70 Mistakes and How to Avoid Them
Mistake 1: Accounting Segregation ≠ Wallet Segregation
The Error: Some platforms maintain separate accounting records but hold all assets in a single set of wallets. This violates Art.70(2).
The Fix: Segregation must be at the wallet level, not just the database level. Each wallet must hold either client assets or CASP assets, never both.
Mistake 2: "We Don't Custody" as a Defense
The Error: Claiming your platform is "non-custodial" while briefly holding client assets during trade settlement.
The Fix: Settlement windows of 1–24 hours are still custody under MiCA. Even temporary possession during trade execution falls under Art.70 if clients cannot independently control the assets during that window.
Mistake 3: Ignoring the Fiat Side
The Error: Building excellent crypto segregation while commingling client EUR in the CASP's general operating bank account.
The Fix: Client fiat must be in a separate, designated bank account. The bank must acknowledge the custodial nature of the account in writing.
Mistake 4: Missing the Consent Documentation Trail
The Error: Offering yield products on client assets without obtaining documented, revocable, per-client consent.
The Fix: Build a consent management system before launching any yield/staking product. Each consent must be stored with timestamp, asset, amount, and the risk disclosure presented.
What's Next in the EU-MICA-CASP-DEVELOPER-2026 Series
This post covered Art.70 client asset safeguarding — the custody and segregation obligations. The remaining posts in this series will cover:
- Post #4/5: MiCA CASP Governance and Risk Management: Art.67–72 Prudential Requirements, Board Obligations, and Conflicts of Interest
- Post #5/5: MiCA CASP Compliance Finale: Complete SaaS Developer Toolkit — Authorization to Operations Checklist 2026
Earlier posts in the series:
- Post #1/5: EU MiCA CASP Compliance for SaaS Developers: Authorization, Technical Requirements and Operating Rules 2026
- Post #2/5: EU MiCA CASP Technical Requirements 2026: IT Systems, Cybersecurity and AML/KYC Integration for SaaS Developers
sota.io and MiCA Infrastructure Compliance
If you're building a CASP and need EU-sovereign infrastructure that supports MiCA's data residency, audit trail, and Art.70 segregation requirements, sota.io provides managed deployments on Hetzner Germany — no US parent company, no CLOUD Act exposure. Your custody systems, KYC data, and client asset ledgers stay under EU jurisdiction at all times.
See also:
- EU MiCA CASP Technical Requirements: IT Systems, Cybersecurity, AML/KYC — The operational backbone
- EU DORA Compliance Tools 2026: Complete Stack — DORA overlap for financial CASPs
- EU CRA Compliance Guide — Software security obligations that apply alongside MiCA
EU-Native Hosting
Ready to move to EU-sovereign infrastructure?
sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.