57553 sc high mytsharesdeposited is not updated in liquidations which breaks bad debt ratio alchemistcr calculations and causes failures in bad debt handling and liquidation handling
AlchemistV3 maintains a _mytSharesDeposited state that tracks the amount of collateral deposited in the system. The state is updated in deposits/withdrawals/redeems and when collateral is paid out as fees. However it is not reduced when collateral is transferred to Transmuter during liquidations.
The value of _mytSharesDeposited is used in these two places (among other)
In transmuter::claimRedemption when calculating the system bad debt ratio so that redemption amounts can be scaled down based on bad debt. (alchemist.getTotalUnderlyingValue() is based on _mytSharesDeposited):
// Ratio of total synthetics issued by the alchemist / underlingying value of collateral stored in the alchemist// If the system experiences bad debt we use this ratio to scale back the value of yield tokens that are transmuteduint256 yieldTokenBalance = TokenUtils.safeBalanceOf(alchemist.myt(),address(this));// Avoid divide by 0uint256 denominator = alchemist.getTotalUnderlyingValue()+ alchemist.convertYieldTokensToUnderlying(yieldTokenBalance)>0? alchemist.getTotalUnderlyingValue()+ alchemist.convertYieldTokensToUnderlying(yieldTokenBalance):1;uint256 badDebtRatio = alchemist.totalSyntheticsIssued()*10**TokenUtils.expectDecimals(alchemist.underlyingToken())/ denominator;uint256 scaledTransmuted = amountTransmuted;if(badDebtRatio >1e18){ scaledTransmuted = amountTransmuted * FIXED_POINT_SCALAR / badDebtRatio;}
In DoLiqquidation/CalculateLiquidation where system CR is checked and if bellow the minimum CR - a full liquidation is run instead of a partial one:
Vulnerability Details
Failing to update mytSharesDeposited during liquidations breaks both calculations that rely on it (mentioned above):
In transmuter - the bad debt ratio is calculated largely as totalDebtTokenIssuance / (Alchemist.GetTotalUnderlyingValue() + TransmuterCurrentCollateralAsUnderlying). However, AlchemistTotalUnderlyingValue is based on the alchemist _mytSharesDeposited state. Since this state is not reduced during liquidations, any collateral transfered from alchemist to transmuter during liquidations will be counted twice. This will "overestimate" system health and fail to detect bad debt when it exists. The result is that redemptions will not be scaled down to bad debt, which will cause a "last redeemer loses" situation leading to bank runs and accelerate system involvancy during bad debt periods.
Similarly, In DoLiquidation/calculateLiquidation, the CR calc is based on the ratio of _mytSharesDeposited (in debt token terms) to the Alchemist debt. Here too the CR calculation should not include collateral that was transferred to Transmuter (because only collateral in Alchemist covers alchemist debt). Liquidations will cause this calculation to "overestimate" system health and fail to detect high LTV situations, enabling partial liquidations that increase insolvancy risk during system-high-ltv periods (in addition to under-paying liquidator fees which are supposed to be based on full liquidations in high-ltv scenarios) .
Impact Details
Failure to assign bad debt on redeemers fairly which can lead to bank runs or assign the full bad debt loss to the last redeemers
Failure to perform full liquidations in times of systemwide-high-ltv, increasing system risk of insolvancy.
Copy the code below into the IntegrationTest contract is test/IntergrationTest.t.sol
Comment out the line addDepositsToMYT(); in the setup() function (this makes myt price drop simulation easier)
add the following import: import {AlchemistTokenVault} from "../AlchemistTokenVault.sol";
Run with FOUNDRY_PROFILE=default forge test --fork-url https://mainnet.gateway.tenderly.co --match-test testMytSharesDepositedErrorPOC -vvv --evm-version cancun