Diffusal

DiffusalInsuranceFund

Liquidation and settlement shortfall coverage

The DiffusalInsuranceFund contract provides a safety net for liquidation and settlement shortfalls. When a liquidation's proceeds don't cover the user's debt, or when shorts can't pay during batch settlement, the insurance fund steps in to cover the gap, preventing protocol insolvency.


Overview

The insurance fund serves four purposes:

FunctionDescription
Shortfall CoverageProvides coverage for liquidation and settlement shortfalls
Liquidation ShortfallCovers debt when liquidation proceeds are insufficient
Settlement ShortfallCovers batch settlement shortfalls when shorts can't pay
Settlement ReadinessCovers bounty payments for settlement readiness liquidations

Fund Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│                              FUNDING SOURCES                                 │
│                                                                              │
│   ┌───────────────────────┐    ┌───────────────────────┐                    │
│   │  Owner / Treasury     │    │  External Funding     │                    │
│   │      Deposits         │    │     Transfers         │                    │
│   └───────────┬───────────┘    └───────────┬───────────┘                    │
│               │                            │                                 │
│               └────────────┬───────────────┘                                 │
│                            ▼                                                 │
│               ┌───────────────────────┐                                      │
│               │    Insurance Fund     │                                      │
│               └───────────┬───────────┘                                      │
│                           ▼                                                  │
│               ┌───────────────────────┐                                      │
│               │   Vault (deposit)     │                                      │
│               └───────────────────────┘                                      │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                           SHORTFALL COVERAGE                                 │
│                                                                              │
│  ┌─────────────────┐  ┌─────────────────┐  ┌────────────────────────────┐   │
│  │   Liquidation   │  │   Settlement    │  │   Settlement Readiness     │   │
│  │     Engine      │  │     Engine      │  │        Liquidator          │   │
│  └────────┬────────┘  └────────┬────────┘  └─────────────┬──────────────┘   │
│           │                    │                         │                   │
│           ▼                    ▼                         ▼                   │
│    ┌──────────────┐     ┌──────────────┐          ┌──────────────┐          │
│    │  Shortfall?  │     │  Shortfall?  │          │   Bounty?    │          │
│    └──────┬───────┘     └──────┬───────┘          └──────┬───────┘          │
│           │                    │                         │                   │
│           └────────────────────┴─────────────────────────┘                   │
│                                │                                             │
│                                ▼                                             │
│               ┌────────────────────────────────┐                             │
│               │   InsuranceFund.cover()        │                             │
│               └───────────────┬────────────────┘                             │
│                               ▼                                              │
│               ┌─────────────────────────────────────────────┐                 │
│               │ Vault.debitPortfolioCollateral() +         │                 │
│               │ Vault.creditPortfolioCollateral()           │                 │
│               └───────────────┬─────────────────────────────┘                 │
│                               ▼                                              │
│               ┌────────────────────────────────┐                             │
│               │       Cover shortfall          │                             │
│               └────────────────────────────────┘                             │
└─────────────────────────────────────────────────────────────────────────────┘

Key Concepts

Balance Storage

The insurance fund doesn't hold USDT directly. Instead, it maintains a deposit in the CollateralVault:

function getBalance() external view returns (uint256 balance) {
    return vault.getPortfolioDeposit(address(this), 0);
}

This design:

  • Leverages existing vault infrastructure
  • Simplifies fund accounting
  • Enables seamless transfers during liquidation

Fee Routing

Trading fees are routed to a configurable feeCollector address on both trading contracts. In the current deployment model, the feeCollector is a dedicated protocol wallet (EOA) — separate from the insurance fund. The insurance fund exists solely for liquidation and settlement shortfall coverage.

// feeCollector is a dedicated protocol EOA, not the insurance fund address
orderBook.setFeeCollector(dedicatedFeeCollectorAddress);
rfq.setFeeCollector(dedicatedFeeCollectorAddress);

Shortfall Coverage

When a liquidation, batch settlement, or settlement readiness liquidation has insufficient funds:

// Liquidation shortfall coverage (simplified)
if (shortfall <= insuranceBalance) {
    insuranceFund.cover(shortfall, CoverageSource.LIQUIDATION, user, user, portfolioId);  // Full coverage
} else if (insuranceBalance > 0) {
    insuranceFund.cover(insuranceBalance, CoverageSource.LIQUIDATION, user, user, portfolioId);  // Partial
}

// In SettlementEngine.settlePortfolioPositionBatch()
// If short collection < long payout, cover each user's shortfall individually:
for (uint256 i = 0; i < results.length; i++) {
    if (results[i].settled && shortfallAmounts[i] > 0) {
        insuranceFund.cover(shortfallAmounts[i], CoverageSource.SETTLEMENT, users[i], users[i], portfolioIds[i]);
    }
}

// In SettlementEngine._settlePortfolioPosition() (single position)
// If user can't pay full obligation:
if (actualDebit < obligation) {
    insuranceFund.cover(obligation - actualDebit, CoverageSource.SETTLEMENT, user, user, portfolioId);
}

// In SettlementReadinessLiquidator
// If user lacks collateral for bounty:
if (bountyShortfall > 0) {
    insuranceFund.cover(bountyShortfall, CoverageSource.SETTLEMENT_READINESS, user, liquidator, liquidatorPortfolioId);
}

Storage & State

The contract uses ERC-7201 namespaced storage for upgradeability:

/// @custom:storage-location erc7201:diffusal.storage.InsuranceFund
struct InsuranceFundStorage {
    address owner;
    address pendingOwner;
    address collateralVault;
    address liquidationEngine;
    address settlementEngine;
    address settlementReadinessLiquidator;
}

The contract stores funds in the vault via its deposit.


View Functions

getBalance

Returns the current insurance fund balance.

function getBalance() external view returns (uint256 balance)

Returns: USDT balance (6 decimals) from vault deposit.


owner

Returns the contract owner.

function owner() external view returns (address)

pendingOwner

Returns the pending owner address (for two-step ownership transfer).

function pendingOwner() external view returns (address)

collateralVault

Returns the collateral vault address.

function collateralVault() external view returns (address)

liquidationEngine

Returns the authorized liquidation engine address.

function liquidationEngine() external view returns (address)

settlementEngine

Returns the authorized settlement engine address.

function settlementEngine() external view returns (address)

settlementReadinessLiquidator

Returns the authorized settlement readiness liquidator address.

function settlementReadinessLiquidator() external view returns (address)

Authorized Engine Functions

cover

Covers a liquidation or settlement shortfall by transferring funds.

function cover(
    uint256 amount,
    CoverageSource source,
    address user,
    address recipient,
    uint256 recipientPortfolioId
) external nonReentrant onlyAuthorizedEngine
ParameterTypeDescription
amountuint256Shortfall amount to cover (USDT)
sourceCoverageSourceSource of coverage request (for indexing)
useraddressUser whose shortfall is being covered (event indexing)
recipientaddressAddress that receives credited funds
recipientPortfolioIduint256Recipient portfolio to credit

CoverageSource Values:

ValueDescription
LIQUIDATIONTraditional liquidation shortfall
SETTLEMENTSettlement shortfall (single or batch)
SETTLEMENT_READINESSSettlement readiness liquidation bounty

Requirements:

  • Caller must be an authorized engine (liquidation, settlement, or settlement readiness)
  • amount > 0
  • amount <= getBalance()

Effect: Debits insurance fund portfolio and credits recipient portfolio.

Emits: ShortfallCovered(engine, user, source, amount)


Owner Functions

withdraw

Withdraws excess funds from the insurance fund.

function withdraw(uint256 amount) external nonReentrant onlyOwner
ParameterTypeDescription
amountuint256Amount to withdraw (USDT)

Requirements:

  • amount > 0
  • amount <= getBalance()

Effect: Transfers amount to owner's vault deposit.

Use case: Withdraw excess funds when balance grows beyond needed safety cushion.

Emits: Withdrawal


setLiquidationEngine

Sets the authorized liquidation engine.

function setLiquidationEngine(address engine_) external onlyOwner

Emits: LiquidationEngineUpdated


setSettlementEngine

Sets the authorized settlement engine.

function setSettlementEngine(address engine_) external onlyOwner

Emits: SettlementEngineUpdated


setSettlementReadinessLiquidator

Sets the authorized settlement readiness liquidator.

function setSettlementReadinessLiquidator(address liquidator_) external onlyOwner

Emits: SettlementReadinessLiquidatorUpdated


setCollateralVault

Updates the collateral vault reference.

function setCollateralVault(address vault_) external onlyOwner

Emits: CollateralVaultUpdated


transferOwnership

Initiates a two-step ownership transfer.

function transferOwnership(address newOwner) external onlyOwner
ParameterTypeDescription
newOwneraddressThe address to transfer ownership to. Set to address(0) to cancel a pending transfer.

Emits: OwnershipTransferStarted

Note: The new owner must call acceptOwnership() to complete the transfer.


acceptOwnership

Completes the two-step ownership transfer (called by the pending owner).

function acceptOwnership() external

Requirements: Caller must be the pending owner set by transferOwnership().

Emits: OwnershipTransferred


Events

EventParametersDescription
ShortfallCoveredengine, user, source, amountShortfall covered with source and user for indexing
Withdrawalto, amountOwner withdrew funds
LiquidationEngineUpdatedoldEngine, newEngineLiquidation engine changed
SettlementEngineUpdatedoldEngine, newEngineSettlement engine changed
SettlementReadinessLiquidatorUpdatedoldLiquidator, newLiquidatorSettlement readiness liquidator changed
CollateralVaultUpdatedoldVault, newVaultVault reference changed
OwnershipTransferStartedpreviousOwner, newOwnerTwo-step ownership transfer initiated
OwnershipTransferredpreviousOwner, newOwnerOwnership changed

Integration Points

Depends On

ContractPurpose
DiffusalCollateralVaultStores insurance fund balance

Used By

ContractPurpose
DiffusalLiquidationEngineLiquidation shortfall coverage
DiffusalSettlementEngineBatch settlement shortfall coverage
DiffusalSettlementReadinessLiquidatorBounty shortfall coverage

Security Considerations

Access Control

FunctionAccess
cover()Liquidation engine, settlement engine, OR settlement readiness liquidator
withdraw()Admin only
set*()Owner only
getBalance()Public

Reentrancy Protection

Both cover() and withdraw() use nonReentrant modifier.

Fund Adequacy

The insurance fund should maintain sufficient balance to cover potential shortfalls. Monitoring should track:

  • Fund balance vs total protocol exposure
  • Historical shortfall frequency
  • Average shortfall size

No Margin Requirements

The insurance fund has no positions and thus no margin requirements. Its "deposit" in the vault is a pure balance.


Example: Shortfall Coverage

Scenario

A user with 3 positions gets liquidated:

  • Debt: $10,000 (IM - equity)
  • Liquidation proceeds: $8,000
  • Shortfall: $2,000

Process

// In liquidation flow (simplified)
if (totalProceeds < debt) {
    uint256 shortfall = debt - totalProceeds;  // $2,000
    insuranceUsed = shortfall;
}

// Coverage call
function _coverShortfall(uint256 shortfall, address user, uint256 portfolioId)
    internal
    returns (uint256 insuranceUsed)
{
    uint256 balance = insuranceFund.getBalance();  // e.g., $50,000

    if (shortfall <= balance) {
        // Cover full $2,000 with LIQUIDATION source
        insuranceFund.cover(shortfall, CoverageSource.LIQUIDATION, user, user, portfolioId);
        insuranceUsed = shortfall;
    }
}

Result

  • User's positions closed
  • $8,000 collected from positions
  • $2,000 drawn from insurance fund
  • Total coverage: $10,000 (matches debt)
  • Insurance fund balance: $48,000

Code Reference

Source: packages/contracts/src/DiffusalInsuranceFund.sol

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


On this page