Brisk Cherry Aphid
Medium
Malicious users can frontrun calls to fully delever through deleverToZeroBorrowBalance
by repaying dust amounts on behalf of the settoken to continously grief the repayment process.
deleverToZeroBorrowBalance
calls the _repayBorrow
function which invokes repay in Morpho.
function _repayBorrow(
ISetToken _setToken,
MarketParams memory _marketParams,
uint256 _notionalQuantity,
uint256 _shares
)
//...
} else {
_setToken.invokeApprove(_marketParams.loanToken, address(morpho), _notionalQuantity);
>> _setToken.invokeRepay(
morpho,
_marketParams,
_notionalQuantity,
0
);
}
}
Morpho's repay function is public, allowing users to repay on behalf of anyone, without any limit on how little the amount can be. From the implementation we can see that anyone could repay any other user's debt(or part of it). So when the manager tries to repay the full amount a malicious user could just front-run the transaction and repay 1 wei on behalf of the connector address, thus reverting the transaction due to underflow.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes calldata data
) external returns (uint256, uint256) {
Id id = marketParams.id();
require(market[id].lastUpdate != 0, ErrorsLib.MARKET_NOT_CREATED);
require(UtilsLib.exactlyOneZero(assets, shares), ErrorsLib.INCONSISTENT_INPUT);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);
_accrueInterest(marketParams, id);
if (assets > 0) shares = assets.toSharesDown(market[id].totalBorrowAssets, market[id].totalBorrowShares);
else assets = shares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);
>>> position[id][onBehalf].borrowShares -= shares.toUint128();
//...
}
No response
No response
No response
Full repayment DOS due to frontrun.
No response
Check the shares owned and if they are less than the amount passed to repay, repay just the shares owned