# Euler Vault Integration

This guide explains how to integrate Cozy Safety Module into a Euler Vault as a bad debt backstop. Use it as a reference when deploying, wiring, or operating the integration. Euler vaults can atomically repay bad debt post-liquidation using eTokens tapped from a Safety Module. This provides an alternative mechanism to managing bad debt with [bad debt socialization](https://docs.euler.finance/developers/evk/?_highlight=bad&_highlight=debt#bad-debt-socialization) (the default option).

```solidity
contract EulerTrancheRaiseStrategy is IRaiseStrategy {
  /// @notice Converts asset needs to safety module specific raises using a tranching strategy which prioritizes
  /// raising the fee share reserve pool prior to the lender share reserve pool.
  /// @param originSafetyModule_ The safety module that triggered the raise
  /// @param assetNeeds_ The asset needs to be converted to raises
  /// @param data_ Encoded reserve pool ids: abi.encode(uint8 feeShareReservePoolId, uint8 lenderShareReservePoolId)
  function calculateRaise(ISafetyModule originSafetyModule_, AssetNeed[] memory assetNeeds_, bytes calldata data_)
    external
    returns (SafetyModuleRaise[] memory);
}
```

```solidity
contract CozyLiquidatorManager is Ownable, ICozyLiquidatorManager {
  /// @notice Deploys a new CozyLiquidator with the provided parameters.
  /// @param safetyModule_ The associated SafetyModule.
  /// @param eVault_ The associated Euler vault.
  /// @param raiseStrategy_ The associated raise strategy.
  /// @param feeShareReservePoolId_ The reserve pool ID to use for the fee share.
  /// @param lenderShareReservePoolId_ The reserve pool ID to use for the lender share.
  /// @param salt_ Used to compute the resulting address of the CozyLiquidator along with `msg.sender`.
  /// @return cozyLiquidator_ The newly created CozyLiquidator.
  function createCozyLiquidator(
    ISafetyModule safetyModule_,
    IEVault eVault_,
    EulerTrancheRaiseStrategy raiseStrategy_,
    uint8 feeShareReservePoolId_,
    uint8 lenderShareReservePoolId_,
    bytes32 salt_
  ) external returns (ICozyLiquidator cozyLiquidator_)
}
```

```solidity
contract FeeReceiver is Ownable {
  /**
   * @notice Constructor that sets all parameters for the fee receiver
   * @param asset_ Euler vault token that this fee receiver manages
   * @param safetyModule_ The SafetyModule to which fees are redirected
   * @param safetyModuleReservePoolId_ The reserve pool ID in the safety module for fee shares
   * @param safetyModuleShare_ Percentage of fees that should be redirected to the safety module represented as a ZOC
   * (e.g. 5000 = 50%)
   * @param owner_ Address of the owner who can claim any undirected fees
   */
  constructor(
    IERC20 asset_,
    ISafetyModule safetyModule_,
    uint8 safetyModuleReservePoolId_,
    uint256 safetyModuleShare_,
    address owner_
  )
}
```

## Components

* `CozyLiquidatorManager.createCozyLiquidator` deploys minimal proxy liquidators that are parameterized for a specific safety module + vault.
* `CozyLiquidator` is the controller that Euler vaults call into.
* `CozyLiquidationHandler.handleCozyLiquidation` is delegate called by the liquidator to execute the liquidation, and trigger + raise the Safety Module.
* `EulerTrancheRaiseStrategy` is a raise strategy which specifies that eTokens deposited by the vault governor (via the FeeReceiver) get tapped prior to eTokens deposited by lenders.
* `FeeReceiver` redirects a configurable portion of vault fees into the safety module’s fee share reserve pool.

## Deployment & Configuration

{% stepper %}
{% step %}

### Configure the safety module

* Define reserve pools for the Euler vault eToken. Pool `0` for fee shares and pool `1` for lender shares (both backed by the same eToken).
* Include `ControllerConfig({controller: ISafetyModuleController(cozyLiquidatorAddress), exists: true})` inside the `ConfigUpdateCalldataParams` supplied to a queued config update. This registers the liquidator as a controller via `CozySafetyModuleManager.registerSafetyModuleController`.
  {% endstep %}

{% step %}

### Deploy the liquidator for the target vault

Call `CozyLiquidatorManager.createCozyLiquidator` with:

* The configured safety module.
* The Euler vault address (eToken).
* The `EulerTrancheRaiseStrategy` instance.
* Fee-share and lender-share reserve pool IDs.
* A deploy salt (for deterministic addresses if desired).
  {% endstep %}

{% step %}

### Wire the Euler vault

* Vault governance must set the liquidator as the `liquidate` hook target (`IEVault.setHookConfig`) and flip `CFG_DONT_SOCIALIZE_DEBT` so Euler does not spread bad debt across depositors.
* `eVault.feeReceiver()` should be set to the `FeeReceiver` contract so `FeeReceiver` receives a portion of the governor's fees.
  {% endstep %}

{% step %}

### (Optional) Divert vault fees to the safety module

* Deploy a `FeeReceiver` pointing at the eToken, safety module, and fee reserve pool ID. Set it as the vault’s fee receiver and choose a `safetyModuleShare` (ZOC).
* Anyone can call `redirectFees()` to push accumulated eTokens into the fee reserve pool.
  {% endstep %}
  {% endstepper %}

## Liquidation & Raise Lifecycle

{% stepper %}
{% step %}

### Trigger liquidation through the liquidator

`CozyLiquidator.liquidate(violator, collateral, repayAssets, minYield)` is called instead of `eVault.liquidate`.

Note: You must use the CozyLiquidator as the entrypoint, otherwise CozyLiquidator will revert with `LiquidationNotRoutedThroughCozyLiquidator()`
{% endstep %}

{% step %}

### Liquidator delegates to handler

`CozyLiquidator` locks re-entrancy (only the vault can re-enter) and delegate-calls `CozyLiquidationHandler.handleCozyLiquidation`.
{% endstep %}

{% step %}

### Handler executes Euler liquidation

The handler executes the real Euler liquidation via the `EVC`, emitting `LiquidationExecuted`. Since CozyLiquidator is set as the pre-hook on the vault, the eVault immediately calls back into `CozyLiquidator.liquidate()`, which returns a no-op and continues on to `eVault.liquidate()`
{% endstep %}

{% step %}

### If residual debt remains, trigger the safety module

* If collateral is insufficient and residual debt remains:
  * A deterministic `triggerEventId` is computed from the violator, remaining debt, timestamp, and `triggerEventIdNonce`.
  * The handler calls `SafetyModule.trigger(triggerEventId, validityDuration)` which moves the module into `TRIGGERED` state and increments `numPendingRaises`.
  * An `AssetNeed` for the Euler eToken shares is created by converting debt assets into eVault share amount.
  * `SafetyModule.requestRaise` is invoked with the `EulerTrancheRaiseStrategy` and pool IDs encoded in `data`.
    {% endstep %}

{% step %}

### Safety module processes the raise

* Uses the raise strategy to split the need into concrete raise instructions.
* Transfers the tapped eTokens to the liquidator, and decrements `numPendingRaises`
  {% endstep %}

{% step %}

### Handler repays the vault

Back in the handler, any eTokens received are sent to `EVault.repayWithShares`, cancelling the bad debt. `BadDebtRepaid` captures the repayment amount.
{% endstep %}

{% step %}

### Liquidator stores snapshot and increments nonce

Control returns to `CozyLiquidator`, which stores and emits a `TriggerEventStateSnapshot` (violator, bad debt amount, amount repaid, timestamp) and increments `triggerEventIdNonce`.
{% endstep %}
{% endstepper %}

## Observability

```solidity
/// SafetyModule

/// @dev Emitted when the SafetyModule is triggered.
event Triggered(ISafetyModuleController indexed controller_, bytes32 indexed triggerEventId_, uint256 expiresAt_);

event ReservePoolTapped(
    ISafetyModuleController indexed safetyModuleController_,
    bytes32 triggerEventId_,
    address indexed receiver_,
    uint8 indexed reservePoolId_,
    uint256 assetAmount_
);

/// @dev Emitted when a safety module is tapped.
event SafetyModuleTapped(
    ISafetyModuleController indexed safetyModuleController_, bytes32 indexed triggerEventId_, address indexed receiver_
);

/// @dev Emitted when the SafetyModule is requested to raise.
event RaiseRequested(
    ISafetyModuleController indexed controller_,
    bytes32 indexed triggerEventId_,
    address indexed receiver_,
    AssetNeed[] assetNeeds_,
    IRaiseStrategy raiseStrategy_,
    bytes data_
);
```

```solidity
/// CozyLiquidator 

/// @notice Emitted on trigger event state snapshot.
event TriggerEventStateSnapshot(bytes32 indexed triggerEventId_, bytes triggerEventStateSnapshot_);
```

<pre class="language-solidity"><code class="lang-solidity"><strong>/// CozyLiquidationHandler 
</strong><strong>
</strong>/// @notice Emitted when a liquidation is executed.
event LiquidationExecuted(
  address liquidator_, address violator_, address collateral_, uint256 repayAssets_, uint256 minYieldBalance_
);

/// @notice Emitted when bad debt is repaid.
event BadDebtRepaid(bytes32 indexed triggerEventId_, uint256 badDebtAmount_, uint256 badDebtRepaid_);
</code></pre>
