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:

/// @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

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.

  • The above withdrawRewardAssetsBySig function is truncated to only show the relevant structure of the digest.


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

/// @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.

Last updated