# 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](https://csm-docs.cozy.finance/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](https://csm-docs.cozy.finance/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](https://csm-docs.cozy.finance/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](https://csm-docs.cozy.finance/creating-a-safety-module/define-safety-module-configuration#reserve-pool-maximum-slash-percentages)).
  * Assets pending withdrawal are also tapped (see [Safety Module Redemptions / Withdrawals](https://csm-docs.cozy.finance/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.
