15,000 USDC
View results
Submission Details
Severity: high

[H] Frontrunner can manipulate collateral deposit process

Summary

The depositCollateralAndMintDsc function allows users to deposit collateral and mint DSC tokens in a single transaction.

Vulnerability Details

However, this function is vulnerable to frontrunning attacks, where an attacker can manipulate the collateral deposit process and secure DSC minting with a lower collateral price.

Impact

POC:

User A intends to deposit 1 WBTC as collateral to mint DSC tokens.
The current price of WBTC is $50,000 per token.
User A submits a transaction to call the depositCollateralAndMintDsc function with the parameters (WBTC, 1 WBTC, X DSC), where X represents the desired amount of DSC tokens to mint.
Before User A's transaction is confirmed, the attacker (Front-runner) observes the pending transaction on the mempool and notices that User A intends to deposit 1 WBTC.
The attacker quickly submits their own transaction with a higher gas price, specifying the same parameters as User A (WBTC, 1 WBTC, Y DSC), where Y is a larger amount of DSC tokens to mint.
The attacker's transaction gets mined before User A's transaction due to the higher gas price, and their 1 WBTC is deposited as collateral.
Now, when User A's transaction gets mined, it fails because the contract's state has already been updated by the attacker's transaction. The attacker has successfully manipulated the collateral deposit process and secured DSC minting with a lower collateral price (1 WBTC).

Tools Used

Manual Review

Recommendations

Change the depositCollateral and mintDsc function to internal functions.
This will prevent frontrunners from manipulating the collateral deposit process.

function depositCollateralAndMintDsc(
address tokenCollateralAddress,
uint256 amountCollateral,
uint256 amountDscToMint
) public moreThanZero(amountCollateral) isAllowedToken(tokenCollateralAddress) nonReentrant {
depositCollateral(tokenCollateralAddress, amountCollateral);
mintDsc(amountDscToMint, msg.sender);
}
function depositCollateral(address tokenCollateralAddress, uint256 amountCollateral) internal {
s_collateralDeposited[msg.sender][tokenCollateralAddress] += amountCollateral;
emit CollateralDeposited(msg.sender, tokenCollateralAddress, amountCollateral);
bool success = IERC20(tokenCollateralAddress).transferFrom(msg.sender, address(this), amountCollateral);
if (!success) {
revert DSCEngine__TransferFailed();
}
}
function mintDsc(uint256 amountDscToMint, address onBehalfOf) internal {
s_DSCMinted[onBehalfOf] += amountDscToMint;
i_dsc.mint(onBehalfOf, amountDscToMint);
emit DSCMinted(onBehalfOf, amountDscToMint);
}

Support

FAQs

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