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).
/// @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_RAISEsafetyModule.numPendingRaisesandcontrollerData[controller_].numPendingRaisesis incremented by 1. An invariant of the protocol is that the Safety Module is triggered whileSafetyModule.numPendingRaises > 0 && SafetyModule.safetyModuleState != SafetyModuleState.PAUSED(see 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 emittedSafetyModule.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).
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():
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_
) externalWhile Shared Safety modules can call sharedSafetyModuleRaise()
/// @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_
) externalAt a high-level, when SafetyModule.requestRaise is called by a valid controller
SafetyModule.numPendingRaises()andcontrollerData[controller_].numPendingRaisesare 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.Assets are tapped from each reserve pool according to the
raises_specified, and transferred toreceiver_.If any of the raise amounts exceeds reserve pool deposit amounts, the transaction reverts (see Define Safety Module Configuration).
Assets pending withdrawal are also tapped (see Safety Module Redemptions / Withdrawals).
Internal asset accounting is updated for each reserve pool and underlying asset.
SafetyModule.reservePool(reservePoolId_).depositAmountis decreased by the amount tapped from the reserve pool.SafetyModule.assetPools(asset_).amountis 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.
Last updated