58354 sc high forcerepay does not decrement mytsharesdeposited causing a temporal blocking of new deposits
Submitted on Nov 1st 2025 at 14:08:17 UTC by @Pataroff for Audit Comp | Alchemix V3
Report ID: #58354
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Temporary freezing of funds for at least 1 hour
Description
Brief/Intro
Unlike repay(), the _forceRepay() function does not decrement _mytSharesDeposited after transferring MYT tokens to the Transmuter and fee receiver.
As a result, _mytSharesDeposited is overstated relative to the actual MYT balance held by the contract, preventing new deposits from succeeding until manual intervention.
Vulnerability Details
During liquidation, _forceRepay() uses a user’s collateral to repay outstanding debt and transfer funds to the Transmuter and protocol fee receiver. While the user’s per-account state is updated correctly, the global _mytSharesDeposited variable is not decremented, leaving it stale:
function _forceRepay(uint256 accountId, uint256 amount) internal returns (uint256) {
...
// Repay debt from earmarked amount of debt first
uint256 earmarkToRemove = credit > account.earmarked ? account.earmarked : credit;
account.earmarked -= earmarkToRemove;
creditToYield = creditToYield > account.collateralBalance ? account.collateralBalance : creditToYield;
@> account.collateralBalance -= creditToYield;
uint256 protocolFeeTotal = creditToYield * protocolFee / BPS;
emit ForceRepay(accountId, amount, creditToYield, protocolFeeTotal);
if (account.collateralBalance > protocolFeeTotal) {
account.collateralBalance -= protocolFeeTotal;
// Transfer the protocol fee to the protocol fee receiver
TokenUtils.safeTransfer(myt, protocolFeeReceiver, protocolFeeTotal);
}
if (creditToYield > 0) {
// Transfer the repaid tokens from the account to the transmuter.
TokenUtils.safeTransfer(myt, address(transmuter), creditToYield);
}
@> //@audit-missing _mytSharesDeposited -= creditToYield
return creditToYield;
}As a consequence, subsequent deposits will fail if the deposit cap was reached since we enforce the deposit cap check against the _mytSharesDeposited variable:
Impact Details
References
Proof of Concept
Proof of Concept
Was this helpful?