Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Missing Slippage Protection in Withdrawal Request Flow

Description

In the VaultRouterBranch contract's withdrawal mechanism, while both deposit() and redeem() functions implement slippage protection through minimum output parameters, the initiateWithdrawal() function lacks this critical protection.

function initiateWithdrawal(uint128 vaultId, uint128 shares) external {
if (shares == 0) {
revert Errors.ZeroInput("sharesAmount");
}
// ... rest of function
}

Impact

Users initiating a withdrawal face significant risks due to the lack of slippage protection. When they initiate a withdrawal, they cannot specify a minimum acceptable asset amount, leaving them exposed to potential value decline during the withdrawal delay period. This forces users into difficult choices if the value drops: they must either accept unfavorable rates when redeeming, leave their funds locked indefinitely in the withdrawal request, or incur additional gas costs to cancel and restart the withdrawal process. This design creates unnecessary financial risk and friction in the withdrawal process, potentially trapping user funds or forcing them to accept substantial losses.

Scenario

  1. User initiates withdrawal of 1000 shares when 1 share = 1 ETH

  2. During the withdrawal delay period, share value drops to 0.7 ETH

  3. User must either accept a 30% loss or leave funds locked in the contract

Proof of Concept

  1. Initialize vault with token pair

  2. Deposit assets and receive shares

  3. Initiate withdrawal request

  4. Manipulate price during delay period

  5. Demonstrates forced acceptance of unfavorable rates at redemption

Recommended Fix

Implement slippage protection at withdrawal initiation:

function initiateWithdrawal(
uint128 vaultId,
uint128 shares,
uint256 minAssetsExpected
) external {
if (shares == 0) {
revert Errors.ZeroInput("sharesAmount");
}
// Get expected assets at current rate
uint256 expectedAssets = getIndexTokenSwapRate(vaultId, shares, true).intoUint256();
// Verify expected assets meets minimum
if (expectedAssets < minAssetsExpected) {
revert Errors.SlippageCheckFailed(minAssetsExpected, expectedAssets);
}
// Store minimum assets with withdrawal request
withdrawalRequest.minAssets = minAssetsExpected;
// ... rest of existing function
}

Additionally:

  1. Add minAssets field to WithdrawalRequest struct

  2. Modify redeem() to check against both current minAssets parameter and stored withdrawalRequest.minAssets

  3. Add option to cancel withdrawal requests if price conditions become unfavorable

Updates

Lead Judging Commences

inallhonesty Lead Judge
7 months ago
inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.