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:
| Function | Description |
|---|---|
| Shortfall Coverage | Provides coverage for liquidation and settlement shortfalls |
| 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
┌─────────────────────────────────────────────────────────────────────────────┐
│ 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| Parameter | Type | Description |
|---|---|---|
amount | uint256 | Shortfall amount to cover (USDT) |
source | CoverageSource | Source of coverage request (for indexing) |
user | address | User whose shortfall is being covered (event indexing) |
recipient | address | Address that receives credited funds |
recipientPortfolioId | uint256 | Recipient portfolio to credit |
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, or settlement readiness)
amount > 0amount <= 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| Parameter | Type | Description |
|---|---|---|
amount | uint256 | Amount to withdraw (USDT) |
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
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 |
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 |
| DiffusalSettlementEngine | Batch settlement shortfall coverage |
| DiffusalSettlementReadinessLiquidator | Bounty shortfall coverage |
Security Considerations
Access Control
| Function | Access |
|---|---|
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
Related
- Liquidation (Protocol) — High-level liquidation mechanics
- DiffusalLiquidationEngine — Shortfall triggering
- Protocol Design — Fee system overview