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.
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.
Unlimited slippage and risk of liquidation for the user; loss of funds.
Manual inspection
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.
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.