Closed code423n4 closed 2 years ago
This is by design. Partial withdrawals should help with this. Do keep in mind that more rebalances decrease the overall profitability of the vault due to curve's fees. I think partial withdrawals are a good compromise but willing to discuss further.
Current thinking is that
For UST vaults (no curve): users can withdraw immediately as per your solution For non-UST vaults (with curve): users cannot withdraw immediately if the amount of funds is greater than the reserve. Allowing them to would introduce another griefing attack vector (more rebalances, decreased profitability due to curve fees). I suggest making the uninvest function of these vaults callable not only by the backend's EOA, but also by our multisig.
Also, although this is a much more comprehensive description, it's a duplicate of #126
Duplicate of #76
Handle
WatchPug
Vulnerability details
https://github.com/code-423n4/2022-01-sandclock/blob/a90ad3824955327597be00bb0bd183a9c228a4fb/sandclock/contracts/Vault.sol#L344-L344
In the current implementation, when the user tries to
withdraw()
, the contract will directly transfer the underlying token to a specified address.However, since the contract will invest a certain portion (usually a rather large portion) of the funds into the strategy (and then to a 3rd party: EthAnchor), the balance of underlying token in the Vault contract can often be quite low.
PoC
Given:
investPerc
= 80%withdraw()
and their txs will fail.Impact
Many
withdraw()
transactions will fail due to insufficient underlying token amounts, especially for withdrawals with larger amounts.Recommendation
Consider adding a new function
requestWithdraw(uint amount)
:Check if the current underlying token balance is enough for the withdraw, if true, fulfill the withdrawal immediately;
Otherwise:
requstedWithdrawlAmount[msg.sender] + amount <= depositAmount
;requstedWithdrawlAmount[msg.sender] += amount
;initRedeemStable(amount)
, return theredeemId
.finishWithdraw(uint id)
with theredeemId
to finalize the withdrawal.This introduces a way for the users to get money back from the underlying contract (
EthAnchor
) without relying on a centralized role.