@@ -360,14 +360,62 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
360360 }
361361
362362 /**
363- * @notice Override withdrawal functions to handle custodied shares
363+ * @notice Withdraws assets with default parameters (maxLoss = 10000, default queue)
364+ * @dev Overload to match Vyper's default parameters behavior
365+ * Enforces custody withdrawal rules - requires active rage quit with cooldown passed
366+ * @param assets Amount of assets to withdraw
367+ * @param receiver Address to receive the withdrawn assets
368+ * @param owner Address whose shares will be burned
369+ * @return shares Amount of shares actually burned from owner
370+ * @custom:security Requires active custody and cooldown period passed
371+ */
372+ function withdraw (
373+ uint256 assets ,
374+ address receiver ,
375+ address owner
376+ ) external override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
377+ return withdraw (assets, receiver, owner, 0 , new address [](0 ));
378+ }
379+
380+ /**
381+ * @notice Withdraws assets from the vault with custody enforcement
382+ * @dev ERC4626-extended withdraw function with custody checks
383+ *
384+ * CUSTODY REQUIREMENTS:
385+ * - Owner must have initiated rage quit (active custody)
386+ * - Cooldown period must have passed
387+ * - Withdrawal amount cannot exceed custodied shares
388+ * - Multiple partial withdrawals allowed from same custody
389+ *
390+ * CONVERSION:
391+ * - Uses ROUND_UP when calculating shares (favors vault)
392+ * - shares = (assets * totalSupply + totalAssets - 1) / totalAssets
393+ *
394+ * BEHAVIOR:
395+ * - Validates custody status before processing withdrawal
396+ * - Updates custody by reducing locked shares
397+ * - Clears custody when all locked shares withdrawn
398+ * - Follows standard withdrawal flow after custody checks
399+ *
400+ * LOSS HANDLING:
401+ * - maxLoss_ = 0: Revert if any loss
402+ * - maxLoss_ = 10000: Accept any loss (100%)
403+ * - Users receive proportional share of unrealized losses
404+ *
405+ * @param assets Amount of assets to withdraw
406+ * @param receiver Address to receive the withdrawn assets
407+ * @param owner Address whose shares will be burned
408+ * @param maxLoss Maximum acceptable loss in basis points (0-10000)
409+ * @param strategiesArray Optional custom withdrawal queue (empty = use default)
410+ * @return shares Amount of shares actually burned from owner
411+ * @custom:security Reentrancy protected, requires active custody
364412 */
365413 function withdraw (
366414 uint256 assets ,
367415 address receiver ,
368416 address owner ,
369417 uint256 maxLoss ,
370- address [] calldata strategiesArray
418+ address [] memory strategiesArray
371419 ) public override (MultistrategyVault, IMultistrategyVault) nonReentrant returns (uint256 ) {
372420 uint256 shares = _convertToShares (assets, Rounding.ROUND_UP);
373421 _processCustodyWithdrawal (owner, shares);
@@ -376,14 +424,63 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
376424 }
377425
378426 /**
379- * @notice Override redeem function to handle custodied shares
427+ * @notice Redeems shares with default parameters (maxLoss = 10000, default queue)
428+ * @dev Overload to match Vyper's default parameters behavior
429+ * Enforces custody withdrawal rules - requires active rage quit with cooldown passed
430+ * @param shares Exact amount of shares to burn
431+ * @param receiver Address to receive the withdrawn assets
432+ * @param owner Address whose shares will be burned
433+ * @return assets Amount of assets actually withdrawn and sent to receiver
434+ * @custom:security Requires active custody and cooldown period passed
435+ */
436+ function redeem (
437+ uint256 shares ,
438+ address receiver ,
439+ address owner
440+ ) external override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
441+ return redeem (shares, receiver, owner, 10_000 , new address [](0 ));
442+ }
443+
444+ /**
445+ * @notice Redeems exact amount of shares for assets with custody enforcement
446+ * @dev ERC4626-extended redeem function with custody checks
447+ *
448+ * CUSTODY REQUIREMENTS:
449+ * - Owner must have initiated rage quit (active custody)
450+ * - Cooldown period must have passed
451+ * - Redemption amount cannot exceed custodied shares
452+ * - Multiple partial redemptions allowed from same custody
453+ *
454+ * CONVERSION:
455+ * - Uses ROUND_DOWN when calculating assets (favors vault)
456+ * - assets = (shares * totalAssets) / totalSupply
457+ *
458+ * BEHAVIOR:
459+ * - Validates custody status before processing redemption
460+ * - Burns exact shares amount from owner
461+ * - Updates custody by reducing locked shares
462+ * - Clears custody when all locked shares redeemed
463+ * - May return less assets than expected if losses occur
464+ *
465+ * DIFFERENCE FROM WITHDRAW:
466+ * - withdraw(): User specifies assets, function calculates shares
467+ * - redeem(): User specifies shares, function calculates assets
468+ * - redeem() may return less assets than preview if losses occur
469+ *
470+ * @param shares Exact amount of shares to burn
471+ * @param receiver Address to receive the withdrawn assets
472+ * @param owner Address whose shares will be burned
473+ * @param maxLoss Maximum acceptable loss in basis points (0-10000)
474+ * @param strategiesArray Optional custom withdrawal queue (empty = use default)
475+ * @return assets Amount of assets actually withdrawn and sent to receiver
476+ * @custom:security Reentrancy protected, requires active custody
380477 */
381478 function redeem (
382479 uint256 shares ,
383480 address receiver ,
384481 address owner ,
385482 uint256 maxLoss ,
386- address [] calldata strategiesArray
483+ address [] memory strategiesArray
387484 ) public override (MultistrategyVault, IMultistrategyVault) nonReentrant returns (uint256 ) {
388485 _processCustodyWithdrawal (owner, shares);
389486 uint256 assets = _convertToAssets (shares, Rounding.ROUND_DOWN);
@@ -466,7 +563,7 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
466563 */
467564 function _transfer (address sender_ , address receiver_ , uint256 amount_ ) internal override {
468565 // Check if sender has locked shares that would prevent this transfer
469- CustodyInfo memory custody = custodyInfo[sender_];
566+ CustodyInfo storage custody = custodyInfo[sender_];
470567
471568 if (custody.lockedShares > 0 ) {
472569 uint256 senderBalance = balanceOf (sender_);
@@ -495,9 +592,9 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
495592 function maxWithdraw (
496593 address owner_ ,
497594 uint256 maxLoss_ ,
498- address [] calldata strategiesArray_
499- ) external view override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
500- CustodyInfo memory custody = custodyInfo[owner_];
595+ address [] memory strategiesArray_
596+ ) public view override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
597+ CustodyInfo storage custody = custodyInfo[owner_];
501598 if (block .timestamp < custody.unlockTime) {
502599 return 0 ;
503600 }
@@ -512,6 +609,12 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
512609 return Math.min (parentMax, custodyAssets);
513610 }
514611
612+ function maxWithdraw (
613+ address owner_
614+ ) external view override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
615+ return maxWithdraw (owner_, MAX_BPS, new address [](0 ));
616+ }
617+
515618 /**
516619 * @notice Get the maximum amount of shares that can be redeemed by an owner
517620 * @param owner_ Address owning shares to check redemption limits for
@@ -525,9 +628,9 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
525628 function maxRedeem (
526629 address owner_ ,
527630 uint256 maxLoss_ ,
528- address [] calldata strategiesArray_
529- ) external view override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
530- CustodyInfo memory custody = custodyInfo[owner_];
631+ address [] memory strategiesArray_
632+ ) public view override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
633+ CustodyInfo storage custody = custodyInfo[owner_];
531634
532635 if (block .timestamp < custody.unlockTime) {
533636 return 0 ;
@@ -547,29 +650,13 @@ contract MultistrategyLockedVault is MultistrategyVault, IMultistrategyLockedVau
547650 }
548651
549652 /**
550- * @notice Get the amount of shares that can be transferred by a user
551- * @param user Address to check transferable shares for
552- * @return Amount of shares available for transfer (not locked in custody)
553- * @dev Returns total balance minus shares currently locked in custody
653+ * @notice Returns maximum shares that owner can redeem with default parameters
654+ * @dev Overload to match Vyper's default parameters behavior (maxLoss = MAX_BPS, default queue)
655+ * Enforces custody constraints - returns 0 if cooldown period not passed
656+ * @param owner_ Address that owns the shares
657+ * @return max Maximum redeemable shares (constrained by custody)
554658 */
555- function getTransferableShares (address user ) external view returns (uint256 ) {
556- uint256 totalShares = balanceOf (user);
557- uint256 lockedShares = custodyInfo[user].lockedShares;
558- return totalShares - lockedShares;
559- }
560-
561- /**
562- * @notice Get the amount of shares available for rage quit initiation
563- * @param user Address to check rage quitable shares for
564- * @return Amount of shares available for initiating rage quit
565- * @dev Returns 0 if user already has active custody, otherwise returns full balance
566- */
567- function getRageQuitableShares (address user ) external view returns (uint256 ) {
568- // If user already has active custody, they cannot initiate new rage quit
569- if (custodyInfo[user].lockedShares > 0 ) {
570- return 0 ;
571- }
572- // Otherwise, they can rage quit all their shares
573- return balanceOf (user);
659+ function maxRedeem (address owner_ ) public view override (MultistrategyVault, IMultistrategyVault) returns (uint256 ) {
660+ return maxRedeem (owner_, MAX_BPS, new address [](0 ));
574661 }
575662}
0 commit comments