Diffusal
Contracts

DiffusalCollateralVault

Central collateral management with portfolio margin enforcement

The DiffusalCollateralVault contract is the central custodian for user collateral in the Diffusal protocol. It holds USDC deposits, calculates portfolio margin requirements, and enforces health checks on withdrawals and trades. This is a high-risk contract as it directly holds user funds.


Overview

The vault provides three core functions:

FunctionDescription
CustodyHolds USDC collateral for all users
Margin CalculationComputes equity, unrealized PnL, IM, and MM
Health EnforcementEnforces margin requirements on withdrawals and trades

Margin Hierarchy

                   ┌────────────────────────┐
                   │       Deposit          │  Raw USDC in vault
                   └────────────────────────┘
                              +
                   ┌────────────────────────┐
                   │   Unrealized PnL       │  Sum of position PnL
                   └────────────────────────┘
                              =
                   ┌────────────────────────┐
                   │        Equity          │  Total account value
                   └────────────────────────┘

                   ┌────────────────────────┐
           MUST    │  Initial Margin (IM)   │  Required for trading
                   └────────────────────────┘
                              >
                   ┌────────────────────────┐
         MUST      │ Maintenance Margin (MM)│  Required to avoid liquidation
(or liquidatable)  └────────────────────────┘

Key Concepts

Equity Calculation

Equity=Deposit+Unrealized PnL\text{Equity} = \text{Deposit} + \text{Unrealized PnL}

Unrealized PnL is the sum of mark-to-market gains/losses across all positions.

Initial Margin (IM)

Initial margin is calculated using SPAN-like stress testing via the MarginEngine. See Margin Calculations for the complete formula.

Maintenance Margin (MM)

MM is 80% of IM. See Margin System for margin mechanics.

Health Check

A user is healthy if:

EquityMaintenance Margin\text{Equity} \geq \text{Maintenance Margin}

A user is liquidatable if:

Equity<Maintenance Margin AND not MMM\text{Equity} < \text{Maintenance Margin} \text{ AND not MMM}

Storage & State

The contract uses ERC-7201 namespaced storage for upgradeability:

/// @custom:storage-location erc7201:diffusal.storage.CollateralVault
struct CollateralVaultStorage {
    address owner;
    bool paused;
    address positionManager;
    address quoter;
    address oracle;
    mapping(address => bool) operators;
    mapping(address => uint256) deposits;  // User balances (USDC, 6 decimals)
}

// Immutable
IERC20 public immutable collateralToken;
address private immutable _SERIES_REGISTRY;

MarginInfo Struct

struct MarginInfo {
    uint256 deposit;            // Raw USDC deposit (6 decimals)
    int256 unrealizedPnL;       // Mark-to-market PnL (6 decimals)
    int256 equity;              // deposit + unrealizedPnL
    uint256 initialMargin;      // IM requirement (6 decimals)
    uint256 maintenanceMargin;  // MM = IM × 80%
    uint256 maxWithdraw;        // max(0, equity - IM)
    bool isHealthy;             // equity >= MM
}

User Functions

deposit

Deposits USDC collateral into the vault.

function deposit(uint256 amount) external nonReentrant whenNotPaused

Requirements:

  • amount > 0
  • User must have approved vault to spend USDC

Emits: Deposited


withdraw

Withdraws USDC collateral from the vault.

function withdraw(uint256 amount) external nonReentrant whenNotPaused

Requirements:

  • amount > 0
  • amount <= deposit
  • amount <= maxWithdraw (post-withdrawal equity must cover IM)

Emits: Withdrawn


View Functions

getDeposit

Returns the user's raw USDC deposit.

function getDeposit(address user) external view returns (uint256)

getEquity

Returns the user's total equity (deposit + unrealized PnL).

function getEquity(address user) external view returns (int256 equity)

Note: Can be negative if unrealized losses exceed deposit.


getUnrealizedPnL

Returns the user's mark-to-market PnL across all positions.

function getUnrealizedPnL(address user) public view returns (int256 pnl)

Uses MarginEngine.calculateUnrealizedPnL internally.


getInitialMargin

Returns the user's initial margin requirement.

function getInitialMargin(address user) public view returns (uint256 im)

Uses MarginEngine.calculateInitialMargin internally.


getMaintenanceMargin

Returns the user's maintenance margin (IM × 80%).

function getMaintenanceMargin(address user) public view returns (uint256 mm)

getMaxWithdraw

Returns the maximum amount a user can withdraw.

function getMaxWithdraw(address user) public view returns (uint256 maxWithdraw)
maxWithdraw=min(deposit,max(0,equityIM))\text{maxWithdraw} = \min(\text{deposit}, \max(0, \text{equity} - \text{IM}))

isHealthy

Checks if a user's margin is above maintenance level.

function isHealthy(address user) public view returns (bool healthy)

isLiquidatable

Checks if a user can be liquidated.

function isLiquidatable(address user) external view returns (bool liquidatable)

Returns true if:

  • User is not healthy (equity < MM), AND
  • User is not a Main Market Maker

getMarginInfo

Returns comprehensive margin information.

function getMarginInfo(address user) external view returns (MarginInfo memory info)

Operator Functions

These functions can only be called by authorized operators (OrderBook, RFQ, Settlement, Liquidation).

transferCollateral

Transfers collateral between users (for premium payments).

function transferCollateral(address from, address to, uint256 amount) external onlyOperator

Requirements:

  • amount > 0
  • from and to not zero
  • from has sufficient deposit

Emits: CollateralTransferred


debitCollateral

Debits collateral from a user (for settlement/liquidation).

function debitCollateral(address user, uint256 amount) external onlyOperator returns (uint256 actualDebit)

Returns: The actual amount debited (may be less than requested if user has insufficient deposit).

Note: Caps at user's available deposit (won't revert if insufficient).

Emits: CollateralDebited


creditCollateral

Credits collateral to a user (for settlement).

function creditCollateral(address user, uint256 amount) external onlyOperator

Emits: CollateralCredited


Owner Functions

setOperator

Authorizes or deauthorizes an operator.

function setOperator(address operator, bool authorized) external onlyOwner

Emits: OperatorUpdated


setPositionManager / setQuoter / setOracle

Updates contract references.

function setPositionManager(address manager) external onlyOwner
function setQuoter(address _newQuoter) external onlyOwner
function setOracle(address _newOracle) external onlyOwner

pause / unpause

Emergency pause controls.

function pause() external onlyOwner
function unpause() external onlyOwner

When paused: deposits and withdrawals are disabled.

Emits: PausedStateChanged


transferOwnership

Transfers contract ownership.

function transferOwnership(address newOwner) external onlyOwner

Emits: OwnershipTransferred


Events

EventParametersDescription
Depositeduser, amountUSDC deposited
Withdrawnuser, amountUSDC withdrawn
CollateralTransferredfrom, to, amountPremium transfer
CollateralDebiteduser, amountSettlement/liquidation debit
CollateralCrediteduser, amountSettlement credit
OperatorUpdatedoperator, authorizedOperator status changed
PositionManagerUpdatedmanagerPosition manager changed
QuoterUpdatedquoterQuoter changed
OracleUpdatedoracleOracle changed
PausedStateChangedpausedPause state toggled
OwnershipTransferredpreviousOwner, newOwnerOwnership changed

Integration Points

Depends On

ContractPurpose
DiffusalOptionsPositionManagerPosition queries for PnL/margin
DiffusalOptionsSeriesRegistrySeries info for margin calculations
DiffusalOptionsQuoterMark prices for unrealized PnL
MarginEngineSPAN-like margin calculations
USDC (ERC20)Collateral token

Used By

ContractPurpose
DiffusalOptionsOrderBookPremium transfers, health checks
DiffusalOptionsRFQPremium transfers, health checks
DiffusalSettlementEngineCredit/debit on settlement
DiffusalLiquidationEngineLiquidation proceeds
DiffusalInsuranceFundStores insurance fund balance

Security Considerations

Reentrancy Protection

All user-facing functions use nonReentrant modifier to prevent callback attacks.

Withdrawal Margin Check

Users can only withdraw excess collateral:

uint256 maxWithdraw = getMaxWithdraw(msg.sender);
if (amount > maxWithdraw) revert Errors.WithdrawExceedsMaximum();

This ensures post-withdrawal equity still covers initial margin.

Post-Trade Health Checks

Trading contracts check health after every trade:

if (!vault.isHealthy(maker)) revert Errors.InsufficientMargin();
if (!vault.isHealthy(taker)) revert Errors.InsufficientMargin();

Operator Trust

Operators can transfer collateral between users. Only trusted contracts should be authorized:

  • DiffusalOptionsOrderBook
  • DiffusalOptionsRFQ
  • DiffusalSettlementEngine
  • DiffusalLiquidationEngine

Emergency Pause

Owner can pause the vault to prevent deposits/withdrawals during emergencies. Operator functions remain active to allow settlement and liquidation.


Code Reference

Source: packages/contracts/src/DiffusalCollateralVault.sol

Interface: packages/contracts/src/interfaces/IDiffusalCollateralVault.sol

Testnet: View on MonadVision

Key Constants

// From Constants.sol
uint256 constant WAD = 1e18;
uint256 constant WAD_TO_USDC = 1e12;  // WAD (18 dec) to USDC (6 dec)
uint256 constant MAINTENANCE_MARGIN_RATE = 0.8e18;  // 80%

On this page