DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: medium
Invalid

depositMargin() Sandwich attack leads to user liquidation

Summary

depositMargin() checks that the total deposit is less than depositCap

Could lead to a sandwich attack by a malicious user who has been unable to deposit collateral and is liquidated

Vulnerability Details

when depositMargin()
we will check depositCap

function depositMargin(uint128 tradingAccountId, address collateralType, uint256 amount) public virtual {
...
TradingAccount.Data storage tradingAccount = TradingAccount.loadExisting(tradingAccountId);
// convert uint256 -> UD60x18; scales input amount to 18 decimals
UD60x18 amountX18 = marginCollateralConfiguration.convertTokenAmountToUd60x18(amount);
// uint128 -> UD60x18
UD60x18 depositCapX18 = ud60x18(marginCollateralConfiguration.depositCap);
// uint256 -> UD60x18
UD60x18 totalCollateralDepositedX18 = ud60x18(marginCollateralConfiguration.totalDeposited);
// enforce converted amount > 0
_requireAmountNotZero(amountX18);
// enforce new deposit + already deposited <= deposit cap
@> _requireEnoughDepositCap(collateralType, amountX18, depositCapX18, totalCollateralDepositedX18);

Users who want to add collateral to avoid being liquidated, but due to the sandwich attack of the giant whale (no fees for depositing and withdrawing collateral), may not be able to do so all the time, leading to liquidation

Impact

Sandwich attack leads to user liquidation

Tools Used

Recommendations

Modify to:

If after depositing: current total deposits are greater than depositCap' and user's MarginBalance > requiredInitialMargin then revert.
This allows the user to deposit collateral that is close to requiredInitialMargin but much larger than requiredMaintenanceMargin to
Avoid liquidation

function depositMargin(uint128 tradingAccountId, address collateralType, uint256 amount) public virtual {
// fetch storage slot for this collateral's config config
MarginCollateralConfiguration.Data storage marginCollateralConfiguration =
MarginCollateralConfiguration.load(collateralType);
// load existing trading account; reverts for non-existent account
// does not enforce msg.sender == account owner so anyone can deposit
// collateral for other traders if they wish
TradingAccount.Data storage tradingAccount = TradingAccount.loadExisting(tradingAccountId);
// convert uint256 -> UD60x18; scales input amount to 18 decimals
UD60x18 amountX18 = marginCollateralConfiguration.convertTokenAmountToUd60x18(amount);
// uint128 -> UD60x18
UD60x18 depositCapX18 = ud60x18(marginCollateralConfiguration.depositCap);
// uint256 -> UD60x18
UD60x18 totalCollateralDepositedX18 = ud60x18(marginCollateralConfiguration.totalDeposited);
// enforce converted amount > 0
_requireAmountNotZero(amountX18);
// enforce new deposit + already deposited <= deposit cap
- _requireEnoughDepositCap(collateralType, amountX18, depositCapX18, totalCollateralDepositedX18);
// enforce collateral has configured liquidation priority
_requireCollateralLiquidationPriorityDefined(collateralType);
// get the tokens first
IERC20(collateralType).safeTransferFrom(msg.sender, address(this), amount);
// then perform the actual deposit
tradingAccount.deposit(collateralType, amountX18);
+ // load new totalDeposited
+ UD60x18 totalCollateralDepositedX18 = ud60x18(marginCollateralConfiguration.totalDeposited);
+ if ( totalCollateralDepositedX18 > depositCapX18) {
+ (UD60x18 requiredInitialMarginUsdX18,, SD59x18 accountTotalUnrealizedPnlUsdX18) =
+ tradingAccount.getAccountMarginRequirementUsdAndUnrealizedPnlUsd(0, SD59x18_ZERO);
+ SD59x18 marginBalanceUsdX18 = tradingAccount.getMarginBalanceUsd(accountTotalUnrealizedPnlUsdX18);
+ require(marginBalanceUsdX18 <= requiredInitialMarginUsdX18," deposit cap");
+ }
emit LogDepositMargin(msg.sender, tradingAccountId, collateralType, amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.