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: 58/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
approve()
and safeApprove()
should be replaced with safeIncreaseAllowance()
/ safeDecreaseAllowance()
approve()
& safeApprove()
are deprecated and subject to a known front-running attack. Consider using safeIncreaseAllowance()
& safeDecreaseAllowance()
instead.
contracts/utils/SpigotedLineLib.sol:L134 IERC20(sellToken).approve(swapTarget, amount);
While floating pragmas make sense for libraries to allow them to be included with multiple different versions of applications, it may be a security risk for application implementations.
A known vulnerable compiler version may accidentally be selected or security tools might fall-back to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain.
It is recommended to pin to a concrete compiler version.
contracts/mock/ZeroEx.sol:L1 pragma solidity ^0.8.9; contracts/modules/credit/SpigotedLine.sol:L1 pragma solidity ^0.8.9; contracts/modules/credit/SecuredLine.sol:L1 pragma solidity ^0.8.9; contracts/modules/credit/LineOfCredit.sol:L1 pragma solidity ^0.8.9; contracts/modules/oracle/Oracle.sol:L2 pragma solidity ^0.8.9; contracts/modules/interest-rate/InterestRateCredit.sol:L1 pragma solidity ^0.8.9;
require()
/revert()
statements should have descriptive strings.Consider adding descriptive strings in require()
/revert()
.
contracts/utils/SpigotedLineLib.sol:L147 require(ISpigot(spigot).updateOwner(newLine)); contracts/utils/SpigotLib.sol:L96 require(LineLib.sendOutTokenOrETH(token, self.treasury, claimed - escrowedAmount)); contracts/utils/SpigotLib.sol:L128 require(revenueContract != address(this)); contracts/utils/SpigotLib.sol:L130 require(self.settings[revenueContract].transferOwnerFunction == bytes4(0)); contracts/utils/SpigotLib.sol:L155 require(success); contracts/utils/SpigotLib.sol:L180 require(newOwner != address(0)); contracts/utils/SpigotLib.sol:L189 require(newOperator != address(0)); contracts/utils/SpigotLib.sol:L201 require(newTreasury != address(0)); contracts/utils/EscrowLib.sol:L91 require(amount > 0); contracts/utils/EscrowLib.sol:L105 require(msg.sender == ILineOfCredit(self.line).arbiter()); contracts/utils/EscrowLib.sol:L161 require(amount > 0); contracts/utils/EscrowLib.sol:L198 require(amount > 0); contracts/utils/EscrowLib.sol:L216 require(msg.sender == self.line); contracts/mock/MockLine.sol:L39 require(msg.sender == arbiter); contracts/modules/credit/SpigotedLine.sol:L62 require(defaultRevenueSplit_ <= SpigotedLineLib.MAX_SPLIT); contracts/modules/credit/SpigotedLine.sol:L143 require(amount <= unusedTokens[credit.token]); contracts/modules/credit/SpigotedLine.sol:L160 require(msg.sender == borrower); contracts/modules/credit/SpigotedLine.sol:L239 require(msg.sender == arbiter); contracts/modules/credit/LineOfCredit.sol:L112 require(uint(status) >= uint( LineLib.STATUS.ACTIVE)); contracts/modules/credit/LineOfCredit.sol:L241 require(interestRate.setRate(id, drate, frate)); contracts/modules/credit/LineOfCredit.sol:L259 require(interestRate.setRate(id, drate, frate)); contracts/modules/credit/LineOfCredit.sol:L326 require(amount <= credit.principal + credit.interestAccrued); contracts/modules/credit/EscrowedLine.sol:L64 require(escrow_.liquidate(amount, targetToken, to)); contracts/modules/credit/EscrowedLine.sol:L90 require(escrow.updateLine(newLine));
_safemint()
should be used rather than _mint()
wherever possible_mint()
is discouraged in favor of _safeMint()
which ensures that the recipient is either an EOA or implements IERC721Receiver
. Both OpenZeppelin and solmate have versions of this function
contracts/mock/RevenueToken.sol:L8 _mint(account, amount);
Zero-address checks are a best practice for input validation of critical address parameters. Accidental use of zero-addresses may result in exceptions, burn fees/tokens, or force redeployment of contracts.
https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/MockEscrowedLine.sol#L20-L21 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/MockLine.sol#L16 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/MockLine.sol#L21 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/MockLine.sol#L26 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/RevenueToken4626.sol#L11 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/RevenueToken4626.sol#L16 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/SimpleOracle.sol#L12-L13 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/SimpleRevenueContract.sol#L10-L11 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/mock/SimpleRevenueContract.sol#L40 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/EscrowedLine.sol#L17 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/LineOfCredit.sol#L55-L57 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/SecuredLine.sol#L23-L27 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/SecuredLine.sol#L30 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/SpigotedLine.sol#L61 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/SpigotedLine.sol#L64 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/credit/SpigotedLine.sol#L66 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/escrow/Escrow.sol#L49-L51 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/oracle/Oracle.sol#L16 https://github.com/debtdao/Line-of-Credit/blob/audit/code4rena-2022-11-03/contracts/modules/spigot/Spigot.sol#L36-L38
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment.
contracts/modules/factories/LineFactory.sol:L140 // TODO: test contracts/modules/factories/LineFactory.sol:L145 // TODO: test
#0 - c4-judge
2022-12-06T22:16:05Z
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
abi.encode()
is less efficient than abi.encodePacked()
Consider using abi.encodePacked()
instead for efficieny.
contracts/utils/CreditLib.sol:L69 return keccak256(abi.encode(line, lender, token));
revert()
/require()
string to save gasCustom errors are available from solidity version 0.8.4, it saves around 50 gas each time they are hit by avoiding having to allocate and store the revert string.
contracts/mock/SimpleOracle.sol:L26 require(prices[token] != 0, "SimpleOracle: unsupported token"); contracts/mock/SimpleRevenueContract.sol:L15 require(msg.sender == owner, "Revenue: Only owner can claim"); contracts/mock/SimpleRevenueContract.sol:L17 require(revenueToken.transfer(owner, revenueToken.balanceOf(address(this))), "Revenue: bad transfer"); contracts/mock/SimpleRevenueContract.sol:L26 require(revenueToken.transfer(owner, revenueToken.balanceOf(address(this))), "Revenue: bad transfer"); contracts/mock/SimpleRevenueContract.sol:L34 require(msg.sender == owner, "Revenue: Only owner can operate"); contracts/mock/SimpleRevenueContract.sol:L39 require(msg.sender == owner, "Revenue: Only owner can transfer");
The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting.
contracts/modules/credit/SpigotedLine.sol:L272 receive() external payable {}
++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.
contracts/utils/CreditListLib.sol:L23 for(uint256 i; i < len; ++i) { contracts/utils/CreditListLib.sol:L51 for(uint i = 1; i < len; ++i) { contracts/utils/EscrowLib.sol:L57 for (uint256 i; i < length; ++i) { contracts/modules/credit/LineOfCredit.sol:L179 for (uint256 i; i < len; ++i) { contracts/modules/credit/LineOfCredit.sol:L203 for (uint256 i; i < len; ++i) { contracts/modules/credit/LineOfCredit.sol:L520 for (uint256 i; i <= lastSpot; ++i) {
Keep revert message lower than or equal to 32 bytes to save gas.
contracts/modules/interest-rate/InterestRateCredit.sol:L26 require(
#0 - c4-judge
2022-11-17T23:01:49Z
dmvt marked the issue as grade-b