The Standard

The Standard
DeFiHardhat
20,000 USDC
View results
Submission Details
Severity: low
Valid

Able to burn and Mint tokens without paying fee

Summary

Because of a rounding error in the mint(), burn() and swap() function in the SmartVaultV3.sol contract, we can borrow and redeem assets without having to pay fees.

Vulnerability Details

The burn and mint functions both calculate the fee in the same manner:
uint256 fee = _amount * ISmartVaultManagerV3(manager).mintFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();

If the product of amount * mintFeeRate() is strictly smaller than HUNDRED_PC(100_000) the fee will be 0. The fee can be changed but is currently set at 500.

So by doing an equation we can figure out what is the maximum amount we can get away with without paying a fee.

500x < 100_000
x < 100_000/500
x < 200

So while amount is smaller than 200 we won't be charged any fee for minting or burning.

Here below is a Foundry test that simulates the fee calculation, the function has been modified to only portray the fee, but the logic remains the same.

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import {Test} from "@forge-std/src/Test.sol";
import {console} from "@forge-std/src/console.sol";
contract MintFunction {
function mint(uint256 _amount) pure external returns(uint256 minted, uint256 fee) {
fee = _amount * 500 / 100_000;
minted = _amount;
}
}
contract BrokenMint is Test {
MintFunction minter;
function setUp() public {
minter = new MintFunction();
}
function test_fee_is_zero() public {
(uint256 amount, uint256 fee) = minter.mint(199);
console.log("fee is:", fee, "amount is: ", amount);
}
}

The log :

test_fee_is_zero() (gas: 9332)
Logs:
fee is: 0 amount is: 199
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 605.08µs

indicates that the fee will be indeed 0

Impact

The impact is quite severe as users theoretically don't have to pay any fees to the protocol and can borrow EUROs for "free".

Tools Used

Foundry
Critical thinking

Recommendations

In order to mitigate this issue, a minimum burn and mint amount should be imposed.

function mint(address _to, uint256 _amount) external onlyOwner ifNotLiquidated {
@> require(amount >= 200, "amount too low");
uint256 fee = _amount * ISmartVaultManagerV3(manager).mintFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC(); //100_000
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);
}

Please do the same for the burn() and swap() functions.

Updates

Lead Judging Commences

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

fee-loss

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

mint-precision

Support

FAQs

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