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 safety module by referencing one of the controllers configured for this safety module.
function trigger(bytes32 triggerEventId_) 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_)
is called successfully with a valid controller and a unique triggerEventId:
Protocol fees are dripped.
The raise state for the controller and triggerEventId is set to PENDING_RAISE
triggerEventRaiseStates_[controller_][triggerEventId_] = TriggerEventRaiseState.PENDING_RAISE
SafetyModule.numPendingRaises
is 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,
SafetyModule.numPendingSsmRaises
is incremented by 1 andSharedSafetyModule.propagateTrigger(controller_,triggerEventId_)
is called to initiate trigger events across all sibling safety modules. Otherwise,SafetyModule.controllerData(controller_).numPendingRaises
is incremented by 1.event Triggered(controller_, triggerEventId_)
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
function calculateRaise(ISafetyModule originSafetyModule_, AssetNeed[] memory assetNeeds_)
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.
function requestRaise(
bytes32 triggerEventId_,
address receiver_,
AssetNeed[] memory assetNeeds_,
IRaiseStrategy raiseStrategy_
) external
While 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_
) external
At a high-level, when SafetyModule.requestRaise
is called by a valid controller
SafetyModule.numPendingRaises()
is decremented by 1.If the safety module is part of a shared safety module,
SafetyModule.numPendingSsmRaises
is decremented by 1 andSharedSafetyModule.requestRaise(triggerEventId_, receiver_, assetNeeds_, raiseStrategy_, controller_)
is called to initiate raise events across all sibling safety modules. Otherwise,SafetyModule.controllerData(controller_).numPendingRaises
is decremented by 1.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_).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 assetAmount);
is emitted.triggerEventId_, receiver_, raise_.reservePoolId, raise_.amount
Last updated