Debt DAO contest - rotcivegaf's results

A cryptonative credit marketplace for fully anon and trustless loans to DAOs.

General Information

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

Debt DAO

Findings Distribution

Researcher Performance

Rank: 47/120

Findings: 2

Award: $110.58

QA:
grade-b
Gas:
grade-b

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

[rotcivegaf] QA report

Low Risk

L-NIssueInstances
[L‑01]Open TODO2
[L‑02]Send ether with call instead of transfer1

Non-critical

N-NIssueInstances
[N‑01]Lintn
[N‑02]Unused imports23
[N‑03]Non-library/interface files should use fixed compiler versions, not floating ones4
[N‑04]Unreachable code2
[N‑05]Don't check address(0)1
[N‑06]Use internal modifier in the library function instead of external/public46
[N‑07]Require without message/custom errors23

Low Risk

[L-01] Open TODO

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

[L-02] Send ether with 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:

  1. The _to smart contract does not implement a payable function.
  2. _to smart contract does implement a payable fallback which uses more than 2300 gas unit.
  3. The _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);

Non-critical

[N‑01] Lint

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

[N‑02] Unused imports

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";

[N‑03] Non-library/interface files should use fixed compiler versions, not floating ones

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;

[N‑04] Unreachable code

File: contracts/utils/SpigotedLineLib.sol

207        return false;

234        return false;

[N‑05] Don't check address(0)

File: contracts/modules/factories/LineFactory.sol

21        address moduleFactory,

[N‑06] Use 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){

[N‑07] Require without message/custom errors

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

Awards

49.2315 USDC - $49.23

Labels

bug
G (Gas Optimization)
grade-b
G-35

External Links

[rotcivegaf] Gas report

G-NIssueInstances
[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-loops6
[G‑02]Unused lines2
[G‑03]Declare variable in the return1
[G‑04]Make view function1
[G‑05]Unused events4
[G‑06]Not multiply by one1

[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

The 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) {

[G-02] Unused lines

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                }

[G-03] Declare variable in the return

File: contracts/modules/credit/LineOfCredit.sol

/// @audit: declare this variable in the returns, L235
239        bytes32 id = _createCredit(lender, token, amount);

[G-04] Make view function

File: modules/oracle/Oracle.sol

23    function getLatestAnswer(address token) external returns (int) {

[G-05] Unused events

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

[G-06] Not multiply by one

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter