The Standard

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

User might always be in debt

Summary

User is always in debt until and unless he/she gains extra euros than borrowed from any means.

Vulnerability Details

User can not repay back all there loans and will always be in debt until they get the extra euros from any other means like by staking,buying or by anyother means. The protocol uses the burn function as the method of repaying and freeing the asset. When the user wants to clear all his/her loan he will not be able to do that due to wrong logic in the burn function.

When user is trying to repay small amounts then it might not create the problem but when user tries to repay all his/her debt the function will always revert and he/she cannot repay back.In the burn function at first the amount specified is burnt and then the fee is transferred to the protocol. Due to this logic when user tries to pay all the debt there will not be any euros left for the fee. So, instead what should be done is fee should be deducted and transferred first from the amount and then burn the remaining amount.

POC

it('user can not repay fully and will always be in debt', async () => {
const collateral = ethers.utils.parseEther('1');
await user.sendTransaction({to: Vault.address, value: collateral});
const burnedValue = ethers.utils.parseEther('99.5');
// 100 to user
// 0.5 to protocol
// 100.5 minted in vault
const mintedValue = ethers.utils.parseEther('100');
await Vault.connect(user).mint(user.address, mintedValue);
console.log("user Euros : ",await EUROs.connect(user).balanceOf(user.address));
console.log();
const burningFee = burnedValue.mul(PROTOCOL_FEE_RATE).div(HUNDRED_PC);
console.log("fee :",burningFee);
// must allow transfer to protocol
await EUROs.connect(user).approve(Vault.address, burningFee);
burn = Vault.connect(user).burn(burnedValue);
await expect(burn).not.to.be.reverted;
await expect(burn).to.emit(Vault, 'EUROsBurned').withArgs(burnedValue, burningFee);
console.log("user Euros After : ",await EUROs.connect(user).balanceOf(user.address));
});

Here only up to 99.5 can be burned, more than that can not be burned

Impact

User will always be in debt until he/she has extra euros than burrowed by locking the asset.

Tools Used

Manual Review

Recommendations

Change the logic in the burn function.

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