IERC20(asset).balanceOf(this) ≥ totalCollateral() + accruedFees()The vault's real on-chain USDC balance is always at least the sum of every user's recorded collateral plus accrued fees. The accounting can never claim more than the contract holds.
Most products that call themselves “decentralized” refuse to publish a threat model because it forces them to be explicit about what the operator can still do. We are explicit. Below: the three invariants the contracts enforce by construction, the roles in scope, and the exact blast radius of compromise per role.
IERC20(asset).balanceOf(this) ≥ totalCollateral() + accruedFees()The vault's real on-chain USDC balance is always at least the sum of every user's recorded collateral plus accrued fees. The accounting can never claim more than the contract holds.
Only withdraw / liquidate / emergencyExit can decrease the vault balanceThree paths can move USDC out. withdraw is callable by the account owner, gated on free margin. liquidate is public, requires the account is flagged + insolvent. emergencyExit is callable by the account owner after the operator silence window. There is no other path.
MARGIN_MANAGER_ROLE cannot transfer to itself, everThe matching engine's on-chain role can read every user's collateral, apply realized P&L between accounts, lock/unlock margin, move user collateral into the protocol fee pool atomically, and flag accounts liquidatable. It cannot transfer to itself.
Full role-management capability. Can grant/revoke any other role.
3-of-5 multisig with hardware-keyed signers, geographically distributed. Timelock contract on every governance action (Phase 6b).
AccessControl, Pausable, ReentrancyGuard, SafeERC20, MerkleProof.
Industry-standard library, audited many times over. Pinned via foundry.toml; upgrades reviewed before bump.
Apply arbitrary P&L between accounts, flag accounts liquidatable, collect fees.
Compromise = wrong P&L applied; tokens stay in the vault (I2 + I3). Recovery: admin Safe revokes, deploys new manager EOA. Damage limited.
Publish bogus Merkle roots.
Off-chain commitment archives + post-mortem reconciliation against the signed-receipt log catch this; new publisher key issued.
Anyone reads on-chain events.
No information privileged from on-chain events. Liquidation is public; griefing-resistance is in the math.
Mechanically enforced by the contracts. Not policy, not promise — code. Each item below is testable in the open-source repo and verifiable on Arbiscan.
If the matching engine ever goes silent for the silence window (default 48h), any account owner can call emergencyExit(to) directly on the vault. Pause must never trap funds — test_emergencyExit_worksWhenPaused enforces this.
function emergencyExit(address to) external {
require(silentFor(msg.sender) >= silenceSeconds);
uint256 takeHome = clampToZero(
equity(msg.sender) - marginUsed(msg.sender)
);
takeHome = min(takeHome, collateralOf(msg.sender));
asset.safeTransfer(to, takeHome);
}These warrant their own operational review but are not audit findings on the contracts.
In-scope contracts, focus areas, prioritized findings-handling protocol — the full document we hand to auditors before they start.