The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: medium
Invalid

Minting exposes users to unlimited slippage & deadline

Summary

The mint() function in SmartVaultV3.sol lets users request minting of EUROs based on the deposited collateral. Before minting EUROs, tt calculates that their requested minted amount + fee is within the fully collateralized limits. Users too would want to mint an amount which is not dangerously close to the fully collateralized figure since any minor price fluctuation will result in their immediate eligibility for being liquidated.

However, there is no function parameter provided to users so that they can control the slippage or the deadline while calling mint() in spite of the fact that it checks the collateralization status through internal calls to maxMintable() & euroCollateral() which fetches the collateral price from chainlink via calculator.tokenToEurAvg().

As a result, users may get minted EUROs at a time much later than they placed the request to mint(), at a much worse collateral price than they expected, putting them dangerously close to liquidation.

function mint(address _to, uint256 _amount) external onlyOwner ifNotLiquidated {
uint256 fee = _amount * ISmartVaultManagerV3(manager).mintFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
@----> require(fullyCollateralised(_amount + fee), UNDER_COLL);
minted = minted + _amount + fee;
EUROs.mint(_to, _amount);
EUROs.mint(ISmartVaultManagerV3(manager).protocol(), fee);
emit EUROsMinted(_to, _amount, fee);
}
function fullyCollateralised(uint256 _amount) private view returns (bool) {
@---> return minted + _amount <= maxMintable();
}
function maxMintable() private view returns (uint256) {
@---> return euroCollateral() * ISmartVaultManagerV3(manager).HUNDRED_PC() / ISmartVaultManagerV3(manager).collateralRate();
}
function euroCollateral() private view returns (uint256 euros) {
ITokenManager.Token[] memory acceptedTokens = getTokenManager().getAcceptedTokens();
for (uint256 i = 0; i < acceptedTokens.length; i++) {
ITokenManager.Token memory token = acceptedTokens[i];
@------> euros += calculator.tokenToEurAvg(token, getAssetBalance(token.symbol, token.addr));
}
}

Vulnerability details

Consider the following from dacian's blog:

Many DeFi protocols allow users to transfer foreign tokens to mint the protocol's native token - this is functionally the same as a swap where users are swapping foreign tokens for the protocol's native token. Since this is packaged and presented as a "mint", a slippage parameter may be omitted exposing the user to unlimited slippage!

Note:

When implementing minting functions based upon pool reserves or other on-chain data that can be manipulated in real-time, developers should provide & auditors should verify that users can specify slippage parameters, as such mints are effectively swaps by another name!

In the context of our protocol, let's go through the following scenario:

  • Alice has deposited worth of ETH as collateral. The current chainlink price feed of ETH/EUR is say, which means she has deposited ETH. (This example is just for simplicity. Protocol actually uses ETH/USD & EUR/USD feeds to calculate the price of collateral in EUR).

  • She understands that her max limit to borrow is worth of EUROs. This is because (€1000 + mintingFee) * collateralRate = .

  • She knows even a minor negative price fluctuation in ETH can throw her underwater and hence she plans to maintain some buffer and borrow only EUROs.

  • This gives her buffer till ETH/EUR is not below

  • She calls mint(995)

  • This transaction remains stuck in the mempool for some period of time (due to low transaction fees or any other reasons) which could be minutes or hours.

  • When eventually it is processed, the chainlink price feed returns a value of . This puts her right on the limit of expected collateralization.

  • In the next few seconds before Alice can burn() or make arrangements for more collateral, a slight negative price movement happens towards , making her eligible for liquidation.

  • She is liquidated and loses her collateral.

Impact

Unlimited slippage and risk of liquidation for the user; loss of funds.

Tools Used

Manual inspection

Recommendations

Add a slippage and deadline parameter inside the mint() function which the user can pass. The slippage param here could refer to the user's desired value of -

  • Either the minimum price of each collateralized token

  • Or the minimum value of the entire collateral

before executing the mint.

Updates

Lead Judging Commences

hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

canRemoveCollateral

tripathi Auditor
over 1 year ago
hrishibhat Lead Judge
over 1 year ago
hrishibhat Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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