The Standard

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

Users will not be able to repay the full `minted` amount because of the `fee` system

Summary

If a user borrows EUROs against his collateral, it will not be possible to repay the full amount because of the way fees are calculated. The burn function will revert because of an insufficient balance of EUROs. The fee system is flawed and the fees will be double accounted for in favor of the protocol.

Vulnerability Details

The Standard website is stating that users can borrow EUROs tokens against their collateral with 0% interest rate. This is correct but there is a mintFee and burnFee which the user has to pay. Let's look at the implementation and see how the burn function can revert if a user tries to repay the full borrowed amount.

Looking at the mintfunction, it can be seen that there is a require statement that the loan is fullyCollateralised and the maxMintable is calculated. Apart from that, there is a fee which is added to the minted variable:

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);
}

For the sake of the example:

Let's say that the user wants to borrow 1000 EUROs tokens and the fee is 0.5% as it is set in the test files.

  1. fee = 1000 * 500(0.05%) / 10000 => fee = 5

  2. minted will be equal to the amount minted + the fee => minted = 1005 EUROs

1000 tokens will be minted to the user and 5 tokens will be minted to the protocol. However, the user will have to repay 1005 tokens. The first problem lies here - even though the protocol already received 5 tokens from the mint, the user will have to repay 5 more tokens resulting in 10 tokens of profit for the protocol. This will result in the inflation of the supply over time.

Now, let's look at what will happen if the user wants to repay his loan. As mentioned above minted == 1005 so that's the amount the user will have to repay. The user now have the exactly 1005 tokens and want to repay the loan by calling burn with _amount = 1005:

function burn(uint256 _amount) external ifMinted(_amount) {
uint256 fee = _amount * ISmartVaultManagerV3(manager).burnFeeRate() / ISmartVaultManagerV3(manager).HUNDRED_PC();
minted = minted - _amount;
EUROs.burn(msg.sender, _amount);
IERC20(address(EUROs)).safeTransferFrom(msg.sender, ISmartVaultManagerV3(manager).protocol(), fee);
emit EUROsBurned(_amount, fee);
}

At first, another burning fee is calculated. Let's use the same rate as the mintFeeRate for the simplicity of the example.

  1. The burn fee will be rounded down to 5.

  2. minted = 1005 - 1005 => 0.

  3. 1005 tokens are burned from the user's account.

  4. safeTransferFrom will try to send 5 tokens(fee) to the protocol. However, the transaction will revert.

This is because all of the user's tokens were already burned. The user checked the minted amount he had to repay beforehand and made sure he had enough balance to repay the loan but the transaction reverted with an insufficient balance error.

Impact

Users will not be able to repay the full amount even though they repaid enough minted tokens.

Tools Used

Manual Review

Recommendations

Consider redesigning the fee system. Include the burnFee in a way that is clear for the user and he knows how many tokens he should have before calling the burn function. Also, remove the double counting of fees in favor of the protocol.

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
Invalidated
Reason: Design choice
Assigned finding tags:

fee-loss

Support

FAQs

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