Withdrawal/redemptions employ a non-user provided hardcoded slippage in their executions #331
Labels
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
duplicate-365
grade-a
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
🤖_148_group
AI based duplicate group recommendation
Lines of code
https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/CollateralTracker.sol#L532-L568
Vulnerability details
Proof of Concept
Take a look at https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/CollateralTracker.sol#L532-L568
This function is used to redeem an amount of shares required to withdraw the specified amount of
assets
the first check in the function's implementation is to check if the attempted withdrawal is greater than user's current maximum amount that can be withdrawn by therm, this check is being done by querying themaxWithdraw()
function whose implementation can be seen here https://github.com/code-423n4/2024-04-panoptic/blob/833312ebd600665b577fbd9c03ffa0daf250ed24/contracts/CollateralTracker.sol#L507-L514Evidently, we can see that unlike protocol's assumption in
withdraw()
that the value retuned bymaxWithdraw()
is user's maximum redemption, it's only valid at the time and not really the amount of assets they have if the owner's current balance is converted, that's to say in a case where a user's current balance is greater than the available assets, the available assets get returned viaMath.min(available, balance)
this then causes the user's attempt at withdrawal to revert if, say in this case they pass their whole balance or even any balance that's above the current available asset balance.Now keep in mind that we can't really rely on the user first calling
maxWithdraw()
to first see how much they are eligible to withdraw and then pass this data to withdraw, cause even if they do this, there is nothing stopping another user from griefing their attempt at withdrawal by front running their calls with minute amounts that ends up causing the value they passed to be more than the available asset fromuint256 available = s_poolAssets;
.Impact
A user non-provided hardcoded slippage is attached to attempts at withdrawing, this leads to user's not being able to remove their assets on their specified time, note that this could lead to asset loss in their
$USD
moneterial value as users might be attempting to withdraw all their assets cause they feel the crypto market is taking a heavy dump and want to sell off these assets (which is not uncommon in the crypto world, considering the current volatility/in flow of users with the bull run) but this is not possible cause an attempt to withdraw a value that's higher than the available assets currently reverts instead of sending users the currently available assets.One could argue that the first case pertains to a user who's not tech savvy enough to call
maxWithdraw()
to see how much they can withdraw, however even a user who queries this and sees how much they can withdraw and then requesting this, another user (intentional or not) could just front run thier attempt at withdrawing with minute values of assets just to cause the available assets be less than the amount attempted at withdrawal so as to ensure their transactions revert thereby griefing them, and this is possible since there is no minimum withdrawal amount.Recommended Mitigation Steps
Generally, slippage shouldn't be calculated on chain but rather provided by the user, so the function could be reimplemented to allow user pass in their slippaged value of the least amount they are willing to receive, or consider sending a user the currently available asset balance if their requested withdrawal is more than this value and then update their balance.
Alternatively at least to mitigate the window for the second case in Impact, consider having a min withdrawal amount so as not to allow users intentionally or unintentionally grief one another.
Assessed type
Context
The text was updated successfully, but these errors were encountered: