Skip to content

fix: function overload in MSV#333

Open
skimaharvey wants to merge 9 commits intodevelopfrom
feature/osu-1378-interface-bug-multistrategy
Open

fix: function overload in MSV#333
skimaharvey wants to merge 9 commits intodevelopfrom
feature/osu-1378-interface-bug-multistrategy

Conversation

@skimaharvey
Copy link
Contributor

@skimaharvey skimaharvey commented Nov 28, 2025

What does this PR introduce ?

This PR addresses critical interface compatibility issues between the Solidity implementation and the original Vyper vault contracts. The changes ensure 1:1 compatibility with the Vyper implementation while maintaining ERC4626 compliance.

Changes

1. Missing Withdraw/Redeem Function Overloads

Added missing function overloads that were not originally ported from Vyper:

Withdraw Functions && Redeem functions:

  • Missing the 4-parameter overloads (documented)

MaxWithdraw/MaxRedeem Functions:

  • Added 1-parameter and 2-paremeters overloads for both functions with sensible defaults

Design Decision: The Vyper implementation includes additional 4-parameter overloads (with just maxLoss parameter). These were intentionally omitted due to Solidity contract size constraints. The 3 and 5 parameter versions provide equivalent functionality while keeping the contract size manageable.

@linear
Copy link

linear bot commented Nov 28, 2025

@github-actions
Copy link

github-actions bot commented Nov 28, 2025

Code Coverage Report for src/ files

File % Lines % Statements % Branches % Funcs
src/core/BaseStrategy.sol ✅ 94.44% (51/54) ✅ 97.44% (38/39) ✅ 100.00% (2/2) ✅ 89.47% (17/19)
src/core/MultistrategyLockedVault.sol ✅ 87.39% (104/119) ✅ 86.18% (106/123) ✅ 85.00% (17/20) 🔴 80.00% (16/20)
src/core/MultistrategyVault.sol ✅ 93.79% (574/612) ✅ 93.58% (598/639) ✅ 92.86% (182/196) ✅ 89.47% (85/95)
src/core/PaymentSplitter.sol ✅ 100.00% (55/55) ✅ 100.00% (52/52) 🔴 83.33% (15/18) ✅ 100.00% (16/16)
src/core/Privileged.sol ✅ 100.00% (13/13) ✅ 100.00% (12/12) ✅ 100.00% (0/0) ✅ 100.00% (4/4)
src/core/TokenizedStrategy.sol ✅ 97.66% (292/299) ✅ 98.11% (259/264) 🔴 77.78% (70/90) ✅ 95.18% (79/83)
src/core/libs/DebtManagementLib.sol ✅ 97.37% (74/76) ✅ 97.50% (78/80) ✅ 90.00% (18/20) ✅ 100.00% (2/2)
src/core/libs/ERC20SafeApproveLib.sol 🔴 75.00% (3/4) 🔴 80.00% (4/5) 🔴 0.00% (0/1) ✅ 100.00% (1/1)
src/factories/AaveV3StrategyFactory.sol ✅ 100.00% (13/13) ✅ 100.00% (19/19) ✅ 100.00% (2/2) ✅ 100.00% (2/2)
src/factories/AddressSetFactory.sol 🔴 0.00% (0/15) 🔴 0.00% (0/15) ✅ 100.00% (0/0) 🔴 0.00% (0/4)
src/factories/BaseERC4626StrategyFactory.sol ✅ 100.00% (15/15) ✅ 100.00% (19/19) ✅ 100.00% (0/0) ✅ 100.00% (3/3)
src/factories/BaseStrategyFactory.sol ✅ 85.71% (12/14) ✅ 92.86% (13/14) ✅ 100.00% (1/1) 🔴 75.00% (3/4)
src/factories/ERC4626StrategyFactory.sol ✅ 100.00% (2/2) ✅ 100.00% (1/1) ✅ 100.00% (0/0) ✅ 100.00% (1/1)
src/factories/LidoStrategyFactory.sol ✅ 100.00% (12/12) ✅ 100.00% (17/17) ✅ 100.00% (2/2) ✅ 100.00% (2/2)
src/factories/MorphoCompounderStrategyFactory.sol ✅ 100.00% (13/13) ✅ 100.00% (19/19) ✅ 100.00% (2/2) ✅ 100.00% (2/2)
src/factories/MultistrategyVaultFactory.sol ✅ 97.30% (72/74) ✅ 98.44% (63/64) ✅ 96.77% (30/31) ✅ 94.44% (17/18)
src/factories/PaymentSplitterFactory.sol 🔴 82.76% (48/58) ✅ 85.51% (59/69) 🔴 50.00% (11/22) 🔴 70.00% (7/10)
src/factories/RegenStakerFactory.sol ✅ 94.12% (32/34) ✅ 90.91% (30/33) 🔴 50.00% (2/4) ✅ 90.00% (9/10)
src/factories/SkyCompounderStrategyFactory.sol ✅ 100.00% (12/12) ✅ 100.00% (17/17) ✅ 100.00% (2/2) ✅ 100.00% (2/2)
src/factories/SparkStrategyFactory.sol ✅ 100.00% (2/2) ✅ 100.00% (1/1) ✅ 100.00% (0/0) ✅ 100.00% (1/1)
src/factories/yieldDonating/YearnV3StrategyFactory.sol ✅ 100.00% (12/12) ✅ 100.00% (16/16) ✅ 100.00% (0/0) ✅ 100.00% (2/2)
src/factories/yieldSkimming/RocketPoolStrategyFactory.sol ✅ 100.00% (12/12) ✅ 100.00% (17/17) ✅ 100.00% (2/2) ✅ 100.00% (2/2)
src/guards/KeeperBotGuard.sol ✅ 96.88% (31/32) ✅ 96.67% (29/30) ✅ 87.50% (7/8) ✅ 100.00% (6/6)
src/mechanisms/AllocationMechanismFactory.sol 🔴 80.77% (21/26) ✅ 88.46% (23/26) 🔴 33.33% (1/3) 🔴 66.67% (4/6)
src/mechanisms/BaseAllocationMechanism.sol ✅ 95.52% (64/67) ✅ 95.77% (68/71) 🔴 57.14% (4/7) ✅ 95.83% (23/24)
src/mechanisms/TokenizedAllocationMechanism.sol ✅ 86.76% (367/423) 🔴 79.70% (373/468) 🔴 41.54% (54/130) ✅ 90.12% (73/81)
src/mechanisms/mechanism/OctantQFMechanism.sol 🔴 83.78% (31/37) 🔴 83.78% (31/37) 🔴 50.00% (7/14) ✅ 85.71% (6/7)
src/mechanisms/mechanism/QuadraticVotingMechanism.sol ✅ 91.30% (63/69) ✅ 86.21% (75/87) 🔴 52.94% (9/17) ✅ 94.12% (16/17)
src/mechanisms/voting-strategy/ProperQF.sol ✅ 86.05% (74/86) ✅ 88.79% (95/107) 🔴 57.14% (8/14) 🔴 80.00% (12/15)
src/regen/RegenEarningPowerCalculator.sol ✅ 88.57% (31/35) ✅ 87.10% (27/31) 🔴 83.33% (5/6) ✅ 87.50% (7/8)
src/regen/RegenStaker.sol ✅ 87.50% (14/16) ✅ 85.71% (12/14) ✅ 100.00% (1/1) 🔴 80.00% (4/5)
src/regen/RegenStakerBase.sol ✅ 88.28% (211/239) ✅ 89.63% (216/241) 🔴 57.53% (42/73) ✅ 87.88% (29/33)
src/regen/RegenStakerWithoutDelegateSurrogateVotes.sol ✅ 100.00% (20/20) ✅ 100.00% (17/17) ✅ 100.00% (4/4) ✅ 100.00% (5/5)
src/strategies/periphery/BaseHealthCheck.sol ✅ 100.00% (32/32) ✅ 100.00% (24/24) ✅ 100.00% (14/14) ✅ 100.00% (9/9)
src/strategies/periphery/BaseYieldSkimmingHealthCheck.sol ✅ 100.00% (41/41) ✅ 100.00% (39/39) ✅ 100.00% (18/18) ✅ 100.00% (10/10)
src/strategies/periphery/UniswapV3Swapper.sol 🔴 34.78% (8/23) 🔴 26.67% (8/30) 🔴 14.29% (1/7) 🔴 75.00% (3/4)
src/strategies/yieldDonating/AaveV3Strategy.sol ✅ 92.31% (36/39) ✅ 93.75% (45/48) 🔴 55.56% (5/9) ✅ 100.00% (7/7)
src/strategies/yieldDonating/ERC4626Strategy.sol ✅ 100.00% (22/22) ✅ 100.00% (24/24) ✅ 100.00% (2/2) ✅ 100.00% (7/7)
src/strategies/yieldDonating/MorphoCompounderStrategy.sol ✅ 100.00% (22/22) ✅ 100.00% (24/24) 🔴 50.00% (1/2) ✅ 100.00% (7/7)
src/strategies/yieldDonating/PrivilegedYieldDonatingTokenizedStrategy.sol ✅ 100.00% (16/16) ✅ 100.00% (14/14) ✅ 100.00% (4/4) ✅ 100.00% (6/6)
src/strategies/yieldDonating/SkyCompounderStrategy.sol 🔴 76.14% (67/88) 🔴 76.62% (59/77) 🔴 45.83% (11/24) ✅ 89.47% (17/19)
src/strategies/yieldDonating/SparkStrategy.sol ✅ 100.00% (8/8) ✅ 100.00% (9/9) ✅ 100.00% (6/6) ✅ 100.00% (1/1)
src/strategies/yieldDonating/YearnV3Strategy.sol ✅ 100.00% (22/22) ✅ 100.00% (24/24) 🔴 50.00% (1/2) ✅ 100.00% (7/7)
src/strategies/yieldDonating/YieldDonatingTokenizedStrategy.sol ✅ 100.00% (23/23) ✅ 100.00% (26/26) ✅ 100.00% (5/5) ✅ 100.00% (2/2)
src/strategies/yieldSkimming/BaseYieldSkimmingStrategy.sol 🔴 62.50% (5/8) 🔴 60.00% (3/5) ✅ 100.00% (0/0) 🔴 60.00% (3/5)
src/strategies/yieldSkimming/LidoStrategy.sol ✅ 100.00% (4/4) ✅ 100.00% (3/3) ✅ 100.00% (0/0) ✅ 100.00% (2/2)
src/strategies/yieldSkimming/PrivilegedYieldSkimmingTokenizedStrategy.sol ✅ 100.00% (16/16) ✅ 100.00% (14/14) ✅ 100.00% (4/4) ✅ 100.00% (6/6)
src/strategies/yieldSkimming/RocketPoolStrategy.sol ✅ 100.00% (4/4) ✅ 100.00% (3/3) ✅ 100.00% (0/0) ✅ 100.00% (2/2)
src/strategies/yieldSkimming/YieldSkimmingTokenizedStrategy.sol ✅ 93.97% (218/232) ✅ 92.73% (268/289) 🔴 66.67% (50/75) ✅ 96.55% (28/29)
src/utils/AddressSet.sol 🔴 76.47% (26/34) 🔴 76.47% (26/34) 🔴 66.67% (8/12) 🔴 71.43% (5/7)
src/utils/hats/AbstractHatsManager.sol 🔴 82.05% (32/39) 🔴 80.00% (28/35) 🔴 42.86% (12/28) 🔴 83.33% (5/6)
src/utils/hats/DragonHatter.sol ✅ 86.11% (31/36) 🔴 77.42% (24/31) 🔴 46.67% (7/15) ✅ 87.50% (7/8)
src/utils/hats/SimpleEligibilityAndToggle.sol ✅ 100.00% (4/4) ✅ 100.00% (2/2) ✅ 100.00% (0/0) ✅ 100.00% (2/2)
src/utils/libs/Maths/WadRay.sol 🔴 52.00% (13/25) 🔴 47.37% (9/19) 🔴 0.00% (0/6) 🔴 66.67% (4/6)
src/utils/libs/Safe/MultiSendCallOnly.sol 🔴 76.19% (16/21) 🔴 72.73% (16/22) 🔴 0.00% (0/1) ✅ 100.00% (1/1)
src/utils/vendor/0xSplits/LibClone.sol 🔴 0.00% (0/13) 🔴 0.00% (0/12) 🔴 0.00% (0/1) 🔴 0.00% (0/1)
src/utils/vendor/0xSplits/TokenUtils.sol 🔴 0.00% (0/9) 🔴 0.00% (0/8) 🔴 0.00% (0/2) 🔴 0.00% (0/4)
src/utils/vendor/0xSplits/UniV3Swap.sol 🔴 0.00% (0/35) 🔴 0.00% (0/39) 🔴 0.00% (0/6) 🔴 0.00% (0/4)
src/zodiac-core/BaseStrategy.sol 🔴 73.33% (22/30) 🔴 81.25% (13/16) ✅ 100.00% (1/1) 🔴 68.75% (11/16)
src/zodiac-core/LinearAllowanceExecutor.sol 🔴 75.00% (18/24) 🔴 62.50% (15/24) ✅ 100.00% (7/7) ✅ 85.71% (6/7)
src/zodiac-core/ModuleProxyFactory.sol ✅ 95.56% (43/45) ✅ 93.75% (45/48) 🔴 0.00% (0/3) ✅ 87.50% (7/8)
src/zodiac-core/SplitChecker.sol 🔴 37.14% (13/35) 🔴 25.64% (10/39) 🔴 0.00% (0/11) 🔴 42.86% (3/7)
src/zodiac-core/modules/LinearAllowanceSingletonForGnosisSafe.sol ✅ 85.71% (78/91) ✅ 85.00% (85/100) 🔴 71.43% (15/21) 🔴 81.25% (13/16)
src/zodiac-core/modules/MethYieldStrategy.sol 🔴 80.65% (25/31) ✅ 90.00% (27/30) ✅ 100.00% (0/0) 🔴 55.56% (5/9)
src/zodiac-core/modules/YearnPolygonUsdcStrategy.sol ✅ 94.59% (35/37) ✅ 97.37% (37/38) ✅ 100.00% (2/2) ✅ 87.50% (7/8)
src/zodiac-core/vaults/DragonBaseStrategy.sol 🔴 73.53% (25/34) 🔴 78.79% (26/33) 🔴 0.00% (0/2) 🔴 62.50% (5/8)
src/zodiac-core/vaults/DragonTokenizedStrategy.sol ✅ 97.70% (170/174) ✅ 97.86% (183/187) ✅ 87.23% (41/47) ✅ 97.22% (35/36)
src/zodiac-core/vaults/Passport.sol 🔴 0.00% (0/2) 🔴 0.00% (0/1) ✅ 100.00% (0/0) 🔴 0.00% (0/1)
src/zodiac-core/vaults/TokenizedStrategy.sol 🔴 77.44% (230/297) 🔴 79.00% (222/281) 🔴 55.77% (29/52) 🔴 65.17% (58/89)
src/zodiac-core/vaults/YieldBearingDragonTokenizedStrategy.sol ✅ 95.00% (19/20) ✅ 95.45% (21/22) ✅ 100.00% (1/1) ✅ 100.00% (3/3)

@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch 6 times, most recently from fc40f2a to 3ea4308 Compare December 2, 2025 15:05
@skimaharvey skimaharvey marked this pull request as ready for review December 3, 2025 17:10
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from 3e74a76 to f7bf88f Compare December 3, 2025 18:26
@skimaharvey
Copy link
Contributor Author

@codex review and make sure that the ABI with our MultistrategyVault will be the exact same as the original Vyper implementation https://github.com/yearn/yearn-vaults-v3/blob/master/contracts/VaultV3.vy (exceptions to the what is stipulated in the PR description)

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@skimaharvey skimaharvey requested review from 0xferit and qGolem December 3, 2025 18:52
Copy link
Contributor

@qGolem qGolem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split snake case into its own pr to make it easier to review

@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from f7bf88f to e2d1943 Compare January 6, 2026 14:21
@skimaharvey skimaharvey changed the base branch from develop to feature/osu-1402-change-to-snake-case-on-msv January 6, 2026 14:22
@skimaharvey skimaharvey force-pushed the feature/osu-1402-change-to-snake-case-on-msv branch from efdd76a to 6d2011a Compare January 6, 2026 14:24
@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from e2d1943 to dbe88b1 Compare January 6, 2026 14:35
@skimaharvey skimaharvey force-pushed the feature/osu-1402-change-to-snake-case-on-msv branch 3 times, most recently from a53e64c to 9fea78e Compare January 6, 2026 15:07
@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from dbe88b1 to 421b258 Compare January 6, 2026 15:09
@skimaharvey skimaharvey requested a review from qGolem January 7, 2026 10:34
@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from f9bf25c to 14aded9 Compare January 7, 2026 10:37
Base automatically changed from feature/osu-1402-change-to-snake-case-on-msv to develop January 7, 2026 18:04
@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch 2 times, most recently from 5fd0104 to f0d6558 Compare January 7, 2026 18:13
@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from 0ce4209 to a4b3d52 Compare January 8, 2026 13:33
0xferit

This comment was marked as duplicate.

@0xferit 0xferit self-requested a review January 9, 2026 18:48
Copy link
Contributor

@0xferit 0xferit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

MEDIUM-1: assess_share_of_unrealised_losses Breaks Vyper Compatibility

Files:

  • src/core/MultistrategyVault.sol (lines 1926-1933)
  • src/core/interfaces/IMultistrategyVault.sol (line 406)

Description: PR 333 removes the 2-param Vyper-compatible wrapper that existed on develop, leaving only the 3-param version:

Branch Versions Available
develop ✅ 2-param + 3-param overloads
PR 333 ❌ Only 3-param (2-param removed)

Vyper VaultV3.vy external API (2 params):

def assess_share_of_unrealised_losses(strategy: address, assets_needed: uint256) -> uint256:
    current_debt: uint256 = self.strategies[strategy].current_debt  # looks up internally
    return self._assess_share_of_unrealised_losses(strategy, current_debt, assets_needed)

develop branch Solidity (before PR 333) - had matching 2-param wrapper:

function assess_share_of_unrealised_losses(address strategy_, uint256 assetsNeeded_) external view returns (uint256) {
    uint256 currentDebt = _strategies[strategy_].currentDebt;  // looks up internally
    return _assess_share_of_unrealised_losses(strategy_, currentDebt, assetsNeeded_);
}

PR 333 removes this wrapper, leaving only:

function assess_share_of_unrealised_losses(address strategy, uint256 currentDebt, uint256 assetsNeeded)

Impact:

  1. Breaks Vyper ABI compatibility - contradicts the PR's stated goal
  2. Breaks existing integrations expecting the 2-param signature

Risk: Medium - breaks existing integrations and contradicts the PR's stated goal of Vyper interface compatibility.


MEDIUM-2: Interface Gap for get_default_queue()

Files:

  • src/core/MultistrategyVault.sol (line 715)
  • src/core/interfaces/IMultistrategyVault.sol

Description: The function defaultQueue() was removed and replaced with get_default_queue() which correctly matches the Vyper function name. However, get_default_queue() is not declared in the interface.

Vyper verification:

# VaultV3.vy has:
def get_default_queue() -> DynArray[address, MAX_QUEUE]:

Risk:

  1. Breaking change for integrators using defaultQueue() (was non-standard name)
  2. Interface consumers cannot call get_default_queue() through IMultistrategyVault

LOW-1: Utility Functions Removed

File: src/core/MultistrategyLockedVault.sol

Description: Two helper functions removed:

  • getTransferableShares(address user)
  • getRageQuitableShares(address user)

Users must now calculate these values from custodyInfo(user).lockedShares manually.

Risk: Convenience regression for integrators. NatSpec in the contract explains the manual calculation approach, but no external documentation was added.


LOW-2: NatSpec/Implementation Mismatch for maxLoss Default

File: src/core/MultistrategyLockedVault.sol (lines 363-380)

Description: The NatSpec for the 3-parameter withdraw function documents maxLoss = 10000 (100% loss accepted) but the implementation passes maxLoss = 0 (no loss accepted):

/**
 * @notice Withdraws assets with default parameters (maxLoss = 10000, default queue)
 */
function withdraw(uint256 assets, address receiver, address owner) ... {
    ...
    _redeem(msg.sender, receiver, owner, assets, shares, 0, new address[](0));
    //                                               ^-- actual value is 0
}

Analysis: The code is correct - it follows the same pattern as the parent MultistrategyVault where withdraw uses maxLoss=0 and redeem uses maxLoss=10000. This matches ERC4626 semantics: withdraw(assets) specifies exact assets (no slippage tolerance), while redeem(shares) burns exact shares (accepts any resulting assets). The NatSpec is simply a typo.

Risk: Documentation error only. No fund loss possible - at worst, users experience unexpected reverts and must use the 5-parameter version with explicit maxLoss.

@skimaharvey
Copy link
Contributor Author

Thank you for the report.

Med 1 -> good catch and fixed
med 2 -> fixed, added it to the interface
low 1 -> unfortunately the MSLV does not fit with these 2 functions (they can be implemented in a separate contract)
low 2 -> fixed

@0xferit 0xferit self-requested a review January 11, 2026 22:45
0xferit
0xferit previously approved these changes Jan 11, 2026
0xferit
0xferit previously approved these changes Jan 12, 2026
@skimaharvey skimaharvey force-pushed the feature/osu-1378-interface-bug-multistrategy branch from a9fc165 to 7c7dec3 Compare February 4, 2026 05:55
@0xferit
Copy link
Contributor

0xferit commented Feb 27, 2026

Let's merge or close this; it's been months. @qGolem @skimaharvey

@skimaharvey
Copy link
Contributor Author

fine to merge for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants