Platform: Code4rena
Start Date: 29/03/2022
Pot Size: $30,000 USDC
Total HM: 6
Participants: 24
Period: 3 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 101
League: ETH
Rank: 12/24
Findings: 2
Award: $157.98
🌟 Selected for report: 0
🚀 Solo Findings: 0
88.9686 USDC - $88.97
A casting overflow can happen when a uint256 is cast to a uint128. SafeMath does not provide protection for casting overflows, and the overflow may lead to unexpected edge cases.
A casting overflow could occur at this line of PooledCreditLine https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L723
An amount value this large may be reached for some ERC20 tokens with a very large total supply and a very small value per token.
Manual analysis
Make borrowLimit uint256, not uint128 in the PooledCreditLineConstants struct. The only reason why borrowLimit and borrowRate in the PooledCreditLineConstants struct are uint128 is for gas savings, but it would be safer to use uint256 for these variables. The gas savings might be minor because the casting operation is required.
Another solution is to use Open Zeppelin SafeCast
Some ERC20 tokens, such as USDT, don't revert when transfer/transferFrom fails. The transfer return value has to be checked (as there are some other tokens that returns false instead revert). safeTransfer should be used instead of transfer
Manual analysis
Use safeTransfer instead of transfer. This line using SafeERC20 for IERC20;
means the safeTransfer function is available
The PoolCreditLine contract allows collateral deposits when the PooledCreditLineStatus is expired. There should not be any need to add collateral when the status is expired, so this logic branch should be removed to reduce possible edge case scenarios.
The suspect line of code is https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L745
Manual analysis
Remove the code || _status == PooledCreditLineStatus.EXPIRED
from the if statement of line 745 of PoolCreditLine
#0 - ritik99
2022-04-12T19:50:03Z
69.0084 USDC - $69.01
The comparison operators >= and <= use more gas than >, <, or ==. Replacing the >= and ≤ operators with a comparison operator that has an opcode in the EVM saves gas
This code is in calculateBorrowableAmount from PooledCreditLine is the same as an if/else statement https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L950-L952
if (_maxPossible <= _currentDebt) return 0; return Math.min(_borrowLimit - _principal, _maxPossible - _currentDebt);
A simple comparison can be used for gas savings by reversing the logic
if (_maxPossible > _currentDebt) return Math.min(_borrowLimit - _principal, _maxPossible - _currentDebt); return 0;
The same code pattern as above is found at the end of withdrawableCollateral from PooledCreditLine. https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L829-L832
The same approach can be used for repay from PooledCreditLine. The existing code is https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L987-L992
if (_amount >= _totalCurrentDebt) { _amount = _totalCurrentDebt; emit CompletePooledCreditLineRepaid(_id, msg.sender, _amount); } else { emit PartialPooledCreditLineRepaid(_id, msg.sender, _amount); }
The same code with a simple comparison is
if (_amount < _totalCurrentDebt) { emit PartialPooledCreditLineRepaid(_id, msg.sender, _amount); } else { _amount = _totalCurrentDebt; emit CompletePooledCreditLineRepaid(_id, msg.sender, _amount); }
Manual analysis
Replace the comparison operator and reverse the logic to save gas using the suggestions above
Identifying a function as payable saves gas. Functions that have the onlyOwner modifier cannot be called by normal users and will not mistakenly receive ETH. These functions can be payable to save gas.
There are many functions that have the onlyOwner modifier and can be payable
LenderPool functions updateStartFeeFraction
PooledCreditLine functions updateBorrowLimitLimits updateIdealCollateralRatioLimits updateBorrowRateLimits updateCollectionPeriodLimits updateDurationLimits updateDefaultGracePeriodLimits updateGracePenaltyRateLimits updatePriceOracle updateSavingsAccount updateProtocolFeeFraction updateProtocolFeeCollector updateStrategyRegistry updateVerification terminate
Manual analysis
Add payable to these functions for gas savings
Use calldata instead of memory for function parameters. Having function arguments use calldata instead of memory can save gas.
Two function parameters use memory instead of calldata https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/LenderPool.sol#L665-L666
Manual analysis
Change function arguments from memory to calldata
Combining require statement conditions with && logic uses unnecessary gas. It is better to split up each part of the logical statement into a separate require statements
This pattern is found throughout PooledCreditLine https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L406 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L418 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L430 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L442 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L454 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L466 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L478 https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L642
Manual analysis
Use separate require statements instead of concatenating with &&
Solidity 0.7.6 is used in these Sublime contracts. Never versions of solidity include gas optimizations.
One example from solidity 0.8.10 is quoted from https://blog.soliditylang.org/2021/11/09/solidity-0.8.10-release-announcement/#full-changelog
Code Generator: Skip existence check for external contract if return data is expected. In this case, the ABI decoder will revert if the contract does not exist
The request function is one example of where this gas savings would apply https://github.com/sublime-finance/sublime-v1/blob/46536a6d25df4264c1b217bd3232af30355dcb95/contracts/PooledCreditLine/PooledCreditLine.sol#L638
Manual analysis
Use a newer solidity release
#0 - ritik99
2022-04-12T19:09:45Z
All suggestions except the last one are valid. The last one isn't valid for us because one of our dependencies are not compatible with v0.8.10 (https://github.com/Uniswap/v3-core/issues/489)