When a user calls the withdraw function, liquidity is removed and the repay amount which the lending vault should receive is calculated. After that, a keeper will call processWithdraw, which will try to repay the lending vault and withdraw funds and if this doesn’t work out will instead update the status of the vault to Withdraw_Failed and call the processWithdrawFailure function. This function borrows the repaid funds again, but they were never repaid as the processWithdraw function reverted. Therefore, the funds are either borrowed twice, which will increase the debt, without further collateral, or if there are not enough funds to borrow in the lending vault the vault is stuck inside the Withdraw_Failed status. Depending on the amount which needs to be borrowed twice the system is forced into emergency action.
The current status of the vault is Open and a user calls the withdraw function. This function calculates the amount to repay to the lending vault and updates the vault's status to Withdraw:
After that, a keeper bot calls the process Withdraw function. This function calls the processWithdraw function inside the GMXProcessWithdraw, which will try to repay the lending vault and do some other things and if they do not work out the catch block will update the status of the vault to Withdraw_failed:
Here we can see processWithdraw function inside the GMXProcessWithdraw contract, which tries to repay the lending vault and therefore if it reverts and the call lands in the catch block, the lending vault was never repaid:
Now if the vault's status is Withdraw_failed a keeper calls processWithdrawFailure which borrows the calculated repaid amount (which was never repaid as the processWithdraw function reverted) again from the lending vault:
So if a keeper calls processWithdrawFailure it will either borrow the funds twice from the lending vault and therefore increase leverage / debt and borrow funds without any further collateral. Or even worse, if there are not enough funds left in the lending vault, the borrow call will revert and the status of the vault will not be updated to Open again. Therefore, the vault is stuck inside this status and all users experience a full DoS as long as there are not enough funds to borrow in the lending vault. Depending on the amount which needs to be borrowed twice, this could force the owners of the vault into emergency actions.
Here we can see the borrow flow and of course that it will revert if there are not enough funds in the lending vault:
Funds are borrowed twice from the lending vault without further collateral and debt is increased, if there are enough funds in the lending vault. If there are not enough funds in the lending vault, all users experience a full DoS as long as there are not enough funds to borrow. Depending on the amount which needs to be borrowed twice, this could force the owners of the vault into emergency actions.
Manual Review
Remove the borrow call inside processWithdrawFailure as the funds were never repaid in this state.
Impact: High Likelihood: High Overlending is caused due to unnecessary re-borrow on processWithdrawFailure. Assumption that the repayment had gone because it was in try-catch is incorrect.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.