# Introduction

**About the Cozy Safety Module**

The Cozy Safety Module (CSM) is the most reliable way for teams to protect the capital of their users from hacks and exploits.

For teams, visit the [developer guides](/developer-guides/creating-a-safety-module) to learn how to create and manage a safety module.&#x20;

For users, learn how protection works and how to earn rewards for supplying funds by visiting the [user FAQs](/user-guides/user-faqs).&#x20;


# User FAQs

## Cozy Safety Module FAQ

#### What is the Cozy Safety Module?

Teams can use a Cozy Safety Module to protect the on-chain assets of their users from hacks and exploits. It’s a pool of funds reserved to reimburse users in case of qualifying losses. To use an analogy, you can think of it as “FDIC-like,” meaning a user’s lost funds are backed by the team’s Cozy Safety Module (not the FDIC, of course, which only protects FDIC-member institutions). You can find more details on how this works below.&#x20;

### For Users Protected by a Safety Module

#### What kinds of losses are covered by my safety module?

The creator of the safety module defines what qualifies as a loss when they set up the safety module. You can see what constitutes a qualified loss by viewing the details of your safety module in the app.

#### How do I make a claim if I experience a qualifying loss?

The process for making a claim depends on the safety module creator's chosen method. Some may use an automated on-chain claims process, while others may use the DAO to distribute funds to users. You can verify the payout mechanism by visiting the safety module details page in the app.

#### What happens if the safety module funds are depleted due to a large-scale hack or exploit?

In the event that the funds are insufficient to cover all the losses, users will typically receive a payout pro-rata, based on the available funds and the total amount of losses. Some teams may choose to allocate funds in a discretionary manner. You can see how your safety module is configured in the details page in the app.

#### Are there any fees associated with using a protocol that has integrated the Cozy Safety Module?

No, there are currently no fees charged by the Cozy Safety Module protocol associated with using a protocol that has integrated the Cozy Safety Module.

### For Safety Module Creators

#### How do I set up a safety module?

Visit [cozy.finance/create](http://cozy.finance/create) and follow the creation flow. You’ll be able to configure and deploy your safety module right there.

#### How does the Cozy Safety Module determine what counts as a qualifying loss?

When integrating the Cozy Safety Module, you set the terms for what types of losses are covered.

#### What are the best practices for setting up payout triggers and handlers?

To minimize the risk of unintended payouts, ensure that the payout trigger is clearly defined and the payout handler is configured to manage funds correctly. Using the UI reduces the likelihood of mistakes. Reach out on discord if you want to see some examples of configurations.

#### How do I ensure there are enough funds in the pool to cover potential losses?

Set a payout cap or a maximum payout per user, then source capital for your safety module to ensure sufficient funds to pay out all users up to the payout cap. This can be done using balance sheet or treasury capital, protocol fees, or by incentivizing third-party deposits with rewards. If there are insufficient funds to pay out users up to the cap, funds may be distributed pro-rata or at your discretion. The available funds in the safety module are visible on-chain, providing transparency to users.

#### How do I determine the optimal size of the safety module fund?

Analyze your protocol's user data to determine the total value locked (TVL) and user balances. Calculate the payout cap needed to fully cover a majority of users, which is often achievable with a small fraction of the TVL. Reach out on discord if you want examples of how to do this analysis.

#### Can I adjust the reward emission rate after deploying the safety module?

Yes, you can adjust the reward emission rate and top up the reward pool at any time. However, changes to the safety module are subject to a time delay, ensuring users have sufficient notice to exit the protocol if they disagree with the changes.

### For Safety Module Suppliers

#### How do I withdraw my funds if I no longer want to supply to the safety module?

You can withdraw your funds directly in the app. Once you initiate your withdrawal, you’ll have to wait for the withdrawal delay to elapse before you can remove your assets from the safety module.

#### How are reward rates determined for depositing funds?

Reward rates are set by the safety module creator, who deposits a quantity of reward tokens and defines an emission rate. Your earnings will depend on these settings and the total quantity of assets supplied by all users earning rewards.

#### What are the risks involved in depositing funds into a safety module?

The primary risk is that in the event of a payout, your deposited funds may be used to cover user losses. To mitigate this risk, look for safety modules with clear payout triggers and a history of responsible fund management.

#### Can I track the performance of my deposits in the safety module?

Yes, the Cozy UI allows you to view your accumulated rewards and track the performance of your deposits, providing transparency and keeping you informed about your investment.


# Creating a Safety Module

Creating a Safety Module is a two-step process:

1. [Define Safety Module Configuration](/developer-guides/creating-a-safety-module/define-safety-module-configuration)
2. [Deploy a Safety Module](/developer-guides/creating-a-safety-module/deploy-a-safety-module)


# Define Safety Module Configuration

Configuration for a Safety Module consists of `ReservePoolConfig[]`, `ControllerConfig[]`, and `DelaysConfig`. These configs are passed to `CozySafetyModuleManager.createSafetyModule` to deploy a new Safety Module.

```solidity
/// @notice Parameters for configuration updates.
struct ConfigUpdateCalldataParams {
  // The new reserve pool configs.
  ReservePoolConfig[] reservePoolConfigs;
  // The new controller configs.
  ControllerConfig[] controllerConfigUpdates;
  // The new delays config.
  Delays delaysConfig;
}

/// @notice Deploys a new SafetyModule with the provided parameters.
/// @param owner_ The owner of the SafetyModule.
/// @param pauser_ The pauser of the SafetyModule.
/// @param configs_ The configuration for the SafetyModule.
/// @param salt_ Used to compute the resulting address of the SafetyModule.
function createSafetyModule(
    address owner_,
    address pauser_,
    ConfigUpdateCalldataParams calldata configs_,
    bytes32 salt_
) external returns (ISafetyModule safetyModule_);
```

## Reserve Pool Config

```solidity
struct ReservePoolConfig {
  // The underlying asset of the reserve pool.
  IERC20 asset;
}
```

Note: The order of the reserve pool configs in the `ReservePoolConfig[]` array passed to `CozySafetyModuleManager.createSafetyModule` are used to determine the resulting reserve pool IDs in the deployed Safety Module.

### Reserve Pool Assets

Each reserve pool must have an underlying asset. Assets used by the Safety Module must follow the [Token Integration Guidelines](/developer-guides/token-integration-guidelines) to avoid any unexpected behavior.&#x20;

## Controller Config

```solidity
struct ControllerConfig {
  // The controller that is being configured.
  ISafetyModuleController controller;
  // Whether the controller is used by the SafetyModule.
  bool exists;
}
```

Safety Modules maintain a list of authorized controllers that can initiate a trigger event using `SafetyModule.trigger(bytes32 triggerEventId_)`. The `triggerEventId_`, generated by the controller, encodes information about the specific event. When triggered, the Safety Module updates the `TriggerEventRaiseState` for that `triggerEventId_` to `PENDING_RAISE`. The controller can then call `requestRaise(triggerEventId_)` to raise assets from the reserve pools, enabling them to be used as specified (see [Safety Module Raising](/developer-guides/safety-module-raises)).

### Controller

The controller to add to the Safety Module (see [Creating a Controller](/developer-guides/create-a-controller)).

### Exists

A boolean which specifies whether or not the trigger is used by the Safety Module. This is helpful for [configuration updates ](/developer-guides/manage-a-safety-module)to remove triggers from the list of triggers that are allowed to trigger the Safety Module.

## Delays Config

```solidity
struct Delays {
  // Duration between when SafetyModule updates are queued and when they can be executed.
  uint64 configUpdateDelay;
  // Defines how long the owner has to execute a configuration change, once it can be executed.
  uint64 configUpdateGracePeriod;
  // Delay for two-step withdraw process (for deposited reserve assets).
  uint64 withdrawDelay;
  // The default amount of time that a trigger event remains valid before expiring for this SafetyModule.
  uint256 triggerEventValidityDuration;
}
```

The Delays config is for Safety Module-level delays.

### Config Update Delay

The config update delay is the duration between when Safety Module updates are queued and when they can be applied / executed (see [Manage a Safety Module](/developer-guides/manage-a-safety-module)). This delay should be longer than the withdraw delay to allow Safety Module depositors to respond to queued config updates before they are applied.

### Config Update Grace Period

The config update grace period is the duration after the config update delay that the Safety Module owner is allowed to apply / execute the queued config changes  (see [Manage a Safety Module](/developer-guides/manage-a-safety-module)). If the owner does not apply the updates by the end of this period, they cannot be applied.&#x20;

### Withdraw Delay

The withdraw delay is for the two-step withdraw process (see [Safety Module Deposits](/developer-guides/safety-module-deposits)). This delay should be shorter than the config update delay to allow Safety Module depositors to respond to queued config updates before they are applied.

### Trigger Event Validity Duration

The trigger event validity duration outlines how long a trigger event from a controller is valid for. Once a trigger event expires, it can be reset by calling `safetyModule.resetTriggerEvent(ISafetyModuleController controller_, bytes32 triggerEventId_)`. Once a trigger event is reset, it can no longer be used to raise / tap funds from the safety module.&#x20;


# Deploy a Safety Module

To deploy a SafetyModule, call `CozySafetyModuleManager.createSafetyModule`:

```solidity
/// @notice Deploys a new SafetyModule with the provided parameters.
/// @param owner_ The owner of the SafetyModule.
/// @param pauser_ The pauser of the SafetyModule.
/// @param configs_ The configuration for the SafetyModule.
/// @param salt_ Used to compute the resulting address of the SafetyModule.
function createSafetyModule(
    address owner_,
    address pauser_,
    ConfigUpdateCalldataParams calldata configs_,
    bytes32 salt_
) external returns (ISafetyModule safetyModule_);
```

See [Define Safety Module Configuration](/developer-guides/creating-a-safety-module/define-safety-module-configuration) for how to define `configs_` , and [Permissions and Authorization](/developer-guides/permissions-and-authorization) for how to define `owner_` and `pauser_`. It is recommended that the `salt_` is randomly generated.


# Manage a Safety Module

As the `owner` of a Safety Module, it is possible to update the configuration in order to:

* Add new reserve pools
* Add/remove controllers that are allowed to be used to trigger the Safety Module
* Update delays

Configuration updates follows a two-step process:

1. Configuration updates are queued with `SafetyModule.updateConfigs`:

   <pre class="language-solidity"><code class="lang-solidity"><strong>/// @notice Parameters for configuration updates.
   </strong>struct ConfigUpdateCalldataParams {
     // The new reserve pool configs.
     ReservePoolConfig[] reservePoolConfigs;
     // The new controller configs.
     ControllerConfig[] controllerConfigUpdates;
     // The new delays config.
     Delays delaysConfig;
   }

   /// @notice Signal an update to the safety module configs. Existing queued updates are overwritten.
   /// @param configUpdates_ The new configs. Includes:
   /// - reservePoolConfigs: The array of new reserve pool configs, sorted by associated ID. The array may also
   /// include config for new reserve pools.
   /// - controllerConfigUpdates: The array of controller config updates. It only needs to include config for updates to
   /// existing controllers or new controllers.
   /// - delaysConfig: The new delays config.
   function updateConfigs(ConfigUpdateCalldataParams calldata configUpdates_) external;
     onlySharedSafetyModuleIfSetElseOwner;
   </code></pre>
2. Configuration updates can be applied after the [config update delay](/developer-guides/creating-a-safety-module/define-safety-module-configuration#config-update-delay) has elapsed and within the [config update grace period](/developer-guides/creating-a-safety-module/define-safety-module-configuration#config-update-grace-period) with `SafetyModule.finalizeUpdateConfigs`:

   ```solidity
   /// @notice Execute queued updates to the safety module configs.
   /// @param configUpdates_ The new configs. Includes:
   /// - reservePoolConfigs: The array of new reserve pool configs, sorted by associated ID. The array may also
   /// include config for new reserve pools.
   /// - controllerConfigUpdates: The array of controller config updates. It only needs to include config for updates to
   /// existing controllers or new controllers.
   /// - delaysConfig: The new delays config.
   function finalizeUpdateConfigs(ConfigUpdateCalldataParams calldata configUpdates_) external;
   ```

The reserve pool configs for the update must obey the general requirements for creating a Safety Module (see [Define Safety Module Configuration](/developer-guides/creating-a-safety-module/define-safety-module-configuration)).&#x20;

Also, it is not possible to remove reserve pools, so existing reserve pools must be included at the start of the `ReservePoolConfig[]` sorted by the associated reserve pool IDs. Any new reserve pools come after the existing reserve pools and the reserve pool IDs assigned to them respect the order of the array.

**Note:** If a configuration update is queued but not finalized before a Safety Module enters the `TRIGGERED` state, the queued update is cleared and may be re-queued when the Safety Module returns to either the `ACTIVE` or `PAUSED` states.

**Note:** When a Safety Module is part of a Shared Safety Module, the `sharedSafetyModule` is the address authorized to do configuration updates, not the `owner`. See [here](/developer-guides/shared-safety-module-functionality) for more details.


# Safety Module Deposits

Assets deposited into a Safety Module can be tapped by controllers if the Safety Module is triggered (see [Safety Module Raising](/developer-guides/safety-module-raises)). In return, depositors are minted receipt tokens which may be used to earn rewards (see [Stake into a Rewards Manager](/developer-guides/stake-into-a-rewards-manager)) and withdraw their assets.

To deposit assets, `SafetyModule.depositReserveAssets` or `SafetyModule.depositReserveAssetsWithoutTransfer` can be used.

**Note:** The `SafetyModule.depositReserveAssetsWithoutTransfer` is only designed to be used by integrators or the [CozyRouter](#using-cozyrouter-to-deposit-assets) contract, where assets are atomically transferred into the SafetyModule and deposited on behalf of a user. Otherwise, assets that have been transferred and sitting in the SafetyModule are at risk of being claimed as a deposit by someone who front-runs the call to `depositReserveAssetsWithoutTransfer`.

```solidity
/// @notice Deposits reserve assets into the SafetyModule and mints deposit receipt tokens.
/// @dev Expects `msg.sender` to have approved this SafetyModule for `reserveAssetAmount_` of
/// `reservePools[reservePoolId_].asset` so it can `transferFrom` the assets to this SafetyModule.
/// @param reservePoolId_ The ID of the reserve pool to deposit assets into.
/// @param reserveAssetAmount_ The amount of reserve assets to deposit.
/// @param receiver_ The address to receive the deposit receipt tokens.
function depositReserveAssets(uint8 reservePoolId_, uint256 reserveAssetAmount_, address receiver_)
    external
    returns (uint256 depositReceiptTokenAmount_);
    
/// @notice Deposits reserve assets into the SafetyModule and mints deposit receipt tokens.
/// @dev Expects depositer to transfer assets to the SafetyModule beforehand.
/// @param reservePoolId_ The ID of the reserve pool to deposit assets into.
/// @param reserveAssetAmount_ The amount of reserve assets to deposit.
/// @param owner_ The owner of the deposited assets (for event logging purposes).
/// @param receiver_ The address to receive the deposit receipt tokens.
function depositReserveAssetsWithoutTransfer(
  uint8 reservePoolId_,
  uint256 reserveAssetAmount_,
  address owner_,
  address receiver_
) external returns (uint256 depositReceiptTokenAmount_)
```

`SafetyModule.depositReserveAssets` requires `msg.sender` to have approved `SafetyModule` to a spend sufficient amount of their `SafetyModule.reservePools(reservePoolId).asset` balance.

`SafetyModule.depositReserveAssetsWithoutTransfer` requires the `SafetyModule.reservePools(reservePoolId).asset` amount being deposited to be transferred to the Safety Module beforehand.

## Using CozyRouter to deposit assets

Using the [CozyRouter](broken://pages/z3zOxW6ojdnY9n2NEfch) may be preferable in cases where integrators would like to batch several Safety Module related function calls into a single transaction (e.g. wrap ETH to WETH and deposit).

To deposit assets using the CozyRouter, integrators can use `CozyRouter.depositReserveAssets`:

```solidity
/// @notice Deposits assets into a `safetyModule_` reserve pool by transferring `reserveAssetAmount_` of the reserve
/// assets from the caller to the `safetyModule_` and minting `depositReceiptTokenAmount_` receipt tokens to the
/// `receiver_`.
/// @dev This will revert if the router is not approved for at least `reserveAssetAmount_` of the reserve asset.
/// @dev The `receiver_` must be set to the msg.sender to mantain the custody invariant.
function depositReserveAssets(
  ISafetyModule safetyModule_,
  uint8 reservePoolId_,
  uint256 reserveAssetAmount_,
  address receiver_
) public payable returns (uint256 depositReceiptTokenAmount_);
```

This method will:

* Transfer the underlying reserve assets from the `msg.sender` to the Safety Module.
* Call `SafetyModule.depositReserveAssetsWithoutTransfer.`

`CozyRouter.depositReserveAssets` requires the depositor to have approved `CozyRouter` to a spend sufficient amount of their `SafetyModule.reservePools(reservePoolId).asset` balance.

## Deposit mechanics

On deposit, high-level the Safety Module does the following:

* Check if the Safety Module is `PAUSED`. If so, revert.
* Check the Safety Module's asset balance to determine if the total deposit amount was transferred to it. If not, revert.
* Update the relevant reserve pool's internal accounting.
* Mint the `receiver_` address deposit receipt tokens.
* Emit a `Deposited` event.


# Safety Module Redemptions / Withdrawals

Depositors are able to redeem deposit receipt tokens / withdraw assets from Safety Modules. Redemptions follow a two-step process in which the redemption is queued and then completed after a delay (see [Withdraw Delay](/developer-guides/creating-a-safety-module/define-safety-module-configuration#withdraw-delay)).  Note: redemptions cannot be queued or completed when the Safety Module is triggered (see [Safety Module States](/developer-guides/safety-module-states)).

`SafetyModule.redeem` is used to queue a redemption:

```solidity
/// @notice Queues a redemption by burning `depositReceiptTokenAmount_` of `reservePoolId_` reserve pool deposit
/// tokens.
/// When the redemption is completed, `reserveAssetAmount_` of `reservePoolId_` reserve pool assets will be sent
/// to `receiver_` if the reserve pool's assets are not tapped. If the SafetyModule is paused, the redemption
/// will be completed instantly.
/// @dev Assumes that user has approved the SafetyModule to spend its deposit tokens.
/// @param reservePoolId_ The ID of the reserve pool to redeem from.
/// @param depositReceiptTokenAmount_ The amount of deposit receipt tokens to redeem.
/// @param receiver_ The address to receive the reserve assets.
/// @param owner_ The address that owns the deposit receipt tokens.
function redeem(uint8 reservePoolId_, uint256 depositReceiptTokenAmount_, address receiver_, address owner_)
    external
    returns (uint64 redemptionId_, uint256 reserveAssetAmount_);
```

When a redemption is queued:

* The owner's deposit receipt tokens are burned.
* `reservePools(reservePoolId_).pendingWithdrawalsAmount` increases by the total assets earmarked for redemption (including fees).
* A `Redemption` struct is inserted into the Safety Module's  `redemptions` mapping. The redemption has an associated `redemptionId_` determined by a state variable `redemptionCounter` which gets incremented by 1 on each new redemption. The `redemptionId_`

```solidity
struct Redemption {
  uint8 reservePoolId;           // Reserve pool being redeemed.
  uint216 receiptTokenAmount;    // Receipt tokens burned when queuing.
  IReceiptToken receiptToken;    // The receipt token contract.
  uint128 totalAssetAmount;      // Gross reserve assets (including fees) cached at queue time.
  address owner;                 // Owner of the burned receipt tokens.
  uint40 queueTime;              // Timestamp when the redemption was queued.
  uint40 delay;                  // Redemption delay captured at queue time (0 if paused).
  uint32 queuedAccISFsLength;    // pendingRedemptionAccISFs length snapshot for scaling.
  uint256 queuedAccISF;          // Last pendingRedemptionAccISFs value at queue time.
}
```

If the Safety Module is PAUSED (or the withdraw delay is zero), `redeemAndComplete` can be called to queue and complete in a single transaction; otherwise a RedemptionPending event is emitted with the redemptionId\_ needed for completion. Note that the struct no longer stores a receiver, the destination address is supplied later during `completeRedemption` or `completeRedemptionBySig.`             &#x20;

```solidity
/// @notice Combined redeem() and completeRedemption(). Designed to be used when SM is paused or when the withdraw
/// delay is 0.
/// @dev Assumes that user has approved the SafetyModule to spend its deposit tokens.
/// @param reservePoolId_ The ID of the reserve pool to redeem from.
/// @param depositReceiptTokenAmount_ The amount of deposit receipt tokens to redeem.
/// @param owner_ The address that owns the deposit receipt tokens.
/// @param receiver_ The address to receive the reserve assets.
function redeemAndComplete(
    uint8 reservePoolId_,
    uint256 depositReceiptTokenAmount_,
    address owner_,
    address receiver_
) external returns (uint64 redemptionId_, uint256 reserveAssetAmount_, uint256 redemptionFeeAmount_) {}
```

```solidity
  /// @notice Completes the redemption request for the specified redemption ID. Owner-only path (no signature). Reserve
  /// pool assets will be sent to `receiver_` if the reserve pool's assets are not tapped.
  /// @param redemptionId_ The ID of the redemption to complete.
  /// @param receiver_ The address to receive the redeemed assets.
  function completeRedemption(uint64 redemptionId_, address receiver_)
    external
    returns (uint256 reserveAssetAmount_, uint256 redemptionFeeAmount_){}
```

* To complete a redemption for yourself, use `completeRedemption`.&#x20;
* The queued redemption data is obtained from the mapping, `redemptions[redemptionId_]`. It is then deleted from the mapping to ensure that redemption cannot be completed again.
* The contract checks that either the Safety Module is `PAUSED` or at least `SafetyModule.delays().withdrawDelay` amount of time has elapsed since `Redemption.queueTime`.
* The final redemption assets gets computed, which may have decreased if reserve pool assets were tapped (see [Safety Module Raising](/developer-guides/safety-module-raises)).
* `SafetyModule.assetPool(asset_).amount` , `SafetyModule.reservePool(reservePoolId_).pendingWithdrawalsAmount` , and `SafetyModule.reservePool(reservePoolId_).depositAmount` are decreased.
* The final redemption assets are transferred to the receiver.
* A `Redemption` event is emitted.

To complete a redemption on behalf of another user, you may use `completeRedemptionBySig`

```solidity
/// @notice Returns the domain separator.
function domainSeparator() external view returns (bytes32);

/// @notice Tracks per-owner nonces for EIP-712 signed operations.
/// @param owner_ the owner of this nonce
/// @param actionKey_ typehash used for this call (i.e. COMPLETE_REDEMPTION_BY_SIG_TYPEHASH)
function eip712Nonces(address owner_, bytes32 actionKey_) external view returns (uint256);

bytes32 public constant COMPLETE_REDEMPTION_BY_SIG_TYPEHASH = keccak256(
    "CompleteRedemptionBySig(address owner,uint64 redemptionId,address caller,address receiver,uint256 deadline)"
  );

/// @notice Completes the redemption request for the specified redemption ID on behalf of the owner. Permit-style
/// path: owner signs off-chain; specific caller executes on-chain. Reserve pool assets will be sent to `receiver_` if
/// the reserve pool's assets are not tapped.
/// @dev Signature binds to (owner, redemptionId, caller=msg.sender, deadline).
/// @param redemptionId_ The ID of the redemption to complete.
/// @param owner_ The owner of the deposit receipt tokens.
/// @param receiver_ The address to receive the redeemed assets.
/// @param deadline_ The time at which the signature expires.
/// @param signature_ The owner's signature over the EIP-712 structured data.
function completeRedemptionBySig(
  uint16 rewardPoolId_,
  uint256 rewardAssetAmount_,
  address owner_,
  address receiver_,
  uint256 deadline_,
  bytes calldata signature_
) external {

  bytes32 digest_ = keccak256(
    abi.encodePacked(
      "\x19\x01",
      keccak256(
        abi.encode(
          domainSeparator()
        )
      ),
      keccak256(
        abi.encode(COMPLETE_REDEMPTION_BY_SIG_TYPEHASH, owner_, redemptionId_, msg.sender, receiver_, deadline_)
      )
    )
  );

  if (!SignatureChecker.isValidSignatureNow(owner_, digest_, signature_)) revert InvalidSignature();
}
```

* The owner must sign a digest that matches the above.
* Fetch Domain Separator via public `domainSeparator()` getter shown above exposed in ISafetyModule and include them when constructing the EIP-712 typed data.
* The above `completeRedemptionBySig` function is truncated to only show the relevant structure of the digest.

### Queued vs final redemption assets

If the reserve pool assets have been [tapped](/developer-guides/safety-module-raises) since a redemption was queued, the final redemption assets a user receives on completion may be smaller than the queued redemption assets.

All assets in the reserve pool are made available to process payouts for raises. This includes any pending redemption assets. So, the following scaling factor is retroactively applied to all pending redemptions on completion:

```
factor = 1 - raiseAmount / (reservePool.depositAmount)
```

This scaling factor may compound if multiple taps occur before a pending redemption is completed.


# Safety Module States

The Safety Module can be in three states:

```solidity
enum SafetyModuleState {
  ACTIVE,
  TRIGGERED,
  PAUSED
}
```

The table below details valid state transitions:

| From      | To        | Notes                                                                                                                                                                                                                                                 |
| --------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ACTIVE    | TRIGGERED | <p>Occurs when <code>SafetyModule.trigger(</code></p><p><code>triggerEventId\_)</code> is executed with a valid controller and the SafetyModule is not <code>PAUSED</code> (see <a href="/pages/3MwdRuow7dR1BRLy0kHh">Safety Module Raising</a>).</p> |
| ACTIVE    | PAUSED    | Occurs when either the protocol owner or pauser or the SafetyModule owner or pauser pauses the SafetyModule.                                                                                                                                          |
| TRIGGERED | ACTIVE    | Occurs when safety module has finished paying out all pending raises (see [Safety Module Raising](/developer-guides/safety-module-raises)).                                                                                                           |
| TRIGGERED | PAUSED    | Occurs when either the protocol pauser or SafetyModule pauser pauses the SafetyModule.                                                                                                                                                                |
| PAUSED    | ACTIVE    | Occurs when either the protocol owner or the SafetyModule owner unpauses the SafetyModule.                                                                                                                                                            |
| PAUSED    | TRIGGERED | Occurs when either the protocol owner or the SafetyModule owner unpauses the SafetyModule and `SafetyModule.numPendingRaises > 0` (see [Safety Module Raising](/developer-guides/safety-module-raises)).                                              |

\
The table below details which actions are allowed in each of these states:

<table><thead><tr><th width="230">Action / State</th><th>Active</th><th>Triggered</th><th>Paused</th></tr></thead><tbody><tr><td><strong>Deposit Reserve Assets</strong></td><td>Y</td><td>Y</td><td>N</td></tr><tr><td><strong>Queue Redeem Reserve Assets</strong></td><td>Y</td><td>N</td><td>N</td></tr><tr><td><strong>Complete Redeem Reserve Assets</strong></td><td>Y</td><td>N</td><td>N</td></tr><tr><td><strong>Instant Redeem Reserve Assets</strong></td><td>N</td><td>N</td><td>Y</td></tr><tr><td><strong>Trigger</strong></td><td>Y</td><td>Y</td><td>Y</td></tr><tr><td><strong>RequestRaise</strong></td><td>N</td><td>Y</td><td>N</td></tr><tr><td><strong>Queue Update Configs</strong></td><td>Y</td><td>N</td><td>Y</td></tr><tr><td><strong>Finalize</strong> <strong>Update Configs</strong></td><td>Y</td><td>N</td><td>Y</td></tr><tr><td><strong>Pause</strong></td><td>Y</td><td>Y</td><td>N</td></tr><tr><td><strong>Unpause</strong></td><td>N</td><td>N</td><td>Y</td></tr><tr><td><strong>Fees Drip</strong></td><td>Y</td><td>N</td><td>N</td></tr><tr><td><strong>Claim Fees</strong></td><td>Y</td><td>Y</td><td>Y</td></tr></tbody></table>


# Safety Module Fees

The Cozy Safety Module protocol is able to take fees in two ways:

* Reserve pool assets drip as fees at a pre-configured rate
* A fixed % of all redemptions are paid as fees

All fees are received by the owner address of the protocol - `CozySafetyModuleManager.owner()`.   **Currently, both fees are set to zero**.

## How are fees dripped?

The Cozy Safety Module protocol uses a drip model which defines the rate at which fees drip from reserve pool assets. The drip model may use the last time fees were dripped in the Safety Module to pro-actively determine the amount of assets to drip to claimable fees.

```solidity
interface IDripModel {
  /// @notice Returns the drip factor, the percentage of reserve assets which should drip to fees, as a wad. For
  /// example, it there are 100 reserve assets and this method returns 1e17, then 100 * 1e17 / 1e18 = 10 assets
  /// will drip to fees.
  /// @param lastDripTime_ Timestamp of the last drip
  function dripFactor(uint256 lastDripTime_) external view returns (uint256 dripFactor_);
}
```

An example of a drip model that may be used for fees is the [exponential-rate drip model](/developer-guides/create-a-rewards-manager/reward-pool-drip-models#exponential-rate-drip-model).

The core drip functionality is implemented in `SafetyModule._dripFeesFromReservePool`. When a reserve pool drips fees, the following happens:

* The amount of dripped fees is calculated as `(reservePool.depositAmount - reservePool.pendingWithdrawalsAmount) * dripModel.dripFactor(reservePool.lastFeesDripTime) / 1e18`, rounded down.
* `reservePool.depositAmount` gets decremented by the amount of dripped fees.
* `reservePool.feeAmount` gets increased by that same amount of dripped fees.
* `reservePool.lastFeesDripTime` updates to `block.timestamp`.

### When do fees drip?

Fees can either drip simultaneously for all reserve pools or for a single reserve pool.&#x20;

Many operations in the Safety Module internally drip fees. However, anyone can drip fees on-demand by calling `SafetyModule.dripFees()`  for all reserve pools and `SafetyModule.dripFeesFromReservePool(reservePoolId_)` for a specific reserve pool, which are also public and external functions, respectively.

The following operations internally drip fees for all reserve pools:

* `SafetyModule.pause`
* `SafetyModule.unpause`
* `SafetyModule.trigger`

The following operations internally drip fees for a single reserve pool:

* `SafetyModule.depositReserveAssets`
* `SafetyModule.depositReserveAssetsWithoutTransfer`
* `SafetyModule.redeem`
* `SafetyModule.claimFees`

### How are fees from reserve pool drip collected?

Fees are collected with `CozySafetyModuleManager.claimFees`, which transfers all accrued fees in the specified Safety Modules to the protocol owner address `CozySafetyModuleManager.owner()`.

```solidity
/// @notice For all specified `safetyModules_`, transfers accrued fees to the owner address.
function claimFees(ISafetyModule[] calldata safetyModules_) external;
```

&#x20;This calls `SafetyModule.claimFees` , which is only allowed to be called from `CozySafetyModuleManager`.&#x20;

## Redemption Fees

The `CozySafetyModuleManager` defines a global `redemptionFee` which applies to all redemptions from the Safety Module. The redemption fee simply takes a fixed % of all reserve assets which are redeemed as fees and sends them to the `CozySafetyModuleManager.owner()`.


# Safety Module Raises

## Triggering a Safety Module

Assets in a Safety Module can be tapped in the event that any of the Safety Module's configured controllers are used to trigger it. To trigger a Safety Module, `SafetyModule.trigger(triggerEventId_)` can be called permissionlessly with a controller that the Safety Module has been configured to use (see [Create a Controller](/developer-guides/create-a-controller)).

```solidity
/// @notice Triggers the SafetyModule by referencing one of the controllers configured for this SafetyModule.
/// @param triggerEventId_ The trigger event ID to reference when triggering the SafetyModule.
/// @param validityDuration_ The duration of the trigger event validity. This will be capped by the SafetyModule's
/// default `triggerEventValidityDuration` delay.
function trigger(bytes32 triggerEventId_, uint256 validityDuration_) external;
```

Each controller can trigger a SafetyModule an unlimited number of times, given that each triggerEventId is unique.

At a high-level, when `SafetyModule.trigger(triggerEventId_, uint256 validityDuration_)` is called successfully with a valid controller and a unique triggerEventId:

* Protocol fees are dripped.
* The trigger event state for the controller and  triggerEventId is set to PENDING\_RAISE `triggerEventData[controller_][triggerEventId_].triggerEventState = TriggerEventState.PENDING_RAISE`
* `safetyModule.numPendingRaises` and `controllerData[controller_].numPendingRaises` is incremented by 1. An invariant of the protocol is that the Safety Module is triggered while `SafetyModule.numPendingRaises > 0 && SafetyModule.safetyModuleState != SafetyModuleState.PAUSED` (see [Safety Module States](/developer-guides/safety-module-states)).
* If the safety module is part of a shared safety module,  `SharedSafetyModule.propagateTrigger(controller_,triggerEventId_, expiresAt_)` is called to initiate trigger events across all sibling safety modules.
* `event Triggered(controller_, triggerEventId_, expiresAt_)` is emitted
* `SafetyModule.safetyModuleState()` is set to triggered if the Safety Module is not paused.

### Safety Module State Change

When `SafetyModule.trigger` is called with a valid controller and unique triggerEventId, the Safety Module's state becomes triggered if it is currently active and not paused (see [Safety Module States](/developer-guides/safety-module-states)). &#x20;

## Raising Safety Module Assets

Assets in a Safety Module can be raised either by an authorized controller or by the parent Shared Safety Module, provided the Safety Module is in the `TRIGGERED` state (`SafetyModule.safetyModuleState() == TRIGGERED`).

To raise assets, controllers can call `SafetyModule.requestRaise()`:

```solidity
interface IRaiseStrategy {
  /// @notice Converts asset needs to safety module specific raises
  /// @param originSafetyModule_ The safety module that triggered the raise
  /// @param assetNeeds_ The asset needs to be converted to raises
  /// @param data_ Arbitrary data that can be used to configure the raise strategy
  function calculateRaise(ISafetyModule originSafetyModule_, AssetNeed[] memory assetNeeds_, bytes calldata data_)
    external
    returns (SafetyModuleRaise[] memory);
}

struct AssetNeed {
  // Asset that needs to be tapped.
  IERC20 asset;
  // Amount of asset that needs to be tapped.
  uint256 amount;
}

struct Raise {
  // ID of the reserve pool.
  uint8 reservePoolId;
  // Asset amount that will be tapped from the reserve pool.
  uint256 amount;
}

/// @notice Requests the raise for a given trigger event id, by calling the raise strategy with the given asset needs
/// and then raising the SafetyModule.
/// @dev If the SafetyModule is in a SharedSafetyModule, the request raise call is delegated to the
/// SharedSafetyModule.
/// @dev Controllers can call this function once for a given trigger event id.
/// @param triggerEventId_ The trigger event id to raise for.
/// @param receiver_ The address to receive the tapped assets.
/// @param assetNeeds_ The asset needs for the trigger event
/// @param raiseStrategy_ The raise strategy for the asset needs.
/// @param data_ Arbitrary data that can be used to configure the raise strategy
function requestRaise(
  bytes32 triggerEventId_,
  address receiver_,
  AssetNeed[] memory assetNeeds_,
  IRaiseStrategy raiseStrategy_,
  bytes calldata data_
) external
```

While Shared Safety modules can call `sharedSafetyModuleRaise()`

```solidity
/// @notice Used by the SharedSafetyModule to raise the SafetyModule.
/// @dev Only the SharedSafetyModule can call this function.
function sharedSafetyModuleRaise(
    bytes32 triggerEventId_,
    Raise[] memory raises_,
    address receiver_,
    ISafetyModuleController originController_
 ) external
```

At a high-level, when `SafetyModule.requestRaise` is called by a valid controller

* `SafetyModule.numPendingRaises()` and `controllerData[controller_].numPendingRaises` are decremented by 1.
* If the safety module is part of a shared safety module, `SharedSafetyModule.requestRaise(triggerEventId_, receiver_, assetNeeds_, raiseStrategy_, controller_, data_)` is called to initiate raise events across all sibling safety modules.&#x20;
* Assets are tapped from each reserve pool according to the `raises_` specified, and transferred to `receiver_`.
  * If any of the raise amounts exceeds reserve pool deposit amounts, the transaction reverts (see [Define Safety Module Configuration](/developer-guides/creating-a-safety-module/define-safety-module-configuration#reserve-pool-maximum-slash-percentages)).
  * Assets pending withdrawal are also tapped (see [Safety Module Redemptions / Withdrawals](/developer-guides/safety-module-redemptions-withdrawals)).
* Internal asset accounting is updated for each reserve pool and underlying asset.
  * `SafetyModule.reservePool(reservePoolId_).depositAmount` is decreased by the amount tapped from the reserve pool.
  * `SafetyModule.assetPools(asset_).amount` is decreased by the amount of the underlying asset tapped.
* If `SafetyModule.numPendingRaises == 0`, `SafetyModule.safetyModuleState()` is set to active.
* For each reserve pool that is tapped, `event ReservePoolTapped( ISafetyModuleController originController_, bytes32 triggerEventId_, address receiver_, uint8 reservePoolId_. uint256 raiseAmount);` is emitted.
* `event SafetyModuleTapped(ISafetyModuleController originController_, bytes32 triggerEventId_, address receiver_)` is emitted.


# Shared Safety Module Functionality

A Shared Safety Module is an external module that allows many individual Safety Modules to coordinate, so they can share risk by pooling reserve assets.

When a Safety Module is part of a Shared Safety Module, its `ISharedSafetyModule sharedSafetyModule` storage variable will be a non-zero address that is the associated `SharedSafetyModule` contract. If `sharedSafetyModule == address(0)`, the Safety Module is not part of Shared Safety Module.

## Specifying A Shared Safety Module

Setting a Shared Safety Module follows a three-step process, where the last two steps are similar to configuration changes (see [Manage a Safety ](/developer-guides/manage-a-safety-module)Module):

1. The Safety Module `owner` first sets a `proposedSharedSafetyModule` by calling:

```solidity
/// @notice Used to set the proposed SharedSafetyModule.
/// @param proposedSharedSafetyModule_ The new proposed SharedSafetyModule.
/// @dev Only the owner can call this function.
function setProposedSharedSafetyModule(ISharedSafetyModule proposedSharedSafetyModule_) external onlyOwner {
```

2. The `proposedSharedSafetyModule` is allowed to queue itself by calling:

<pre class="language-solidity"><code class="lang-solidity"><strong>/// @notice Used to queue an update to this SafetyModule's SharedSafetyModule.
</strong>/// @dev Only the proposed SharedSafetyModule can call this function.
function queueSharedSafetyModule() external onlyProposedSharedSafetyModule;
</code></pre>

3. The queued `sharedSafetyModule` can get applied by the `proposedSharedSafetyModule` after the [config update delay](/developer-guides/creating-a-safety-module/define-safety-module-configuration#config-update-delay) has elapsed and within the [config update grace period](/developer-guides/creating-a-safety-module/define-safety-module-configuration#config-update-grace-period) with `SafetyModule.finalizeSharedSafetyModule`:

```solidity
/// @notice Finalizes an update SharedSafetyModule for the SafetyModule.
/// @dev Only the proposed SharedSafetyModule can call this function.
function finalizeSharedSafetyModule() external onlyProposedSharedSafetyModule;
```

The delay period allows Safety Module depositors to withdraw in case they do not wish to be part of the specified Shared Safety Module.

## Shared Safety Module Privileges

A Shared Safety Module is given certain privileges with respect to the Safety Module, explained below.

### Triggering the Safety Module

A **Shared Safety Module** is triggered indirectly via one of its child `SafetyModule` contracts. When a child `SafetyModule`’s `trigger()` function is called, it forwards the trigger to its parent `SharedSafetyModule` if one is configured. This is done by invoking `SharedSafetyModule.propagateTrigger()`.

> **Note:** The snippet below only shows the relevant portion of the child module’s `trigger()` function. It is not the complete implementation of the trigger flow.

```solidity
function trigger(bytes32 triggerEventId_) external {
  if (address(sharedSafetyModule) != address(0)) {
    sharedSafetyModule.propagateTrigger(controller_, triggerEventId_, expiresAt_);
  }
}
```

PropagateTrigger will then call sharedSafetyModuleTrigger on all of the sibling Safety Modules

```solidity
  function sharedSafetyModuleTrigger(
    bytes32 triggerEventId_,
    ISafetyModule originSafetyModule_,
    ISafetyModuleController originController_,
    uint256 expiresAt_
  ) external onlySharedSafetyModule {}
```

### Updating Safety Module Configurations

The Shared Safety Module assumes the traditional role of the `owner` in Safety Module update[ configurations](/developer-guides/manage-a-safety-module). Specifically, it is authorized to call `SafetyModule.updateConfigs`:

```solidity
/// @notice Signal an update to the safety module configs. Existing queued updates are overwritten.
/// @param configUpdates_ The new configs. Includes:
/// - reservePoolConfigs: The array of new reserve pool configs, sorted by associated ID. The array may also
/// include config for new reserve pools.
/// - controllerConfigUpdates: The array of controller config updates. It only needs to include configs for updates to
/// existing controllers or new controllers.
/// - delaysConfig: The new delays config.
/// @dev Only the SharedSafetyModule can call this function, if it is set. Else, only the owner can call this
/// function.
function updateConfigs(ConfigUpdateCalldataParams calldata configUpdates_)
    external
    onlySharedSafetyModuleIfSetElseOwner;
```

Configuration updates that occur while a Safety Module is part of a Shared Safety Module have two unique features:

* The Shared Safety Module's config update delay and config update grace period are used
* Only the `sharedSafetyModule` is authorized to call `SafetyModule.finalizeUpdateConfigs` instead of anyone

### Resetting The Shared Safety Module

The Shared Safety Module is the only address authorized to reset the `sharedSafetyModule` to `address(0)`:

```solidity
/// @notice Used to trigger the SafetyModule if it is part of a SharedSafetyModule.
/// @dev Only the SharedSafetyModule can call this function.
function resetSharedSafetyModule() external onlySharedSafetyModule;
```

This is intended to be used when the Safety Module leaves the Shared Safety Module.


# Create a Rewards Manager

Creating a Rewards Manager is a two-step process:

1. [Define a Rewards Manager configuration](/developer-guides/create-a-rewards-manager/define-a-rewards-manager-configuration)
2. [Deploy a Rewards Manager](/developer-guides/create-a-rewards-manager/deploy-a-rewards-manager)


# Define a Rewards Manager Configuration

A Rewards Manager config consists of an array of stake pool and reward pool configs: `StakePoolConfig[]` and `RewardPoolConfig[]`. These configs are passed to `CozyManager.createRewardsManager` when deploying a new Rewards Manager.

## Stake Pool Config

```solidity
struct StakePoolConfig {
  // The underlying asset of the stake pool.
  IERC20 asset;
  // The rewards weight of the stake pool.
  uint16 rewardsWeight;
}
```

### Stake Pool Assets

Each stake pool must have a unique underlying asset. When constructing `StakePoolConfig[]`, the structs must be sorted by the address of the underlying stake asset. Passing in an array where the structs are unsorted or contain a duplicate asset will revert.

### Stake Pool Rewards Weights

The rewards weight determines the share of the total rewards that are distributed to a given stake pool. For example, a rewards weight of 90% implies stakers in that pool earn 90% of all dripped reward assets.

The `rewardsWeight` parameter is represented as `zoc` (e.g. 5000 is 50%). The sum of rewards weights across all stake pools must be a `zoc` (or 100%).

### Allowed Stake Pools

The `allowedStakePools` constant defines a limit on the number of stake pools in a single Rewards Manager.

## Reward Pool Config

```solidity
struct RewardPoolConfig {
  // The underlying asset of the reward pool.
  IERC20 asset;
  // The drip model for the reward pool.
  IDripModel dripModel;
}
```

### Reward Pool Assets

There are no restrictions on the underlying assets of reward pools.

### Reward Pool Drip Models

The drip model for a reward pool defines the rate at which assets deposited into a reward pool accrue (i.e. "drip") to stakers. Drip-decay models must conform to the `IDripModel` interface.&#x20;

For more details on the mechanics of drip models, see [here](/developer-guides/create-a-rewards-manager/reward-pool-drip-models).

### Allowed Reward Pools

The `allowedRewardPools` constant defines a limit on the number of reward pools in a single Rewards Manager.


# Deploy a Rewards Manager

To deploy a RewardsManager, call `CozyManager.createRewardsManager:`

```solidity
/// @notice Deploys a new Rewards Manager with the provided parameters.
/// @param owner_ The owner of the rewards manager.
/// @param pauser_ The pauser of the rewards manager.
/// @param stakePoolConfigs_ The array of stake pool configs. These configs must obey requirements described in
/// `Configurator.updateConfigs`.
/// @param rewardPoolConfigs_  The array of reward pool configs. These configs must obey requirements described in
/// `Configurator.updateConfigs`.
/// @param salt_ Used to compute the resulting address of the rewards manager.
/// @return rewardsManager_ The newly created rewards manager.
function createRewardsManager(
    address owner_,
    address pauser_,
    StakePoolConfig[] calldata stakePoolConfigs_,
    RewardPoolConfig[] calldata rewardPoolConfigs_,
    bytes32 salt_
) external returns (IRewardsManager rewardsManager_);
```

When selecting the underlying stake and reward assets of a Rewards Manager, you should be considerate of the [Token Integration Guidelines](/developer-guides/token-integration-guidelines).


# Reward Pool Drip Models

The drip model for a reward pool defines the rate at which assets deposited into the reward pool accrue (i.e. "drip") to stakers.&#x20;

Drip models must conform to the `IDripModel` interface, and may use a reward pool's last drip time to determine the returned drip factor.&#x20;

```solidity
interface IDripModel {
  /// @notice Returns the drip factor, the percentage of undripped rewards which should drip to stakers, as a wad. For
  /// example, it there are 100 undripped reward assets and this method returns 1e17, then 100 * 1e17 / 1e18 = 10 assets
  /// will drip.
  /// @param lastDripTime_ Timestamp of the last drip
  function dripFactor(uint256 lastDripTime_) external view returns (uint256 dripFactor_);
}
```

The drip model gets specified in the `RewardPoolConfig` struct when a config is passed during Rewards Manager deployment or update (see [Define Rewards Manager Configuration](/developer-guides/create-a-rewards-manager/define-a-rewards-manager-configuration)). Note the drip model can differ for each individual reward pool.

For details on how exactly rewards drip works, check [here](/developer-guides/rewards-manager-accounting#when-do-rewards-drip).

### Exponential-rate drip model

A default exponential-rate drip model implemented in [`DripModelExponential`](https://github.com/Cozy-Finance/cozy-safety-module-models/blob/main/src/DripModelExponential.sol).

The drip rate is a fixed number, `uint256 public immutable ratePerSecond`. In this model, rewards drip according to the exponential decay function `A = U * (1 - r)^t`, where:

* *U* is the starting amount of undripped rewards
* *A* is the remaining amount of undripped rewards after some number of seconds
* *t* is the number of elapsed seconds
* *r* is the per-second drip rate

From some simple math, we can compute the *r* value for a desired rate of drip.&#x20;

Suppose you want to drip 25% of rewards per year. You then make the following substitutions:

* U is `1`, or 100%, since we don't care what the actual starting value is, only what it decays to.
* *A* is `0.75` because the desired drip rate is 25%, and 100% reduced by 25% is 75%.
* *t* is `31557600`, the number of seconds in a year. The time period is arbitrary. We use a year only because our target rate is 25% drip *per year*.

This results in the following formula:

> 0.75 = 1 \* (1 - r ) ^ 31557600

We may now solve for *r* as follows:

> 0.75 = 1 \* (1 - r ) ^ 31557600\
> 0.75 = (1 - r ) ^ 31557600\
> 0.75 ^ (1 / 31557600) = 1 - r\
> 0.75 ^ (1 / 31557600) - 1 = - r\
> r = -((0.75 ^ (1 / 31557600)) - 1)\
> r = 0.000000009...

Finally, we can multiply *r* by a wad to get `ratePerSecond` is approximately `9e9`.

#### Deploying a exponential-rate drip model

If you would like to deploy the exponential-rate drip model and use it for reward pools in the Rewards Manager, you can use the dedicated [`DripModelExponentialFactory`](https://github.com/Cozy-Finance/cozy-safety-module-models/blob/main/src/DripModelExponentialFactory.sol).

To deploy the model, call the following function on that factory:

```solidity
/// @notice Deploys a DripModelExponential contract and emits a DeployedDripModelExponential event that
/// indicates what the params from the deployment are. This address is then cached inside the
/// isDeployed mapping.
/// @return model_ which has an address that is deterministic with the input ratePerSecond_.
function deployModel(uint256 ratePerSecond_) external returns (DripModelExponential model_);
```

Because the `deployModel` function is deterministic, it will revert if a model with your desired configurations already exists. To first confirm that your model needs to be deployed, you can call the `getModel` function with the same params you would pass to `deployModel`. The `getModel` function will return the address of the model that has your desired configs, if one exists.

The most up-to-date instructions on how to use the factory can be found in its [source code](https://github.com/Cozy-Finance/cozy-models-v2/blob/main/src/DripDecayModelConstantFactory.sol).

For the addresses of factories deployed to various chains, see our [contracts deployments registry](/developer-guides/contract-deployments-registry).


# Manage a Rewards Manager

* [Deposit Rewards](/developer-guides/manage-a-rewards-manager/deposit-rewards)
* [Update a Rewards Manager Configuration](/developer-guides/manage-a-rewards-manager/update-a-rewards-manager-configuration)


# Deposit Rewards

To incentivize stakers, users can deposit rewards into a Rewards Manager.&#x20;

## Using CozyRouter to deposit assets

Using the CozyRouter is the preferable way to deposit reward assets. To deposit assets using the CozyRouter, integrators can use `CozyRouter.depositRewardAssets`:

```solidity
/// @notice Deposits exactly `rewardAssetAmount_` of the reward pool's underlying tokens into the `rewardsManager_`.
/// The specified amount of assets are transferred from the caller to the `rewardsManager_`.
/// @dev This will revert if the router is not approved for at least `rewardAssetAmount_` of the reward pool's
/// underlying asset.
function depositRewardAssets(IRewardsManager rewardsManager_, uint16 rewardPoolId_, uint256 rewardAssetAmount_)
    external
    payable;
```

This method will:

* Transfer the underlying reward assets from the `msg.sender` to the Rewards Manager.
* Call `RewardsManager.depositRewardAssetsWithoutTransfer.`

\*\*Note that fee on transfer tokens are not supported.

Prior to calling this function, the user must have approved `CozyRouter` to a spend sufficient amount of their `RewardsManager.rewardPools(rewardId).asset` balance.

## Deposit mechanics

[`RewardsManager.depositRewardAssetsWithoutTransfer`](https://github.com/Cozy-Finance/cozy-safety-module-rewards-manager/blob/main/src/lib/Depositor.sol#L50) assumes that the assets to be deposited has already been transferred to the Rewards Manager. Any excess assets transferred will be kept by the Rewards Manager.&#x20;

On deposit, high-level the Rewards Manager does the following:

* Check if the Rewards Manager is `PAUSED`. If so, revert.
* Check the Rewards Manager's asset balance to determine if the total deposit amount was transferred. If not, revert.
* Update the relevant reward pool's internal `rewardPool.undrippedRewards` value.
* Emit a `Deposited` event.


# Withdraw Rewards

### Withdrawing rewards from a Rewards Manager

To allow depositors to reclaim unutilized incentives, the Rewards Manager supports withdrawals of undripped reward assets. A depositor can withdraw rewards they have previously contributed to a reward pool, provided those rewards have not yet dripped.

Depositors may call `RewardsManager.withdrawRewardAssets` directly:

```solidity
/// @notice Withdraw undripped reward assets.
/// @param rewardPoolId_ The ID of the reward pool to withdraw from.
/// @param rewardAssetAmount_ The amount of reward assets to withdraw.
/// @param receiver_ The address that will receive the withdrawn assets.
function withdrawRewardAssets(
  uint16 rewardPoolId_,
  uint256 rewardAssetAmount_,
  address receiver_
) external;
```

This method will:

1. **Preview withdrawable rewards**: Check the caller’s current withdrawable rewards using `_previewCurrentWithdrawableRewards`.
2. **Validate request**: Revert if `rewardAssetAmount_` exceeds the caller’s withdrawable rewards.
3. **Update accounting**: Reduce the caller’s `depositorRewards` balance and the pool’s `undrippedRewards` and asset totals.
4. **Transfer assets**: Send the specified reward assets to the `receiver_`.
5. **Emit event**: Log the withdrawal in a `Withdrawn` event.

To withdraw on behalf of another user, you may use `RewardsManager.withdrawRewardAssetsBySig`

```solidity
bytes32 public constant WITHDRAW_REWARD_ASSETS_BY_SIG_TYPEHASH = keccak256("WithdrawRewardAssetsBySig(address owner,uint16 rewardPoolId,uint256 rewardAssetAmount,address caller,address receiver,uint256 deadline,uint256 nonce)")

/// @notice Returns the domain separator.
function domainSeparator() external view returns (bytes32);

/// @notice Tracks per-owner nonces for EIP-712 signed operations.
/// @param owner_ the owner of this nonce
/// @param actionKey_ typehash used for this call (i.e. WITHDRAW_REWARD_ASSETS_BY_SIG_TYPEHASH)
function eip712Nonces(address owner_, bytes32 actionKey_) external view returns (uint256);

/// @notice Withdraw undripped reward assets on behalf of the owner via permit-style authorization.
/// @dev Signature binds to (owner, rewardPoolId, rewardAssetAmount, caller=msg.sender, receiver, deadline).
/// @param rewardPoolId_ The ID of the reward pool to withdraw from.
/// @param rewardAssetAmount_ The amount of reward assets to withdraw.
/// @param owner_ The owner of the reward assets.
/// @param receiver_ The address that will receive the withdrawn assets.
/// @param deadline_ The time at which the signature expires.
/// @param signature_ The owner's signature over the EIP-712 structured data.
function withdrawRewardAssetsBySig(
  uint16 rewardPoolId_,
  uint256 rewardAssetAmount_,
  address owner_,
  address receiver_,
  uint256 deadline_,
  bytes calldata signature_
) external {

  bytes32 digest_ = keccak256(
    abi.encodePacked(
      "\x19\x01",
      keccak256(
        abi.encode(
         domainSeparator()
        )
      ),
      keccak256(
        abi.encode(
          WITHDRAW_REWARD_ASSETS_BY_SIG_TYPEHASH,
          owner_,
          rewardPoolId_,
          rewardAssetAmount_,
          msg.sender,
          receiver_,
          deadline_,
          nonce_
        )
      )
    )
  );

  if (!SignatureChecker.isValidSignatureNow(owner_, digest_, signature_)) revert InvalidSignature();
}
```

* The owner must sign a digest that matches the above.
* Fetch Domain Separator via external `domainSeparator()` getter and nonce via external `eip712Nonces(owner, actionKey)`(actionKey is the relevant typehash) getter. Both are exposed in IRewardsManager. &#x20;
* The above `withdrawRewardAssetsBySig` function is truncated to only show the relevant structure of the digest.&#x20;

***

Before withdrawing, users may use `previewCurrentWithdrawableRewards` to determine how many rewards a depositor is eligible to withdraw:

```solidity
/// @notice Preview the current withdrawable rewards for the depositor.
/// @param rewardPoolId_ The ID of the reward pool.
/// @param depositor_ The address of the depositor.
/// @return The depositor's current withdrawable rewards.
function previewCurrentWithdrawableRewards(
  uint16 rewardPoolId_,
  address depositor_
) external view returns (uint256);
```

This function accounts for:

* **Epoch changes**: If the depositor’s rewards belong to an expired epoch, withdrawable rewards are set to 0.
* **Drip updates**: If rewards have dripped since the last update, withdrawable rewards are scaled down accordingly.
* **Stable snapshots**: If no drip has occurred since the depositor’s last update, withdrawable rewards remain unchanged.


# Update a Rewards Manager Configuration

As the `owner` of a Rewards Manager, it is possible to update the configuration in order to:

* Add new stake pools
* Add new reward pools
* Update rewards weights
* Update drip models

To update the configs, the relevant call is `RewardsManager.updateConfigs`:

```solidity
function updateConfigs(StakePoolConfig[] calldata stakePoolConfigs_, RewardPoolConfig[] calldata rewardPoolConfigs_)
    external
    onlyOwner;
```

The stake and reward pool configs for the update must obey the general requirements for creating a Rewards Manager (see [Define Rewards Manager Configuration](/developer-guides/create-a-rewards-manager/define-a-rewards-manager-configuration)) with a few caveats:

* It is not possible to remove stake pools, so existing stake pools must be included at the start of the `StakePoolConfig[]` sorted by the associated stake pool IDs. Any new stake pools come after the existing stake pools and must be sorted by the address of the underlying asset and not contain duplicates.
* It is not possible to remove reward pools, so the existing reward pools must be included at the start of the `RewardPoolConfig[]` sorted by the associated reward pool IDs.

Note before a config update is applied, rewards are dripped and cumulative rewards values for all `RewardPool` and `ClaimableRewardsData` structs in storage are reset to 0. For an in-depth explanation why, see [here](/developer-guides/rewards-manager-accounting#config-updates-and-claimable-rewards).


# Stake into a Rewards Manager

* [Stake](/developer-guides/stake-into-a-rewards-manager/stake)
* [Claim Rewards](/developer-guides/stake-into-a-rewards-manager/claim-rewards)
* [Unstake](/developer-guides/stake-into-a-rewards-manager/unstake)


# Stake

Staking into a Rewards Manager, provides users with the opportunity to earn rewards. Different stake pools will have a different underlying stake asset and provide a different reward profile.

Stakers receive receipt tokens, which can be used to claim rewards.

### Using CozyRouter to stake assets

The recommended way to programmatically stake assets is to call `CozyRouter.stake` (see [CozyRouter](broken://pages/z3zOxW6ojdnY9n2NEfch)):

```solidity
function stake(IRewardsManager rewardsManager_, uint16 stakePoolId_, uint256 stakeAssetAmount_, address receiver_)
    external
    payable
    returns (uint256 stakeReceiptTokenAmount_);
```

This method will:

* Transfer the underlying stake assets from the `msg.sender` to the Rewards Manager.
* Internally call `RewardsManager.stakeWithoutTransfer.`&#x20;

Prior to calling this function, the user must have approved `CozyRouter` to a spend sufficient amount of their `StakePool.asset` balance.

### Stake mechanics

`RewardsManager.stakeWithoutTransfer` assumes that the assets to be stakes have already been transferred to the Rewards Manager. Any excess assets transferred will be kept by the Rewards Manager.&#x20;

On stake, we follow the following steps:

* Check it the Rewards Manager is `PAUSED`. If so, revert.
* Check the Rewards Manager's asset balance to determine if the stake amount was transferred. If not, revert.
* Update the `StakePool.amount` value.
* Drip and apply any pending rewards to get `claimableRewards[stakePoolId_]` up to date.
* Update `userRewards[stakePoolId_][receiver_]`.
* Mint the `receiver_` address stake receipt tokens.
* Emit a `Staked` event.


# Claim Rewards

To claim rewards, a staker can call `RewardsManager.claimRewards`&#x20;

```solidity
// Used to track which reward pool to claim from and whether to drip from the reward pool.
struct ClaimRewardsPoolData {
  uint16 rewardPoolId;
  bool drip;
}
  
/// @notice Claim rewards for a specific stake pool and all reward pools and transfer rewards to `receiver_`.
/// @dev Note that this function drips all reward pools. If you want to claim without dripping from specific reward
/// pools, you can use one of the claimRewards functions that accepts `ClaimRewardsPoolData[] calldata
/// claimRewardsPoolData_` as an arg.
/// @param stakePoolId_ The ID of the stake pool to claim rewards for.
/// @param receiver_ The address to transfer the claimed rewards to.
function claimRewards(uint16 stakePoolId_, address receiver_) external;

/// @notice Claim rewards for a set of stake pools and all reward pools and transfer rewards to `receiver_`.
/// @dev Note that this function drips all reward pools. If you want to claim without dripping from specific reward
/// pools, you can use one of the claimRewards functions that accepts `ClaimRewardsPoolData[] calldata
/// claimRewardsPoolData_` as an arg.
/// @param stakePoolIds_ The IDs of the stake pools to claim rewards for.
/// @param receiver_ The address to transfer the claimed rewards to.
function claimRewards(uint16[] calldata stakePoolIds_, address receiver_) external;

/// @notice Claim rewards for a specific stake pool and set of reward pools and transfer rewards to `receiver_`.
/// @dev Note that this function only drips and claims rewards for the reward pools specified in
/// `claimRewardsPoolData_`. If a reward pool is omitted from `claimRewardsPoolData_`, then no rewards will be dripped
/// or claimed for that reward pool. If drip is false, then no rewards will be dripped for that reward pool, but
/// rewards will still be claimed.
/// @dev The `claimRewardsPoolData_` must contain only valid reward pool IDs and no duplicates.
/// @param stakePoolId_ The ID of the stake pool to claim rewards for.
/// @param claimRewardsPoolData_ The reward pool IDs and whether to drip or not.
/// @param receiver_ The address to transfer the claimed rewards to.
function claimRewards(uint16 stakePoolId_, ClaimRewardsPoolData[] calldata claimRewardsPoolData_, address receiver_) external;
    
/// @notice Claim rewards for a specific set of stake pools and set of reward pools and transfer rewards to
/// `receiver_`.
/// @dev Note that this function only drips and claims rewards for the reward pools specified in
/// `claimRewardsPoolData_`. If a reward pool is omitted from `claimRewardsPoolData_`, then no rewards will be dripped
/// or claimed for that reward pool. If drip is false, then no rewards will be dripped for that reward pool, but
/// rewards will still be claimed.
/// @dev The `claimRewardsPoolData_` must contain only valid reward pool IDs and no duplicates.
/// @param stakePoolIds_ The IDs of the stake pools to claim rewards for.
/// @param claimRewardsPoolData_ The reward pool IDs and whether to drip or not.
/// @param receiver_ The address to transfer the claimed rewards to.
function claimRewards(
    uint16[] calldata stakePoolIds_,
    ClaimRewardsPoolData[] calldata claimRewardsPoolData_,
    address receiver_
 ) external;
```

There are 4 variations of the function that allow you to specify which stake pools you want to claim rewards for and which reward pools you want to drip and claim from. Accrued rewards are sent to the  `receiver_` address.

### Claim rewards mechanics

On claiming rewards, we follow the following steps for each reward pool:

* Drip from the reward pool since time may have passed since the last drip.
* Compute and update the `ClaimableRewardsData` for the (stake pool, reward pool) pair.
* Update the `UserRewardsData` for the (stake pool, reward pool) pair.
* Transfer the user's `accruedRewards` from the reward pool to the `receiver_.`
* Reset `accruedRewards` to 0.
* Emit a `ClaimedRewards` event.

To claim rewards on behalf of another user, you may use `RewardsManager.claimRewardsBySig`

<pre class="language-solidity"><code class="lang-solidity">/// @notice Returns the domain separator.
function domainSeparator() external view returns (bytes32);

/// @notice Tracks per-owner nonces for EIP-712 signed operations.
/// @param owner_ the owner of this nonce
/// @param actionKey_ typehash used for this call (i.e. CLAIM_REWARDS_BY_SIG_ALL_POOLS_TYPEHASH)
function eip712Nonces(address owner_, bytes32 actionKey_) external view returns (uint256);

function hashStakePoolIds(uint16[] calldata stakePoolIds_) external pure returns (bytes32);
<strong>
</strong><strong>bytes32 public constant CLAIM_REWARDS_BY_SIG_ALL_POOLS_TYPEHASH = keccak256("ClaimRewardsBySig(uint16[] stakePoolIds,address owner,address caller,address receiver,uint256 deadline,uint256 nonce)")
</strong>
/// @notice Claim rewards for a set of stake pools on behalf of owner_ and transfer rewards to receiver_.
/// @dev This variant claims and drips all reward pools. Signature binds to (stakePoolIds, owner, caller=msg.sender, receiver, deadline, nonce).
/// @param stakePoolIds_ The IDs of the stake pools to claim rewards for.
/// @param owner_ The address whose rewards are being claimed.
/// @param receiver_ The address to receive the claimed rewards.
/// @param deadline_ The time after which the signature is no longer valid.
/// @param signature_ The owner's signature over the EIP-712 structured data.
function claimRewardsBySig(
  uint16[] calldata stakePoolIds_,
  address owner_,
  address receiver_,
  uint256 deadline_,
  bytes calldata signature_
) external;

bytes32 digest_ = keccak256(
  abi.encodePacked(
    "\x19\x01",
    keccak256(
      abi.encode(domainSeparator)
    ),
    keccak256(
      abi.encode(
          CLAIM_REWARDS_BY_SIG_ALL_POOLS_TYPEHASH,
          hashStakePoolIds(stakePoolIds),
          owner_,
          msg.sender,
          receiver_,
          deadline_,
          nonce_
      )
    )
  )
);

if (!SignatureChecker.isValidSignatureNow(owner_, digest_, signature_)) revert InvalidSignature();
}

function _hashStakePoolIds(uint16[] calldata stakePoolIds_) internal pure returns (bytes32) {
  // Encode each stake pool id as a full 32-byte word to satisfy EIP-712 array hashing semantics.
  uint256 stakePoolCount_ = stakePoolIds_.length;
  bytes32[] memory stakePoolIdsEncoded_ = new bytes32[](stakePoolCount_);
  for (uint256 i = 0; i &#x3C; stakePoolCount_; i++) {
    stakePoolIdsEncoded_[i] = bytes32(uint256(stakePoolIds_[i]));
  }
  return keccak256(abi.encodePacked(stakePoolIdsEncoded_));
}
</code></pre>

* The owner must sign a digest that matches the above.
* Fetch Domain Separator via external `domainSeparator()` getter and nonce via external `eip712Nonces(owner, actionKey)`(actionKey is the relevant typehash) getter. Both are exposed in IRewardsManager. &#x20;
* The above `claimRewardsBySig` function is truncated to only show the relevant structure of the digest. `hashStakePoolIds` is a public exposed function that encodes each stakePoolId as a 32-byte word before hashing to satisfy EIP-712 array semantics.

To specify which reward pools to drip and claim from, you can use a similar `claimRewardsBySig` function with a slightly different set of typehashes and an additional claimRewardsPoolData\_ arg in the signature. Its important that the signature has structured the data correctly before hashing to satisfy EIP-712 semantics. `hashStakePoolIds` and `hashClaimRewardsPoolData` are public exposed functions on IRewardsManager that can help you construct this part of the signature.&#x20;

```solidity

function hashStakePoolIds(uint16[] calldata stakePoolIds_) external pure returns (bytes32);

function hashClaimRewardsPoolData(ClaimRewardsPoolData[] calldata claimRewardsPoolData_)
  external
  pure
  returns (bytes32);
  
bytes32 public constant CLAIM_REWARDS_POOL_DATA_TYPEHASH =
  keccak256("ClaimRewardsPoolData(uint16 rewardPoolId,bool drip)");

bytes32 public constant CLAIM_REWARDS_BY_SIG_SELECTED_POOLS_TYPEHASH = keccak256(
  "ClaimRewardsBySig(uint16[] stakePoolIds,ClaimRewardsPoolData[] claimRewardsPoolData,address owner,address caller,address receiver,uint256 deadline,uint256 nonce)ClaimRewardsPoolData(uint16 rewardPoolId,bool drip)"
);

/// @notice Claim rewards for a set of stake pools on behalf of `owner_`, authorized by signature.
/// @dev This variant claims and drips specified reward pools.
/// @param stakePoolIds_ The IDs of the stake pools to claim rewards for.
/// @param claimRewardsPoolData_ The reward pool IDs and whether to drip before claiming each one.
/// @param owner_ The address whose rewards are being claimed.
/// @param receiver_ The address to receive the claimed rewards.
/// @param deadline_ The time after which the signature is no longer valid.
/// @param signature_ The owner's signature over the EIP-712 structured data.
function claimRewardsBySig(
  uint16[] calldata stakePoolIds_,
  ClaimRewardsPoolData[] calldata claimRewardsPoolData_,
  address owner_,
  address receiver_,
  uint256 deadline_,
  bytes calldata signature_
) external;

bytes32 digest_ = keccak256(
  abi.encodePacked(
    "\x19\x01",
    keccak256(
      abi.encode(domainSeparator)
    ),
    keccak256(
      abi.encode(
          CLAIM_REWARDS_BY_SIG_SELECTED_POOLS_TYPEHASH,
          hashStakePoolIds(stakePoolIds),
          _hashClaimRewardsPoolData(claimRewardsPoolData_)
          owner_,
          msg.sender,
          receiver_,
          deadline_,
          nonce_
      )
    )
  )
);

if (!SignatureChecker.isValidSignatureNow(owner_, digest_, signature_)) revert InvalidSignature();
}

function _hashStakePoolIds(uint16[] calldata stakePoolIds_) internal pure returns (bytes32) {
  // Encode each stake pool id as a full 32-byte word to satisfy EIP-712 array hashing semantics.
  uint256 stakePoolCount_ = stakePoolIds_.length;
  bytes32[] memory stakePoolIdsEncoded_ = new bytes32[](stakePoolCount_);
  for (uint256 i = 0; i < stakePoolCount_; i++) {
    stakePoolIdsEncoded_[i] = bytes32(uint256(stakePoolIds_[i]));
  }
  return keccak256(abi.encodePacked(stakePoolIdsEncoded_));
}


function _hashClaimRewardsPoolData(ClaimRewardsPoolData[] calldata claimRewardsPoolData_)
  internal
  pure
  returns (bytes32)
{
  uint256 length_ = claimRewardsPoolData_.length;
  if (length_ == 0) return keccak256("");

  bytes32[] memory elementHashes_ = new bytes32[](length_);
  for (uint256 i = 0; i < length_; i++) {
    elementHashes_[i] = keccak256(
      abi.encode(
        CLAIM_REWARDS_POOL_DATA_TYPEHASH, claimRewardsPoolData_[i].rewardPoolId, claimRewardsPoolData_[i].drip
      )
    );
  }

  return keccak256(abi.encodePacked(elementHashes_));
}
```


# Unstake

Stakers can exchange their stake receipt tokens for the underlying asset they staked in the Rewards Manager (typically a Safety Module deposit receipt token). There is no delay to unstake - stakers can immediately unstake from a Rewards Manager.

### Using CozyRouter to unstake assets

The recommended way to programmatically unstake assets is to call `CozyRouter.unstake` (see CozyRouter):

```solidity
function unstake(
    IRewardsManager rewardsManager_,
    uint16 stakePoolId_,
    uint256 stakeReceiptTokenAmount,
    address receiver_
) public payable;
```

This method will internally call`RewardsManager.unstake`.

Prior to calling this function, the user must have approved `CozyRouter` to a spend sufficient amount of their `StakePool.stakeReceiptToken` balance.

### Unstake mechanics

On `RewardsManager.unstake`, we follow the following steps:

* Claim rewards on behalf of the `owner_`, transferring the reward assets to `receiver_`.
* Decrement `StakePool.amount`.
* Burn the `owner_`'s stake receipt tokens.
* Transfer the `receiver_` the relevant amount of stake assets.
* Emit a `Unstaked` event.


# Rewards Manager Accounting

The graphic below provides a useful mental model of how rewards accounting works.

Conceptually, rewards flow from the `RewardPool` struct, to `ClaimableRewardsData` structs (one for each stake pool), to `UserRewardsData` (one for each staker in a stake pool).

<figure><img src="/files/PFeh6vc2xy48FqjWqgSW" alt="" width="563"><figcaption></figcaption></figure>

### Reward Pools and Drip

The `RewardPool` struct stores undripped rewards and cumulative dripped rewards. At this stage, there is no concept of stake pools or stakers.&#x20;

```solidity
struct RewardPool {
  // The amount of undripped rewards held by the reward pool.
  uint256 undrippedRewards;
  // The cumulative amount of rewards dripped since the last config update. This value is reset to 0 on each config
  // update.
  uint256 cumulativeDrippedRewards;
  // The last time undripped rewards were dripped from the reward pool.
  uint128 lastDripTime;
  ...
}
```

#### When do rewards drip?

Rewards can either drip simultaneously for all reward pools or for a single reward pool.&#x20;

Many operations in the Rewards Manager internally drip rewards. However, anyone can drip rewards on-demand by calling `RewardsManager.dripRewards` and `RewardsManager.dripRewardPool`, which are also public and external functions, respectively.

The following operations internally drip rewards for all reward pools:

* `RewardsManager.pause`
* `RewardsManager.unpause`
* `RewardsManager.claimRewards`
* `RewardsManager.updateConfigs`
* `RewardsManager.dripRewards`
* `RewardsManager.stake`
* `RewardsManager.stakeWithoutTransfer`

The following operations internally drip rewards for a single reward pool:

* `RewardsManager.deposit`
* `RewardsManager.depositWithoutTransfer`
* `RewardsManager.dripRewardPool`

#### How exactly does drip work?

The core drip functionality is implemented in `RewardsManager._dripRewardPool`. When a reward pool drips, the following happens:

* `undrippedRewards` gets decremented by the amount of dripped rewards.
* `cumulativeDrippedRewards` gets incremented by that same amount of dripped rewards.
* `lastDripTime` updates to `block.timestamp`.

The amount of dripped rewards is simply:

<pre><code><strong>dripFactor = dripModel.dripFactor(lastDripTime);
</strong><strong>drippedRewards = dripFactor * rewardPool.undrippedRewards;
</strong></code></pre>

### Claimable Rewards

The `claimableRewards` storage variable is a nested mapping which maps stake pool IDs to reward pool IDs to a `ClaimableRewardsData` struct.&#x20;

Each `ClaimableRewardsData` struct is used to track the claimable rewards associated with a given (stake pool, reward pool) pair.

```solidity
struct ClaimableRewardsData {
  // The cumulative amount of rewards that are claimable on behalf of all users. This value is reset to 0 on each
  // config update.
  uint256 cumulativeClaimableRewards;
  // The index snapshot the relevant claimable rewards data, when the cumulative claimed rewards were updated. The index
  // snapshot must update each time the cumulative claimed rewards are updated.
  uint256 indexSnapshot;
}
```

#### When do claimable rewards get updated?

The following operations trigger an update to `claimableRewards`:

* `RewardsManager.claimRewards` -> `_claimRewards`
* `RewardsManager.stake` and `RewardsManager.stakeWithoutTransfer` -> `_dripAndApplyPendingDrippedRewards`
* `RewardsManager.unstake` -> `_claimRewards`
* `RewardsManger.updateConfigs` -> `_dripAndResetCumulativeRewardsValues`

#### How exactly do claimable rewards work?

The `claimableRewards` variable is lazily updated, which obviates the need to iterate through all (stake pool, reward pool) pairs when unnecessary.

The `cumulativeClaimableRewards` value is the amount of `RewardPool.cumulativeDrippedRewards` which are now fully "claimable" by stakers in a specific stake pool. Since it is lazily updated, it is a lagging value. Specifically, we have the following invariant always holds:

```
claimableRewards[stakePoolId][rewardPoolId].cumulativeClaimableRewards <=
    rewardPools[rewardPoolId].cumulativeDrippedRewards.mulDivDown(stakePools[stakePoolId].rewardsWeight, ZOC)
```

Each time `cumulativeClaimableRewards` is updated, it is brought in sync with the right-hand side of the inequality above.

Each time `cumulativeClaimableRewards` is updated, so is `indexSnapshot`. The `indexSnapshot` value represents the accrued rewards of a theoretical staker who owns a single `stkReceiptToken` and began staking at initialization of the stake pool.&#x20;

Say `cumulativeClaimableRewards` is incremented by `x`. Then:

```
indexSnapshot += x.divWadDown(stakePools[stakePoolId].stkReceiptToken.totalSupply())
```

### User Rewards

The `userRewards` storage variable is a nested mapping which maps stake pool IDs to staker addresses to an array of `UserRewardsData` structs. Each `UserRewardsData` struct is used to track the rewards a staker is entitled to for a given reward pool.

```solidity
struct UserRewardsData {
  // The total amount of rewards accrued by the user.
  uint256 accruedRewards;
  // The index snapshot the relevant claimable rewards data, when the user's accrued rewards were updated. The index
  // snapshot must update each time the user's accrued rewards are updated.
  uint256 indexSnapshot;
}
```

#### When do user rewards get updated?

Any operation which updates a user's `stkReceiptToken` balance or claims some of the user's accrued rewards triggers an update to `userRewards`:

* `RewardsManager.claimRewards` -> `_claimRewards`
* `RewardsManager.stake` and `RewardsManager.stakeWithoutTransfer` -> `_updateUserRewards`
* `RewardsManager.unstake` -> `_claimRewards`
* `StkReceiptToken.transfer` -> `_updateUserRewardsForStkReceiptTokenTransfer`

#### How exactly do user rewards work?

Much like claimable rewards, `accruedRewards` is lazily updated since it is impossible to iterate through all stakers in a given stake pool.

Each time a user's `stkReceiptToken` balance changes, `accruedRewards` are updated as follows:

<pre><code><strong>oldRewardPoolIndex = userRewards[stakePoolId][staker][rewardPoolId].indexSnapshot
</strong><strong>newRewardPoolIndex = claimableRewards[stakePoolId][rewardPoolId].indexSnapshot
</strong><strong>accruedRewards += stakerReceiptTokenBalance.mulWadDown(newRewardPoolIndex - oldRewardPoolIndex);
</strong></code></pre>

The special case is when the rewards are claimed. In that case, `accuredRewards` is set to 0.

Whenever `accruedRewards` is updated, the user rewards `indexSnapshot` is also brought in sync with the claimable rewards `indexSnapshot`.

Since new reward pools can be added after a user has staked, it is possible that `userRewards[stakePoolId][staker].length <= rewardPools.length`. In that case, there is special handling to push a new `UserRewardsData` struct.

### Config Updates and Claimable Rewards

Recall that the claimable rewards accounting crucially depends on an [invariant](#how-exactly-do-claimable-rewards-work), which uses the `StakePool.rewardsWeight`.&#x20;

It is possible that a Rewards Manager config update changes these weights and the invariant no longer holds. So, before any config update is applied, all claimable rewards data is fully reset. More specifically:

* All reward pools are dripped.
* `ClaimableRewardsData.indexSnapshot` is fully updated for all (stake pool, reward pool) pairs.
* `RewardPool.cumulativeDrippedRewards` is reset to 0.
* `ClaimableRewardsData.cumulativeClaimedRewards` is reset to 0.

By resetting the cumulative rewards values to 0, we can use the invariant again to do accounting until there is another config update.&#x20;

### StkReceiptToken Transfers

Stake receipt token transfers change user balances and so must get reflected in the Rewards Manager's user rewards accounting.

Prior to the standard `IERC20.transfer` call, `stkReceiptToken`s call `RewardsManager.updateUserRewardsForStkReceiptTokenTransfer`. This function  brings the `UserRewardsData` for both the `to` and `from` address up to date, so rewards accrue properly after the transfer occurs.


# Rewards Manager States

The Rewards Manager can be in two states:

```solidity
enum RewardsManagerState {
  ACTIVE,
  PAUSED
}
```

The table below details which actions are allowed in each of these states:

<table><thead><tr><th width="230">Action / State</th><th>Active</th><th>Paused</th></tr></thead><tbody><tr><td><strong>Deposit Rewards</strong></td><td>Y</td><td>N</td></tr><tr><td><strong>Claim Rewards</strong></td><td>Y</td><td>Y</td></tr><tr><td><strong>Drip Rewards</strong></td><td>Y</td><td>N</td></tr><tr><td><strong>Stake</strong></td><td>Y</td><td>N</td></tr><tr><td><strong>Unstake</strong></td><td>Y</td><td>Y</td></tr><tr><td><strong>Update Configs</strong></td><td>Y</td><td>Y</td></tr><tr><td><strong>Pause</strong></td><td>Y</td><td>N</td></tr><tr><td><strong>Unpause</strong></td><td>N</td><td>Y</td></tr></tbody></table>

Although calling `RewardsManager.dripRewards` or `RewardsManager.dripRewardPool` revert when `PAUSED`, certain actions which drip rewards internally (such as claiming rewards) are still possible when `PAUSED`. These actions will just skip the internal rewards drip unless the Rewards Manager is `ACTIVE`.


# Create a Controller

Controllers are smart contracts that contain logic which can be used by Safety Modules to determine when to allow assets to be tapped.&#x20;

Controller factories provide an easy way to create new controller contracts programmatically, without the need to implement any custom controller logic. The following controller factories exist:

* [Ownable Controller Factory](/developer-guides/create-a-controller/ownable-controller-factory)


# Ownable Controller Factory

The `OwnableControllerFactory` deploys controllers that can be used to trigger the safety module.

### Determine Controller Parameters

<pre class="language-solidity"><code class="lang-solidity">struct ControllerMetadata {
  // The name that should be used for SafetyModules that use the controller
  string name;
  // A human-readable description of the controller.
  string description;
  // The URI of a logo image to represent the controller.
  string logoURI;
  // Any extra data that should be included in the controller's metadata.
  string extraData;
}
<strong>
</strong><strong>/// @notice Deploys a new OwnableController contract with the supplied owner and deploy salt.
</strong>/// @param _owner The owner of the controller.
/// @param _metadata The metadata of the controller.
/// @param _salt Used during deployment to compute the address of the new OwnableController.
  function deployController(address _owner, ControllerMetadata memory _metadata, bytes32 _salt)
    external
    returns (ISafetyModuleController _controller);
</code></pre>


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


# Permissions and Authorization

## Cozy Safety Module

There are two Cozy Safety Module protocol-wide authorized addresses - the `owner` and the `pauser`, both of which are defined on the `CozySafetyModuleManager`.&#x20;

The `owner` is allowed to:

* claim protocol fees
* pause/unpause Safety Modules
* update fee drip models
* update the `owner` and `pauser`

The `pauser` is allowed to:

* pause Safety Modules
* update the `pauser`

## Cozy Rewards Manager

There are two Cozy Rewards Manager protocol-wide authorized addresses - the `owner` and the `pauser`, both of which are defined on the `CozyManager` for the Cozy Rewards Manager protocol.&#x20;

The `owner` is allowed to:

* pause/unpause Rewards Managers
* update the `owner` and `pauser`

The `pauser` is allowed to:

* pause Rewards Managers
* update the `pauser`


# Token Integration Guidelines

<table><thead><tr><th width="374.66666666666663">Attribute</th><th>Compatibility</th><th>Explanation</th></tr></thead><tbody><tr><td>Optionality of decimals</td><td>Not compatible</td><td>The existence of the <code>decimals()</code> function is not a hard requirement for ERC20 tokens, but SafetyModules and RewardsManagers require assets to have decimals.</td></tr><tr><td>Rebasing balances</td><td>Not compatible</td><td>SafetyModules and RewardsManagers make heavy use of internal accounting and thus cannot support rebase tokens.</td></tr><tr><td>Fee on transfer</td><td>Not Compatible</td><td>SafetyModules and RewardsManagers support multiple tokens and make heavy use of internal accounting and thus cannot support fee on transfer tokens.</td></tr><tr><td>Tokens with callbacks</td><td>Not Compatible</td><td>SafetyModules and RewardsManagers support multiple tokens and make heavy use of internal accounting and thus cannot support tokens with callbacks.</td></tr><tr><td>Low to no decimals</td><td>Issues possible</td><td>The use of assets with a low number of decimals, or decimals of 0, might indicate that small numbers of the token (eg. 1 wei) are of substantial value. If that is the case, users of SafetyModules and RewardsManagers may experience loss due to rounding down in the protocol logic.</td></tr><tr><td>High decimals</td><td>Issues possible</td><td>The use of assets with a high number of decimals might indicate that a large integer is necessary to represent any significant value. If that is the case, note that SafetyModules and RewardsManagers internal accounting uses <code>uint256</code>, restricting the maximum possible number of tokens that can be stored to <code>type(uint256).max</code>.</td></tr><tr><td>Forced transfer</td><td>Issues possible</td><td>If the admins in control of the asset can be trusted, it should be reasonable to integrate tokens even if there exists the possibility of a forced transfer (ie. admins can forcefully move anyone's balance). When SafetyModule and RewardsManager assets are forcefully removed however, they will become insolvent.</td></tr><tr><td>Uncommon decimals type</td><td>Issues possible</td><td>SafetyModules and RewardsManagers assume that the number returned by <code>decimals()</code> fits into a <code>uint8</code>.</td></tr><tr><td>Token without success bools</td><td>Compatible</td><td>While the ERC20 standards requires a token's functions to return booleans to represent whether an action succeeded or not, many do not follow this standard. The protocol supports tokens that do not return such booleans (ie. usage of OpenZeppelin's SafeERC).</td></tr><tr><td>Blocklist</td><td>Compatible</td><td>The protocol's SafetyModule and RewardsManager smart contracts hold user's assets in custody. Assuming that a SafetyModule/RewardsManager contract itself is not added to a blocklist (ie. disabling transfers from the address), there's no issue. Even if any of the protocol's users are added to the asset's blocklist, they may simply specify a new address as <code>receiver_</code> to bypass this.</td></tr><tr><td>Pausable</td><td>Compatible</td><td>While an asset is paused (ie. all transfers are disabled), all protocol interactions requiring the movement of funds are unavailable, except for redemptions. Everything else will continue to work as intended within a SafetyModule/RewardsManager internal accounting.</td></tr><tr><td>Multiple token addresses</td><td>Compatible</td><td>Tokens that have multiple addresses (also called Double-Entry-Tokens) do not appear to be able to cause any issues with the protocol. The SafetyModule/RewardsManager exclusively uses the address that was specified as the asset (ie. there's no sweeping or rescuing function interacting with other token addresses).</td></tr><tr><td>Limited amount size</td><td>Compatible</td><td>Some ERC20 tokens appear to allow transferring full integers (ie. <code>uint256</code>) but will in practice revert when a large transfer amount is specified. Thanks to the fact that all interactions involving token transfers with SafetyModule/RewardsManager can be split into multiple calls (resulting in the same effect as a single call with a larger amount) this should not be an issue.</td></tr></tbody></table>


# Contract Deployments Registry

## Ethereum Mainnet

### Core Protocol

TimelockController (protocol owner): `0x20Fd25c19964acE1971682D0Ed4E2aD719dD014f`

CozySafetyModuleManager: `0x4f993ab56e71b4bf7f784ce5c4ead11ef08d7759`

CozyRewardsManager: `0x425640a11f1a3f541eb985b89fc45da3a37d28df`

SafetyModuleFactory: `0x97d2510f057d261528dab86e0ef8d5881f8c3843`

RewardsManagerFactory: `0x8e6b294d9e342179c1556612e7a04048ae74e5c2`

SafetyModule logic: `0x527d9a8c6fc52480be66d683011c250331e34e5e`

RewardsManager logic: `0x6f4b2b57f7c7bf7e263f8be1b0c5cb85e9205bc0`

StkReceiptToken: `0x2f3e76428b1c307ae41bbd270726cee9a3cc7a8d`

ReceiptToken: `0xa3919739bf446e8b873b74f5a4e0fcfd4494567d`

ReceiptTokenFactory: `0x7b83a82681e895dd19075f4adff05339dfd97051`

CozyRouter: `0x640c73692320ed0758a9838bb17298ee38920726`

### Controller Factories

OwnableControllerFactory: `0x7d8514219Fb7b2b2119b46C1d57Ca5bc0BF5836E`

UMAControllerFactory: `0xe6e40ad4815097ba3d92b6a67ee747750c323e08`

### Raise Strategies

BasicRaiseStrategy: `0x415da7d703c336AAF82e7D9BD44f17EFf9Ec3d13`

### Model Factories

DripModelConstantFactory: `0x91ce3417da8f3b6fe78a6dd400ba308212bb7fba`

DripModelExponentialFactory: `0x6d158877f368da51629c2121f6fe6a447dea14a3`

### Metadata Registry

MetadataRegistry: `0x53ab303ef6f06694580e3351f12b76361e2fa6bd`

### Euler Vault Integration Contracts

CozyLiquidatorManager: `0xa97F85150693b5DccDb29650bcf78aDC75C96ddE`

CozyLiquidator logic: `0x3B8B3977c432ed00045E7c582d1d71C3999707A7`

CozyLiquidatorFactory: `0x1b2e4ac452c386877dE921dcb30Df75D6a5499b7`

CozyLiquidationHandler: `0x22893aB491Bed3827bcBEFCf5dCd68492227d56d`

EulerTrancheRaiseStrategy: `0xf68406D6Cd41a5a3C5c4b9F0aDd41A3e789C138c`


# Payout Vaults

A Payout Vault is a way to manage distributions of slashed Safety Module assets to a set of addresses via an off-chain Merkle tree.

## Deploying a Payout Vault

The PayoutVaultFactory's `deployPayoutVault` function can be used to deploy a Payout Vault:

```solidity
function deployPayoutVault(address owner_, IERC20[] calldata assets_, bytes32 baseSalt_)
    external
    returns (IPayoutVault payoutVault_)
```

The `owner_` is the manager of the Payout Vault that will be responsible for registering new payout assets, setting the Merkle tree root, and withdrawing assets once payouts have been processed.

The `assets_` argument is a list of registered assets (see [below](#registering-assets) for more details).

## Managing a Payout Vault

### Registering Assets

All assets that will eventually be distributed need to be registered with the Payout Vault. In most cases, these assets are simply a Safety Module's reserve assets. The owner can register new assets by calling `PayoutVault.registerPayoutAssets`.

### Merkle Tree and Setting the Root

Each address claiming payout assets is entitled to a `claimableShare` of each registered asset's balance in the Payout Vault (represented as a WAD, so 50% is 0.5e18).

It is assumed an off-chain Merkle tree of all eligible addresses has been computed, where each leaf represents a single eligible user encoded as:

```solidity
bytes32 leaf = 
    keccak256(bytes.concat(keccak256(abi.encode(userAddress, claimableShare))));
```

To set the Merkle tree root, the owner can call `PayoutVault.setRoot`.

### Setting Claims Deadline

The owner also sets a deadline by which all users must claim by calling `PayoutVault.setClaimsDeadline`.

### Initializing Claims

The preferred way to initialize claims is by the owner calling:

```solidity
function initializeClaims(bytes32 root_, uint256 claimsDeadline_) external onlyOwner;
```

Note that this call sets the Merkle root and the claims deadline. It also takes a snapshot of the PayoutVault's balances of all registered assets. These balances are the total amounts of each asset that are eventually paid out to users.

### Withdrawing Assets

Once the `PayoutVault.claimsDeadline` has passed, the owner can withdraw any remaining assets in the vault by calling `PayoutVault.withdraw`.

### Pause

In case of an emergency, the owner can also pause claims, by calling `PayoutVault.pause`.

## Claiming Payouts

An address that wishes to claim payouts from the vault must call:

```solidity
function claim(bytes32[] calldata proof_, uint256 claimableShare_) external;
```

where `proof_` is the appropriate Merkle tree proof and `claimableShare_` is that address's appropriate share of the vault assets. It is assumed that an off-chain service will help users generate these values for them given the Merkle tree.

Payouts must be claimed by the `PayoutVault.claimsDeadline` or they may be withdrawn.


# Security FAQ

Is the protocol audited?

Cozy Safety Module, Cozy Rewards Manager & Euler Integration contracts have been audited several times. See [here](https://www.notion.so/cozyfinance/Audits-2cc44b4e9a2080ea9d8ec959c45bface) for details.&#x20;


