56442 sc high inflated totallocked because vault yield accrual would skew collateralweight calculation
Submitted on Oct 16th 2025 at 02:15:36 UTC by @farismaulana for Audit Comp | Alchemix V3
Report ID: #56442
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Protocol insolvency
Description
Brief/Intro
MYT is VaultV2 share which overtime would accrue yield. this yield more or less growing and can be used as part of the user debt payment.
but there are issue in AlchemistV3::_addDebt that chain into redeem function, which makes the _collateralWeight inaccurate.
Vulnerability Details
// Update collateral variables
@> uint256 toLock = convertDebtTokensToYield(amount) * minimumCollateralization / FIXED_POINT_SCALAR;
@> uint256 lockedCollateral = convertDebtTokensToYield(account.debt) * minimumCollateralization / FIXED_POINT_SCALAR;
if (account.collateralBalance - lockedCollateral < toLock) revert Undercollateralized();
account.rawLocked = lockedCollateral + toLock;
@> _totalLocked += toLock;
account.debt += amount;
totalDebt += atoLock which is the amount of shares (MYT) needed for debt amount is added into _totalLocked .
notice that this value toLock is recalculated using convertDebtTokensToYield which if the VaultV2 accruing yield, the same amount at timestamp X would result different share if done at timestamp X + Y where the yield accrued.
this ultimately create discrepancy in the real _totalLocked, because how it is updated only with toLock which after many subsequent deposit it would became inflated/innacurate.
example: at timestamp X, the asset per share is 1:1, user mint 100 debt token which need 111 MYT as collateral. 111 MYT is added to _totalLocked. account.rawLocked is 111 MYT.
at timestamp X+Y, the asset per share is 1:0.9, user mint 100 debt token which need only 99.9 MYT collateral. 99.9 MYT is added to _totalLocked . now _totalLocked is 111 MYT + 99.9 MYT = 210.9 MYT.
notice the account.rawLocked is each time recalculate the lockedCollateral + toLock using latest value per share which is now respectively: 99.9 MYT and the new debt requires 99.9 MYT to lock, for a new total of 199.8 MYT.
this discrepancy itself already sufficient for a bug. but we can further check where the additional impact is:
when redeem happening, the _collateralWeight would be calculated using the _totalLocked and totalOut . now we know that _totalLocked is inflated, this means the _collateralWeight would be inaccurate and affect all users.
Impact Details
_totalLocked would be inflated over time which later would severely affect how the _collateralWeight is calculated. potentially to an artificially low or "stunted" _collateralWeight over time.
References
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L917-L925
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L632-L634
Proof of Concept
Proof of Concept
there are multiple files that need to modified:
AlchemistV3.sol so we can see the _totalLocked value
VaultV2.sol, MockMYTVault.sol and so we can quickly simulate/mock that Vault accrue yield
and lastly, the test itself:
we then call call forge test --mt test_poc_amountLockedIssue -vvvv to see our Debug event from second deposit:
the first debug is _totalLocked after first deposit where the asset per share is still 1:1
the second debug is _totalLocked after the second deposit when 1 share is about 1.001 asset worth
the third debug is account.rawLocked which shown that it is not the same as latest _totalLocked at second debug event.
this clearly prove that the _totalLocked over time would inflates.
Was this helpful?