ByAUJay
Which Custodial Services Support Dual-Control MPC Plus On-Chain Audits, and How to Verify Attestation Data Programmatically?
Dual‑control MPC is quickly becoming table stakes for institutional crypto security, but decision‑makers also want on‑chain auditability they (and their users) can verify without waiting for PDF reports. This guide pinpoints which custodians actually combine dual‑control MPC with verifiable on‑chain attestations today, and shows you how to programmatically verify those attestations in code.
Summary: Only a handful of providers pair enterprise‑grade, dual‑control MPC with production on‑chain audits. BitGo is the primary custodian with both in-market; others offer strong MPC and governance but require you to integrate an external on‑chain Proof of Reserves (PoR) feed yourself. Below you’ll find exact features, caveats, and copy‑pasteable verification snippets.
Quick definitions you can act on (and skip the fluff)
- Dual‑control MPC: Separation of duties enforced by policy (e.g., “four‑eyes”) on top of a threshold signature scheme. Practically: 2–5 independent approvers must satisfy rules before any signing flow completes. Fireblocks and BitGo expose this as a policy/quorum engine; Cobo and Qredo expose co‑managed roles and approvers. (developers.fireblocks.com)
- On‑chain audits: Real‑time reserve proofs published to a public chain (e.g., Chainlink PoR feeds) that protocols and users can read trust‑minimized at runtime. Typical uses: wrapped BTC, stablecoins, tokenized RWAs. Caveat: many PoR feeds rely on self‑attested addresses or third‑party reporters—verification is technical, but also governance‑ and process‑dependent. (chain.link)
Who actually supports both today?
Below are the providers that (a) implement dual‑control MPC with enterprise policy/quorum controls and (b) have production on‑chain audit integrations you can verify on mainnet, or provide the building blocks and docs for you to publish audits programmatically.
1) BitGo — Dual‑control MPC with production on‑chain PoR (WBTC, others)
- Dual‑control MPC: BitGo supports MPC/TSS and policy‑based approvals (2‑of‑3 key architecture; approval rules at wallet/enterprise scope). (developers.bitgo.com)
- On‑chain audits live: BitGo pioneered on‑chain audits for WBTC via Chainlink PoR. You can read reserves from Chainlink feeds that monitor BitGo’s BTC custodian addresses and compare to minted supply. (businesswire.com)
- Additional PoR building blocks: BitGo documents a PoR workflow and APIs to enumerate wallets/addresses and publish balances for auditor or oracle consumption. If you’re an exchange, fund, or issuer using BitGo, you can stand up verifiable PoR pipelines using their REST endpoints plus a Merkleized liabilities snapshot. (developers.bitgo.com)
- Concrete feeds you can hit:
- WBTC/WBTC.e PoR feeds are publicly browsable on Chainlink’s data site (e.g., Avalanche WBTC.e PoR; note the “self‑attested address” disclosure). (data.chain.link)
- Other BitGo‑custodied wrapped BTC variants have feeds (e.g., bgbtc‑por). Always inspect the “Data Source” and “Reporter” info. (data.chain.link)
Bottom line: If you need dual‑control MPC plus already‑running PoR with public feeds and vendor‑maintained docs, BitGo is the most turnkey option today. (developers.bitgo.com)
2) Coinbase (for cbBTC PoR) — On‑chain audits present, but custody isn’t MPC
- Coinbase publishes a Chainlink PoR feed for cbBTC on Base/Ethereum, providing on‑chain reserve transparency. However, Coinbase’s institutional custody stack is based on HSMs and segregation controls—not MPC—so it does not fully meet the “dual‑control MPC” criterion for all assets. Use Coinbase here as an example of a mature PoR implementation rather than an MPC provider. (data.chain.link)
3) Fireblocks — Dual‑control MPC with SGX‑hardened policy engine; PoR requires integration
- Dual‑control MPC: Fireblocks runs MPC across SGX enclaves and enforces “four‑eyes” style workflows via an approval quorum and policy engine (admin quorum for configuration, approval groups per domain, granular transaction rules). (developers.fireblocks.com)
- On‑chain audits: Fireblocks does not natively publish PoR feeds. Clients commonly integrate Chainlink PoR or an auditor to publish on‑chain attestations (you provide addresses via API, or let an auditor/PoR oracle read them). (chain.link)
When Fireblocks is your signing stack for an issued/wrapped asset, you can wire your mint logic to consume a Chainlink PoR feed and gate issuance programmatically (guide and code below). (blog.chain.link)
4) Cobo — Co‑managed dual‑control MPC; bring‑your‑own PoR
- Dual‑control MPC: Cobo’s co‑managed custody splits MPC key shares (default 2‑of‑3), assigns roles (admin/spender/approver), and supports per‑wallet risk policies and TEE‑backed secure auth (Cobo Guard). (docs.cobo.com)
- On‑chain audits: No default PoR feed; integrate Chainlink PoR or work with an auditor to publish reserves on‑chain. (chain.link)
5) Qredo — Decentralized MPC with on‑chain governance… but PoR for external assets is not native
- Dual‑control MPC: Qredo uses distributed MPC and enforces approvals via on‑chain governance recorded on the Qredo Network; roles, whitelists, and multi‑level policies are first‑class. (qredo.com)
- On‑chain audits: Governance is on‑chain (Qredo chain), but reserve attestations for assets on L1/L2s require an external oracle/auditor. (chain.link)
Bottom‑line mapping (January 7, 2026)
- Dual‑control MPC + production on‑chain PoR for at least one widely used asset: BitGo (e.g., WBTC). (businesswire.com)
- Dual‑control + publishable PoR with extra work: Fireblocks, Cobo, Qredo (you integrate Chainlink PoR or an auditor API). (developers.fireblocks.com)
- Strong on‑chain PoR without MPC custody: Coinbase for cbBTC. (data.chain.link)
Note the PoR caveat: Chainlink PoR is the de‑facto standard for on‑chain reserves, but suppliers and reporters vary (self‑attested addresses, third‑party reporters). You must read the feed metadata and validate your trust model accordingly. (chain.link)
How to verify on‑chain attestation data programmatically
Below are battle‑tested patterns you can drop into your stacks today.
A) Solidity: Gate mint/redemption with Chainlink PoR
Use Chainlink’s Aggregator-style interface to compare a PoR feed’s reported reserves with your token’s totalSupply before mints or redemptions. Example shows cbBTC on Base or WBTC.e on Avalanche; swap the feed address per your target chain.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; contract MintWithPoR is ERC20Burnable { AggregatorV3Interface public porFeed; // Chainlink PoR feed uint8 public immutable porDecimals; constructor(address _porFeed) ERC20("MyWrappedBTC", "mwBTC") { porFeed = AggregatorV3Interface(_porFeed); porDecimals = porFeed.decimals(); } function reserves() public view returns (uint256) { (, int256 answer,,,) = porFeed.latestRoundData(); require(answer > 0, "invalid PoR"); // PoR answer reports satoshis or BTC depending on feed; normalize as needed return uint256(answer); } function mint(address to, uint256 amount) external { // Example policy: require reserves >= new total supply post-mint uint256 newSupply = totalSupply() + amount; require(reserves() >= newSupply, "PoR undercollateralized"); _mint(to, amount); } }
- Find feed addresses at data.chain.link and confirm reporter/source type. For instance, cbBTC on Base exposes cbbtc‑por; WBTC.e on Avalanche exposes wbtce‑por with a “self‑attested address” note—treat that in your governance. (data.chain.link)
- Chainlink’s PoR docs include guidance on “circuit breaker” mint controls and architectural patterns. (blog.chain.link)
B) Node.js/ethers: Read PoR, compare to token supply off‑chain
Use this when you control a minting backend, exchange risk engine, or a monitoring bot.
import { ethers } from "ethers"; import erc20 from "@openzeppelin/contracts/build/contracts/ERC20.json" assert { type: "json" }; const RPC = process.env.RPC_URL; // e.g., Base mainnet const provider = new ethers.JsonRpcProvider(RPC); // Example: cbBTC PoR feed on Base const POR_FEED = "0x0F8E...2519"; // cbbtc-por (verify latest address on data.chain.link) const TOKEN = "0xYourToken"; // token you want to check (e.g., cbBTC or your wrapped asset) // Chainlink Aggregator ABI (subset) const AGG_ABI = [ "function latestRoundData() view returns (uint80,int256,uint256,uint256,uint80)", "function decimals() view returns (uint8)" ]; async function main() { const feed = new ethers.Contract(POR_FEED, AGG_ABI, provider); const token = new ethers.Contract(TOKEN, erc20.abi, provider); const [ , ans ] = await feed.latestRoundData(); if (ans <= 0n) throw new Error("Invalid PoR reading"); const por = ans; // normalize to your token's units const supply = await token.totalSupply(); if (por < supply) { console.error("Under-collateralized! POR < totalSupply"); process.exit(2); } else { console.log("Collateralization OK"); } } main().catch(console.error);
- Replace POR_FEED with your target PoR feed (e.g., cbBTC on Base). Always review the “Reporter” and “Data Source” sections for self‑attestation vs. third‑party reporters. (data.chain.link)
C) BitGo: Build a PoR snapshot from custody addresses (REST) and publish it on‑chain
If you custody with BitGo but don’t have a Chainlink feed yet, you can:
- Enumerate addresses/wallets via BitGo REST (custody wallets recommended for reserves).
- Publish balances and addresses to an auditor or to your own Merkle tree.
- Have an oracle (e.g., Chainlink) read this source and update an on‑chain feed. (developers.bitgo.com)
BitGo shows how to list wallets and extract data for PoR:
# Example outline (use BitGo SDK or REST) # 1) List wallets and select reserve set curl -H "Authorization: Bearer $BITGO_TOKEN" \ "https://app.bitgo.com/api/v2/wallets" # 2) For each wallet ID, list addresses and balances curl -H "Authorization: Bearer $BITGO_TOKEN" \ "https://app.bitgo.com/api/v2/btc/wallet/<WALLET_ID>/addresses?limit=500"
From here you can:
- Dump balances into a signed JSON manifest,
- Generate a Merkle root over liabilities (customer balances), and
- Publish both the asset manifest and liabilities root on-chain or via an auditor’s API that a Chainlink External Adapter can consume. (developers.bitgo.com)
D) Verifying Merkle proofs for exchange/fund PoR (client‑side)
If your auditor issues a Merkle leaf for each user, your clients can independently verify inclusion:
import crypto from "crypto"; function hash(x) { return crypto.createHash("sha256").update(x).digest(); } /** * Verify a Merkle proof for a leaf (balance commitment). * @param {Buffer} leaf * @param {Buffer[]} proof - list of sibling hashes from leaf->root * @param {Buffer} root * @returns {boolean} */ function verifyMerkle(leaf, proof, root) { return proof.reduce((acc, sib) => { const [a,b] = Buffer.compare(acc, sib) < 0 ? [acc, sib] : [sib, acc]; return hash(Buffer.concat([a, b])); }, hash(leaf)).equals(root); }
Even if you rely on Chainlink PoR for “asset” side, giving users a Merkle proof for “liabilities” side provides stronger solvency assurance (assets ≥ liabilities). Align your auditor’s API with the feed’s update cadence and include a signed report URL in the on‑chain feed metadata. (chain.link)
E) If a vendor exposes enclave attestation (SGX/DCAP), verify quotes server‑side
Some MPC providers secure policy/approvals inside TEEs like Intel SGX. If your vendor exposes remote attestation quotes, you can verify them against Intel’s DCAP flow and bind policy execution to attested measurements (MRENCLAVE/MRSIGNER). High‑level steps (DCAP):
- Collect the ECDSA quote from the enclave.
- Send to an attestation verification service (local DCAP verifier or cloud PCCS) to validate TCB status and measurements.
- Compare measurements to an allowlist; reject requests if attestation fails or firmware is outdated. (intel.com)
Keep in mind: Fireblocks states it uses SGX to harden its policy engine and MPC flow, but providers rarely expose raw quotes to clients; negotiate this in contract if your threat model requires runtime attestation checks. (fireblocks.com)
Practical examples you can replicate
- Verifying WBTC reserves before accepting WBTC as collateral in a lending market: read the WBTC PoR feed; compare to WBTC.totalSupply(); cap LTV or disable borrows when reserve deviations exceed a threshold. (businesswire.com)
- Issuing a wrapped BTC product with Fireblocks as the signer: publish reserve addresses via BitGo‑like APIs or custodian exports; stand up a Chainlink External Adapter that reads your signed reserve manifest; gate minting via the PoR feed in your ERC‑20 contract. (chain.link)
- Monitoring cbBTC health on Base: a small bot reads cbbtc‑por every N blocks; if reserves dip under circulating supply, it alerts ops and your protocol toggles “pause” on relevant markets. (data.chain.link)
Best emerging practices (what we see working in 2025–2026)
-
Treat PoR feed metadata as part of your trust boundary. Don’t just read “answer()”—also check whether the feed is self‑attested, uses a wallet address manager, or a third‑party reporter (and document who). Build alerts for reporter changes. (data.chain.link)
-
Combine asset‑side PoR with liabilities‑side Merkle proofs. Chainlink feeds commonly cover reserves; pair that with a user‑verifiable Merkle inclusion proof for liabilities—this yields a much stronger solvency claim than PoR alone. (chain.link)
-
Enforce mint circuit breakers in code. Use Chainlink Automation or your own keeper to freeze mint/burn when PoR < supply, not after governance notices. This closes the window between under‑collateralization and response. (blog.chain.link)
-
Don’t over‑trust PoR alone; audit the process. Press and research have noted that PoR is only as good as inputs and governance (e.g., self‑attestation vs. auditor‑sourced data). Require documented data paths and sign‑offs, and version your “attestation policy” alongside code. (coindesk.com)
-
Lock change‑management behind dual‑control too. Approval quorums shouldn’t just cover transfers; they should also protect policy edits, whitelists, new signers, and feed address changes. Fireblocks and BitGo both expose admin quorum/policy‑change approvals—use them. (developers.fireblocks.com)
-
If you depend on TEEs, ask for attestation evidence. Require (or pilot) periodic enclave quote verification with DCAP. If your vendor can’t expose quotes, require SOC2 mapping to enclave controls and at least one annual third‑party review of enclave configurations. (intel.com)
Brief vendor‑by‑vendor implementation notes
-
BitGo
- Use BitGo policies to enforce “four‑eyes” per asset/amount, and REST to export reserve addresses daily. If you issue a wrapped asset, wire a Chainlink PoR feed where reporters read your signed JSON manifest of addresses+balances. (bitgo.com)
-
Fireblocks
- Set Admin Quorum and Approval Groups, then define transaction policies by asset/amount/destination. For PoR, publish reserve addresses and work with an auditor or Chainlink External Adapter. Expect SGX‑hardened policy execution but negotiate if you need raw quotes. (developers.fireblocks.com)
-
Cobo
- Leverage co‑managed MPC (2‑of‑3 default) with approver roles and Cobo Guard for secure auth. For PoR, export addresses via API and feed them into an oracle. (docs.cobo.com)
-
Qredo
- Strong decentralized MPC and on‑chain governance for approvals. For reserve transparency of externally issued tokens, pair Qredo with Chainlink PoR and a liabilities Merkle audit. (qredo.com)
What to ask vendors before you commit
- MPC specifics: threshold (e.g., 2‑of‑3, 3‑of‑5), who holds which shares, and where the TEEs/HSMs are hosted. BitGo and Cobo provide clear TSS/key‑share models in docs. (developers.bitgo.com)
- Policy coverage: which changes require admin quorum, mobile approvals, API‑only approvals, expirations, and who can veto. Fireblocks documents these controls explicitly. (developers.fireblocks.com)
- PoR posture: do they already have a live PoR feed? If not, who supplies data to Chainlink (self‑attestation vs. auditor), at what heartbeat/deviation threshold, and how will liabilities be proven? Review feed pages and disclaimers; require a runbook for incident handling. (chain.link)
- TEE attestation: if they claim enclave protection, can they furnish DCAP/IAS artifacts or at least auditor attestations that map enclave measurements to builds? (intel.com)
The 30‑day rollout plan we recommend
- Week 1: Pick custodian and PoR path. If you need “MPC + PoR now,” start with BitGo for WBTC‑like products; otherwise, choose Fireblocks/Cobo/Qredo for MPC and plan a Chainlink PoR integration. (businesswire.com)
- Week 2: Implement dual‑control policies and admin quorums; turn on address whitelists and size‑based approvals. (developers.fireblocks.com)
- Week 3: Stand up PoR—either by consuming an existing feed (e.g., cbBTC) or by publishing your reserves to an auditor or feed and writing a simple mint gate contract (code above). (data.chain.link)
- Week 4: Add liabilities Merkle proofs to user portals; run failover drills for reporter outages and under‑collateralization circuit breakers. (chain.link)
Key links and references (for your RFP and engineers)
- BitGo MPC/TSS, policies, and PoR developer docs. (developers.bitgo.com)
- Fireblocks approval quorums, policy engine, and SGX‑backed architecture. (developers.fireblocks.com)
- Cobo co‑managed MPC roles and key‑share model. (docs.cobo.com)
- Chainlink PoR overview and developer guidance. (chain.link)
- Live PoR examples: WBTC.e (Avalanche), cbBTC (Base), FBTC feed (Ethereum). Always review “Reporter” and “Data Source.” (data.chain.link)
- PoR caveats in the press—use them to strengthen your governance docs. (coindesk.com)
- Intel SGX attestation (DCAP) for enclave quote verification. (intel.com)
Final take
- If you need dual‑control MPC with proven, public on‑chain audits today, BitGo is the clearest “both boxes checked” choice. (businesswire.com)
- If you prefer Fireblocks/Cobo/Qredo for operations, treat PoR as a separable module: implement Chainlink PoR and a liabilities Merkle proof, then wire circuit breakers to those feeds. Your users—and your auditors—will thank you. (chain.link)
7Block Labs can help you blueprint the policy engine, stand up a PoR pipeline, and ship the Solidity guards and monitoring bots in under a month.
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

