Platform: Code4rena
Start Date: 03/11/2022
Pot Size: $115,500 USDC
Total HM: 17
Participants: 120
Period: 7 days
Judge: LSDan
Total Solo HM: 1
Id: 174
League: ETH
Rank: 47/120
Findings: 2
Award: $110.58
π Selected for report: 0
π Solo Findings: 0
π Selected for report: IllIllI
Also found by: 0x1f8b, 0xNazgul, 0xRoxas, 0xSmartContract, Awesome, Aymen0909, B2, BClabs, Bnke0x0, Deekshith99, Deivitto, Diana, Dinesh11G, Funen, HE1M, HardlyCodeMan, Josiah, Nyx, Rahoz, RaymondFam, RedOneN, ReyAdmirado, Rolezn, Saintcode_, TomJ, Trust, __141345__, a12jmx, adriro, ajtra, aphak5010, apostle0x01, brgltd, btk, bulej93, c3phas, carlitox477, catwhiskeys, ch0bu, chaduke, chrisdior4, cryptonue, cryptostellar5, csanuragjain, ctf_sec, delfin454000, djxploit, durianSausage, erictee, fatherOfBlocks, gogo, i_got_hacked, immeas, joestakey, jumpdest7d, lukris02, martin, mcwildy, merlin, minhquanym, oyc_109, pashov, peanuts, pedr02b2, rbserver, rotcivegaf, rvierdiiev, sakman, saneryee, seyni, shark, slowmoses, tnevler, trustindistrust, w0Lfrum, yurahod, zaskoh
61.3462 USDC - $61.35
L-N | Issue | Instances |
---|---|---|
[Lβ01] | Open TODO | 2 |
[Lβ02] | Send ether with call instead of transfer | 1 |
N-N | Issue | Instances |
---|---|---|
[Nβ01] | Lint | n |
[Nβ02] | Unused imports | 23 |
[Nβ03] | Non-library/interface files should use fixed compiler versions, not floating ones | 4 |
[Nβ04] | Unreachable code | 2 |
[Nβ05] | Don't check address(0) | 1 |
[Nβ06] | Use internal modifier in the library function instead of external /public | 46 |
[Nβ07] | Require without message/custom errors | 23 |
Open TODO can point to architecture or programming issues that still need to be resolved.
File: contracts/modules/factories/LineFactory.sol 140 // TODO: test 145 // TODO: test
call
instead of transfer
Use call instead of transfer to send ether. And return value must be checked if sending ether is successful or not. Sending ether with the transfer is no longer recommended.
This transaction will fail inevitably when:
_to
smart contract does not implement a payable function._to
smart contract does implement a payable fallback which uses more than 2300 gas unit._to
smart contract implements a payable fallback function that needs less than 2300 gas units but is called through proxy, raising the callβs gas usage above 2300.File: contracts/utils/LineLib.sol 48 payable(receiver).transfer(amount);
Wrong identation: All contracts in the scope haves use both 2 and 4 spaces for indentation, use always 4 spaces
Remove space:
File: contracts/modules/interest-rate/InterestRateCredit.sol 10 // = 31557600 * 10000 = 315576000000;
File: contracts/modules/oracle/Oracle.sol 33 \n 34 \n
File: contracts/utils/CreditLib.sol 15 \n 30 \n 35 \n 53 \n 114 public pure
File: contracts/utils/CreditListLib.sol 41 uint256 len = ids.length ;
File: contracts/utils/SpigotedLineLib.sol 222 \n
File: contracts/utils/CreditLib.sol 7 import { LineLib } from "./LineLib.sol";
File: contracts/modules/factories/LineFactory.sol 5 import {LineLib} from "../../utils/LineLib.sol"; 7 import {SecuredLine} from "../credit/SecuredLine.sol";
File: contracts/modules/escrow/Escrow.sol 3 import { Denominations } from "chainlink/Denominations.sol"; 7 import {IOracle} from "../../interfaces/IOracle.sol"; 8 import {ILineOfCredit} from "../../interfaces/ILineOfCredit.sol"; 9 import {CreditLib} from "../../utils/CreditLib.sol"; 10 import {LineLib} from "../../utils/LineLib.sol";
File: contracts/modules/spigot/Spigot.sol 4 import { LineLib } from "../../utils/LineLib.sol";
File: contracts/modules/credit/SpigotedLine.sol 3 import { Denominations } from "chainlink/Denominations.sol"; 7 import {CreditLib} from "../../utils/CreditLib.sol"; 9 import {MutualConsent} from "../../utils/MutualConsent.sol";
File: contracts/modules/credit/SecuredLine.sol 2 import { IERC20 } from "openzeppelin/token/ERC20/IERC20.sol";
File: contracts/modules/credit/LineOfCredit.sol 3 import { Denominations } from "chainlink/Denominations.sol";
File: contracts/modules/credit/EscrowedLine.sol 9 import { LineOfCredit } from "./LineOfCredit.sol";
File: contracts/utils/SpigotLib.sol 3 import { ReentrancyGuard } from "openzeppelin/security/ReentrancyGuard.sol";
File: contracts/utils/SpigotedLineLib.sol 4 import { ISpigotedLine } from "../interfaces/ISpigotedLine.sol";
File: contracts/utils/LineLib.sol 2 import { IInterestRateCredit } from "../interfaces/IInterestRateCredit.sol"; 3 import { ILineOfCredit } from "../interfaces/ILineOfCredit.sol"; 4 import { IOracle } from "../interfaces/IOracle.sol";
File: contracts/utils/CreditListLib.sol 2 import { ILineOfCredit } from "../interfaces/ILineOfCredit.sol"; 3 import { IOracle } from "../interfaces/IOracle.sol"; 4 import { CreditLib } from "./CreditLib.sol";
File: contracts/modules/oracle/Oracle.sol 2 pragma solidity ^0.8.9;
File: contracts/modules/interest-rate/InterestRateCredit.sol 1 pragma solidity ^0.8.9;
File: contracts/modules/credit/SpigotedLine.sol 1 pragma solidity ^0.8.9;
File: contracts/modules/credit/LineOfCredit.sol 1 pragma solidity ^0.8.9;
File: contracts/utils/SpigotedLineLib.sol 207 return false; 234 return false;
address(0)
File: contracts/modules/factories/LineFactory.sol 21 address moduleFactory,
internal
modifier in the library function instead of external
/public
File: contracts/utils/CreditListLib.sol 20 function removePosition(bytes32[] storage ids, bytes32 id) external returns(bool) { 40 function stepQ(bytes32[] storage ids) external returns(bool) {
File: contracts/utils/CreditLib.sol 66 external pure 79 external 114 public pure 132 external 173 external 207 external 244 public
File: contracts/utils/EscrowLib.sol 34 function _getLatestCollateralRatio(EscrowState storage self, address oracle) public returns (uint256) { 51 function _getCollateralValue(EscrowState storage self, address oracle) public returns (uint256) { 88 external 104 function enableCollateral(EscrowState storage self, address oracle, address token) external returns (bool) { 160 ) external returns (uint256) { 182 function getCollateralRatio(EscrowState storage self, address oracle) external returns (uint256) { 187 function getCollateralValue(EscrowState storage self, address oracle) external returns (uint256) { 197 ) external returns (bool) { 210 function isLiquidatable(EscrowState storage self, address oracle, uint256 minimumCollateralRatio) external returns(bool) { 215 function updateLine(EscrowState storage self, address _line) external returns(bool) {
File: contracts/utils/LineLib.sol 39 external 64 external 80 function getBalance(address token) external view returns (uint256) {
File: contracts/utils/SpigotedLineLib.sol 61 external 126 public 146 function rollover(address spigot, address newLine) external returns(bool) { 151 function canDeclareInsolvent(address spigot, address arbiter) external view returns (bool) { 169 function updateSplit(address spigot, address revenueContract, LineLib.STATUS status, uint8 defaultSplit) external returns (bool) { 194 function releaseSpigot(address spigot, LineLib.STATUS status, address borrower, address arbiter, address to) external returns (bool) { 217 function sweep(address to, address token, uint256 amount, LineLib.STATUS status, address borrower, address arbiter) external returns (bool) {
File: contracts/utils/SpigotLib.sol 30 public 61 function operate(SpigotState storage self, address revenueContract, bytes calldata data) external returns (bool) { 84 external 106 external 125 function addSpigot(SpigotState storage self, address revenueContract, ISpigot.Setting memory setting) external returns (bool) { 144 external 165 external 178 function updateOwner(SpigotState storage self, address newOwner) external returns (bool) { 187 function updateOperator(SpigotState storage self, address newOperator) external returns (bool) { 196 function updateTreasury(SpigotState storage self, address newTreasury) external returns (bool) { 208 function updateWhitelistedFunction(SpigotState storage self, bytes4 func, bool allowed) external returns (bool) { 216 function getEscrowed(SpigotState storage self, address token) external view returns (uint256) { 221 function isWhitelisted(SpigotState storage self, bytes4 func) external view returns(bool) { 228 external view
File: contracts/utils/LineFactoryLib.sol 47 ) external returns(address) { 57 function transferModulesToLine(address line, address spigot, address escrow) external { 86 ) external returns(address){
Add message/use custom errors to give the idea what was the cause of failure
File: contracts/modules/credit/EscrowedLine.sol 64 require(escrow_.liquidate(amount, targetToken, to)); 90 require(escrow.updateLine(newLine));
File: contracts/modules/credit/LineOfCredit.sol 112 require(uint(status) >= uint( LineLib.STATUS.ACTIVE)); 241 require(interestRate.setRate(id, drate, frate)); 259 require(interestRate.setRate(id, drate, frate)); 326 require(amount <= credit.principal + credit.interestAccrued);
File: contracts/modules/credit/SpigotedLine.sol 62 require(defaultRevenueSplit_ <= SpigotedLineLib.MAX_SPLIT); 143 require(amount <= unusedTokens[credit.token]); 160 require(msg.sender == borrower); 239 require(msg.sender == arbiter);
File: contracts/utils/EscrowLib.sol 91 require(amount > 0); 105 require(msg.sender == ILineOfCredit(self.line).arbiter()); 161 require(amount > 0); 198 require(amount > 0); 216 require(msg.sender == self.line);
File: contracts/utils/SpigotedLineLib.sol 147 require(ISpigot(spigot).updateOwner(newLine));
File: contracts/utils/SpigotLib.sol 96 require(LineLib.sendOutTokenOrETH(token, self.treasury, claimed - escrowedAmount)); 128 require(revenueContract != address(this)); 130 require(self.settings[revenueContract].transferOwnerFunction == bytes4(0)); 155 require(success); 180 require(newOwner != address(0)); 189 require(newOperator != address(0)); 201 require(newTreasury != address(0));
#0 - c4-judge
2022-12-07T17:26:51Z
dmvt marked the issue as grade-b
π Selected for report: IllIllI
Also found by: 0x1f8b, 0xRajkumar, Awesome, Aymen0909, B2, Bnke0x0, Deivitto, Diana, JC, Metatron, Rahoz, RaymondFam, RedOneN, ReyAdmirado, Rolezn, Saintcode_, TomJ, __141345__, ajtra, aphak5010, brgltd, c3phas, ch0bu, chrisdior4, cryptonue, durianSausage, emrekocak, erictee, exolorkistis, gogo, karanctf, lukris02, martin, me_na0mi, oyc_109, peanuts, rotcivegaf, saneryee, seyni, tnevler, zaskoh
49.2315 USDC - $49.23
G-N | Issue | Instances |
---|---|---|
[Gβ01] | ++i /i++ should be unchecked{++i} /unchecked{i++} when it is not possible for them to overflow, as is the case when used in for - and while -loops | 6 |
[Gβ02] | Unused lines | 2 |
[Gβ03] | Declare variable in the return | 1 |
[Gβ04] | Make view function | 1 |
[Gβ05] | Unused events | 4 |
[Gβ06] | Not multiply by one | 1 |
++i
/i++
should be unchecked{++i}
/unchecked{i++}
when it is not possible for them to overflow, as is the case when used in for
- and while
-loopsThe unchecked
keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop
File: contracts/modules/credit/LineOfCredit.sol 179 for (uint256 i; i < len; ++i) { 203 for (uint256 i; i < len; ++i) { 520 for (uint256 i; i <= lastSpot; ++i) {
File: contracts/utils/CreditListLib.sol 23 for(uint256 i; i < len; ++i) { 51 for(uint i = 1; i < len; ++i) {
File: contracts/utils/CreditLib.sol 57 for (uint256 i; i < length; ++i) {
This checks could be do offchain:
File: contracts/utils/CreditLib.sol 135 int price = IOracle(oracle).getLatestAnswer(token); 136 if(price <= 0 ) { revert NoTokenPrice(); }
File: contracts/utils/CreditLib.sol 126 int256 price = IOracle(oracle).getLatestAnswer(deposit.asset); 127 if (price <= 0) { 128 revert InvalidCollateral(); 129 }
File: contracts/modules/credit/LineOfCredit.sol /// @audit: declare this variable in the returns, L235 239 bytes32 id = _createCredit(lender, token, amount);
File: modules/oracle/Oracle.sol 23 function getLatestAnswer(address token) external returns (int) {
File: contracts/utils/LineFactoryLib.sol 16 event DeployedSpigot( 17 address indexed deployedAt, 18 address indexed owner, 19 address indexed treasury, 20 address operator 21 ); 23 event DeployedEscrow( 24 address indexed deployedAt, 25 uint32 indexed minCRatio, 26 address indexed oracle, 27 address owner 28 );
File: contracts/utils/EscrowLib.sol 227 event Liquidate(address indexed token, uint256 indexed amount);
File: contracts/utils/CreditLib.sol 38 event Borrow(bytes32 indexed id, uint256 indexed amount);
File: contracts/utils/CreditLib.sol 117 return price <= 0 ? 0 : (amount * uint(price)) / (1 * 10 ** decimals);
#0 - c4-judge
2022-11-17T23:05:35Z
dmvt marked the issue as grade-b