In the SmartVaultV3.sol
contract vault owners can borrow EUROs by calling the mint
function. For every borrow a fee of 0.05%(currently from tests) is taken and is calculated by uint256 fee = _amount * ISmartVaultManagerV3(manager).mintFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
i.e. fee = amount * 500 / 1e5
which can be written as fee = amount / 200
. And since the user can mint any amount(as long as he is overcollateralised) of EUROs he can mint 199 EUROs which is less than 200 so that the fee is rounded down to 0. fee = 199 / 200 = 0
.
He can do this countless times by using a contract that has a for loop function to mint 199 amount of EUROs multiple times until he sucessfully mints 1e18(1 EUROs) tokens but pay 0 amount of fees.
This is possible because the EUROs token contract uses openzeppelin's ERC20Upgradeable contract which does not revert on minting/burning 0 amount of tokens.
And the SmartVaultV3::mint
doesn't check that there is atleast some amount of fees paid by the user.
A user could:
create a contract that has a function with maximim possible loop that can handle the SmartVault contract's minting and burning and transfering the nft.
create new vault by calling SmartVaultManagerV5::mint
.
transfer the nft to his contract.
mint or burn without fees in loop until he reaches the desired amount and transfer back the nft to his address.
While this would be very expensive on mainnet chain the gas cost significantly becomes lower for l2 chains like arbitrum which the protocol is currently using which will make the transaction more profitable for the user.
And it also depends on the amount of fees set by the protocol.
With the growing blockchain ecosystem we will see more chains that cost significantly lesser transaction fees(gas) where the protocol will likely participate in and it is more likely that the protocol will charge less fees it grows.
And this is also possible in the burn
function. Hence I would rate this to be a medium severity although it might not be profitable for the attacker in some cases.
Integrate foundry in the project and create a new file in the test folder and paste this code below:
For this POC to work change the SmartVaultManagerV5::initialize
to:
we do this because we are directly deploying the SmartVaultManagerV5 contract for this test and not upgrading it from an existing one so we need to initialize the owner.
and comment out the require check in the SmartVault::mint
function:
we don't need to check for the collateral for this specific test purpose. It will work as long as there is enough collateral for the amounts minted so we comment out for simplicity and easy testing.
run forge test --mt test_MintWithoutFees -vvv
.
manual, foundry.
Add a check that the fees must be always greater than 0.
require(fee > 0, "insufficient mint amount")
in the mint
and burn
functions.
OR
alternatively add require(amount >= 1e18)
in both the mint and burn functions.
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.