DiffusalInsuranceFund
Fee collection and liquidation shortfall coverage
The DiffusalInsuranceFund contract collects protocol trading fees and 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:
| Function | Description |
|---|---|
| Fee Collection | Receives trading fees as feeRecipient for OrderBook and RFQ |
| Liquidation Shortfall | Covers debt when liquidation proceeds are insufficient |
| Settlement Shortfall | Covers batch settlement shortfalls when shorts can't pay |
| Settlement Readiness | Covers bounty payments for settlement readiness liquidations |
Fund Flow
┌─────────────────────────────────────────────────────────────────────────────┐
│ FEE COLLECTION │
│ │
│ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ OrderBook │ │ RFQ │ │
│ │ (maker + taker fees) │ │ (RFQ fees) │ │
│ └───────────┬───────────┘ └───────────┬───────────┘ │
│ │ │ │
│ └────────────┬───────────────┘ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Insurance Fund │ │
│ └───────────┬───────────┘ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Vault (deposit) │ │
│ └───────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ SHORTFALL COVERAGE │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌────────────────────────────┐ │
│ │ Liquidation │ │ Settlement │ │ Settlement Readiness │ │
│ │ Engine │ │ Engine │ │ Liquidator │ │
│ └────────┬────────┘ └────────┬────────┘ └─────────────┬──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Shortfall? │ │ Shortfall? │ │ Bounty? │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └────────────────────┴─────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────┐ │
│ │ InsuranceFund.cover() │ │
│ └───────────────┬────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────┐ │
│ │ Vault.transferCollateral() │ │
│ └───────────────┬────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────┐ │
│ │ Cover shortfall │ │
│ └────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘Key Concepts
Balance Storage
The insurance fund doesn't hold USDC directly. Instead, it maintains a deposit in the CollateralVault:
function getBalance() external view returns (uint256 balance) {
return vault.getDeposit(address(this));
}This design:
- Leverages existing vault infrastructure
- Simplifies fund accounting
- Enables seamless transfers during liquidation
Fee Recipient Role
The insurance fund should be set as feeRecipient on both trading contracts:
// On OrderBook
orderBook.setFeeRecipient(address(insuranceFund));
// On RFQ
rfq.setFeeRecipient(address(insuranceFund));When fees are collected, they're transferred to the insurance fund's vault deposit.
Shortfall Coverage
When a liquidation, batch settlement, or settlement readiness liquidation has insufficient funds:
// In LiquidationEngine._coverShortfall()
if (shortfall <= insuranceBalance) {
insuranceFund.cover(shortfall, CoverageSource.LIQUIDATION, user); // Full coverage
} else if (insuranceBalance > 0) {
insuranceFund.cover(insuranceBalance, CoverageSource.LIQUIDATION, user); // 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]);
}
}
// In SettlementEngine._settlePortfolioPosition() (single position)
// If user can't pay full obligation:
if (actualDebit < obligation) {
insuranceFund.cover(obligation - actualDebit, CoverageSource.SETTLEMENT, user);
}
// In SettlementReadinessLiquidator
// If user lacks collateral for bounty:
if (bountyShortfall > 0) {
insuranceFund.cover(bountyShortfall, CoverageSource.SETTLEMENT_READINESS, user);
}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;
address liquidationSettlement; // NEW: Extracted from LiquidationEngine
}The contract stores funds in the vault via its deposit.
Note: The liquidationSettlement field was added when settlement logic was extracted from DiffusalLiquidationEngine to DiffusalLiquidationSettlement.
View Functions
getBalance
Returns the current insurance fund balance.
function getBalance() external view returns (uint256 balance)Returns: USDC 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)liquidationSettlement
Returns the authorized liquidation settlement contract address.
function liquidationSettlement() 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) external nonReentrant onlyAuthorizedEngine| Parameter | Type | Description |
|---|---|---|
amount | uint256 | Shortfall amount to cover (USDC) |
source | CoverageSource | Source of coverage request (for indexing) |
user | address | User whose shortfall is being covered (must be non-zero, reverts on address(0)) |
CoverageSource Values:
| Value | Description |
|---|---|
LIQUIDATION | Traditional liquidation shortfall |
SETTLEMENT | Settlement shortfall (single or batch) |
SETTLEMENT_READINESS | Settlement readiness liquidation bounty |
Requirements:
- Caller must be an authorized engine (liquidation, settlement, settlement readiness, or liquidation settlement)
user != address(0)(reverts withZeroAddress)amount > 0amount <= getBalance()
Effect: Transfers amount from insurance fund's vault deposit to the calling engine.
Emits: ShortfallCovered(engine, user, source, amount)
Owner Functions
withdraw
Withdraws excess funds from the insurance fund.
function withdraw(uint256 amount) external nonReentrant onlyOwner| Parameter | Type | Description |
|---|---|---|
amount | uint256 | Amount to withdraw (USDC) |
Requirements:
amount > 0amount <= 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 onlyOwnerEmits: LiquidationEngineUpdated
setSettlementEngine
Sets the authorized settlement engine.
function setSettlementEngine(address engine_) external onlyOwnerEmits: SettlementEngineUpdated
setSettlementReadinessLiquidator
Sets the authorized settlement readiness liquidator.
function setSettlementReadinessLiquidator(address liquidator_) external onlyOwnerEmits: SettlementReadinessLiquidatorUpdated
setLiquidationSettlement
Sets the authorized liquidation settlement contract.
function setLiquidationSettlement(address settlement_) external onlyOwnerEmits: LiquidationSettlementUpdated
setCollateralVault
Updates the collateral vault reference.
function setCollateralVault(address vault_) external onlyOwnerEmits: CollateralVaultUpdated
transferOwnership
Initiates a two-step ownership transfer.
function transferOwnership(address newOwner) external onlyOwner| Parameter | Type | Description |
|---|---|---|
newOwner | address | The 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() externalRequirements: Caller must be the pending owner set by transferOwnership().
Emits: OwnershipTransferred
Events
| Event | Parameters | Description |
|---|---|---|
ShortfallCovered | engine, user, source, amount | Shortfall covered with source and user for indexing |
Withdrawal | to, amount | Owner withdrew funds |
LiquidationEngineUpdated | oldEngine, newEngine | Liquidation engine changed |
SettlementEngineUpdated | oldEngine, newEngine | Settlement engine changed |
SettlementReadinessLiquidatorUpdated | oldLiquidator, newLiquidator | Settlement readiness liquidator changed |
LiquidationSettlementUpdated | oldSettlement, newSettlement | Liquidation settlement contract changed |
CollateralVaultUpdated | oldVault, newVault | Vault reference changed |
OwnershipTransferStarted | previousOwner, newOwner | Two-step ownership transfer initiated |
OwnershipTransferred | previousOwner, newOwner | Ownership changed |
Integration Points
Depends On
| Contract | Purpose |
|---|---|
| DiffusalCollateralVault | Stores insurance fund balance |
Used By
| Contract | Purpose |
|---|---|
| DiffusalLiquidationEngine | Liquidation shortfall coverage |
| DiffusalLiquidationSettlement | Bounty and shortfall coverage |
| DiffusalSettlementEngine | Batch settlement shortfall coverage |
| DiffusalSettlementReadinessLiquidator | Bounty shortfall coverage |
| DiffusalOptionsOrderBook | Fee recipient |
| DiffusalOptionsRFQ | Fee recipient |
Security Considerations
Access Control
| Function | Access |
|---|---|
cover() | Liquidation engine, liquidation settlement, settlement engine, OR settlement readiness liquidator |
withdraw() | Owner 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 LiquidationEngine._settleCollateral()
if (totalProceeds < debt) {
uint256 shortfall = debt - totalProceeds; // $2,000
insuranceUsed = _coverShortfall(shortfall);
}
// In _coverShortfall()
function _coverShortfall(uint256 shortfall, address user) 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);
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
Related
- Liquidation (Protocol) — High-level liquidation mechanics
- DiffusalLiquidationEngine — Shortfall triggering
- Protocol Design — Fee system overview