# 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](https://csm-docs.cozy.finance/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](https://csm-docs.cozy.finance/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](https://csm-docs.cozy.finance/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](https://csm-docs.cozy.finance/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.
