Submitted by kaden
Withdrawals will revert whenever there is not sufficient wrapped native tokens to cover loss from integer truncation.
CompoundStrategy._withdraw calculates the amount of cETH to redeem with cToken.exchangeRateStored based on a provided amount of ETH to receive from the withdrawal.
To understand the vulnerability, we look at the CEther contract which we are attempting to withdraw from.
redeem returns the result from redeemInternal
After accruing interest and checking for errors, redeemInternal returns the result from redeemFresh with the amount of tokens to redeem passed as the second param.
redeemFresh retrieves the exchange rate (the same one that CompoundStrategy._withdraw uses to calculate the amount to redeem), and uses it to calculate vars.redeemAmount which is later transferred to the redeemer. This is the amount of underlying ETH that we are redeeming the CEther tokens for.
We can carefully copy over the logic used in CEther to calculate the amount of underlying ETH to receive, as well as the logic used in CompoundStrategy._withdraw to determine how many CEther to redeem for the desired output amount of underlying ETH, creating the following test contract in Remix.
We run the following example with the current exchangeRateStored (at the time of writing) of 200877136531571418792530957 and an output amount of underlying ETH to receive of 1e18 on the function getToWithdraw, receiving an output of 4978167337 CEther. This is the amount of CEther that would be passed to CEther.redeem.
Next we can see the output amount of underlying ETH according to CEthers logic. We pass the same exchangeRateStored value and the amount of CEther to redeem: 4978167337, receiving an output amount of 999999999831558306, less than the intended amount of 1e18.
Since we receive less than intended to receive from CEther.redeem, the _withdraw call likely fails at the following check:
Rather than computing an amount of CEther to redeem, we can instead use the CEther.redeemUnderlying function to receive our intended amount of underlying ETH.
cryptotechmaker (Tapioca) confirmed
