A user can call borrow function with small amounts in order to avoid paying the fee. This way, the user can keep on borrowing for free. There is no condition to check if feeAmount is 0 or not. Additionally, in the function calls, it is never checked how much amount is being borrowed.
Proof of Concept
In the "function _borrow", the borrowOpeningFee is 50, and FEE_PRECISION is 1e5 (100,000). The division operation divides the amount by FEE_PRECISION, which means the result will be rounded down to the nearest integer, in some cases 0.
To calculate the maximum value of amount after which feeAmount will not be 0, we need to find the value of amount at which (amount * borrowOpeningFee) / FEE_PRECISION becomes non-zero.
That means, if the user borrows the amount less than 2000, the feeAmount will always result in 0 as the numerator will be smaller than denominator.
Tools Used
Manual review + in-house tool + SMT solver
Recommended Mitigation Steps
Either a require statement can be put on feeAmount to check for 0, or a require statement can be used to ensure a minimum borrow amount is always passed as input.
Lines of code
https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/master/contracts/markets/bigBang/BigBang.sol#L747 https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/master/contracts/markets/singularity/SGLLendingCommon.sol#L63
Vulnerability details
Impact
A user can call borrow function with small amounts in order to avoid paying the fee. This way, the user can keep on borrowing for free. There is no condition to check if feeAmount is 0 or not. Additionally, in the function calls, it is never checked how much amount is being borrowed.
Proof of Concept
In the "function _borrow", the borrowOpeningFee is 50, and FEE_PRECISION is 1e5 (100,000). The division operation divides the amount by FEE_PRECISION, which means the result will be rounded down to the nearest integer, in some cases 0.
To calculate the maximum value of amount after which feeAmount will not be 0, we need to find the value of amount at which (amount * borrowOpeningFee) / FEE_PRECISION becomes non-zero.
Since the division operation rounds down, the minimum value of feeAmount for it to be non-zero would be 1.
Solving for "amount"
That means, if the user borrows the amount less than 2000, the feeAmount will always result in 0 as the numerator will be smaller than denominator.
Tools Used
Manual review + in-house tool + SMT solver
Recommended Mitigation Steps
Either a require statement can be put on feeAmount to check for 0, or a require statement can be used to ensure a minimum borrow amount is always passed as input.
Assessed type
Math