# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://csm-docs.cozy.finance/developer-guides/euler-vault-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
