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: 41/120
Findings: 3
Award: $115.92
π Selected for report: 0
π Solo Findings: 0
π Selected for report: __141345__
Also found by: 0xdeadbeef0x, 8olidity, Amithuddar, Bnke0x0, Ch_301, Deivitto, IllIllI, KingNFT, Nyx, RaymondFam, RedOneN, Satyam_Sharma, SmartSek, Tomo, adriro, bananasboys, carlitox477, cccz, cloudjunky, codexploder, corerouter, cryptonue, d3e4, datapunk, joestakey, martin, merlin, minhquanym, pashov, peanuts, rvierdiiev
5.3388 USDC - $5.34
If gas costs are subject to change, then smart contracts canβt depend on any particular gas costs. Any smart contract that uses transfer() or send() is taking a hard dependency on gas costs by forwarding a fixed amount of gas: 2300.
48: payable(receiver).transfer(amount);
VScode
Use call instead and take care of reentrancy. For example
(bool success, ) = msg.sender.call{amount}(""); require(success, "Transfer failed.");
#0 - c4-judge
2022-11-15T16:12:25Z
dmvt marked the issue as duplicate of #14
#1 - c4-judge
2022-11-17T19:20:15Z
dmvt marked the issue as partial-50
#2 - c4-judge
2022-12-06T14:57:59Z
dmvt marked the issue as full credit
#3 - c4-judge
2022-12-06T14:58:03Z
dmvt marked the issue as satisfactory
#4 - C4-Staff
2022-12-20T05:56:43Z
liveactionllama marked the issue as duplicate of #369
π 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
receive()
/fallback()
functionIf the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth))). Having no access control on the function means that someone may send Ether to the contract, and have no way to get anything back out, which is a loss of funds
There are 2 instances of this issue:
File: /contracts/modules/spigot/Spigot.sol 227: receive() external payable {
File: /contracts/modules/credit/SpigotedLine.sol 272: receive() external payable {}
require()
/revert()
statements should have descriptive reason stringsThere are 22 instances of this issue:
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)); 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/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));
File: /contracts/utils/SpigotedLineLib.sol 147: require(ISpigot(spigot).updateOwner(newLine));
return
variables anywhere in the function
is confusingConsider changing the variable to be an unnamed one
There are 2 instances of this issue:
File: /contracts/modules/spigot/Spigot.sol 72: returns (uint256 claimed) 88: returns (uint256 claimed)
pragma
should be usedThere are 5 instances of this issue:
File: /contracts/modules/credit/LineOfCredit.sol File: /contracts/modules/credit/SecuredLine.sol File: /contracts/modules/credit/SpigotedLine.sol File: /contracts/modules/oracle/Oracle.sol File: /contracts/modules/interest-rate/InterestRateCredit.sol
There are 2 instances of this issue:
File: /contracts/modules/factories/LineFactory.sol 140: // TODO: test 145: // TODO: test
1e18
) rather than exponentiation (e.g. 10**
18)There are 2 instances of this issue:
File: /contracts/utils/CreditLib.sol 117: return price <= 0 ? 0 : (amount * uint(price)) / (1 * 10 ** decimals);
File: /contracts/utils/EscrowLib.sol 42: uint256 _numerator = collateralValue * 10**5; // scale to 4 decimals
There are 3 instances of this issue:
File: /contracts/utils/SpigotedLineLib.sol 13: uint8 constant MAX_SPLIT = 100;
File: /contracts/modules/factories/LineFactory.sol 13: uint8 constant MAX_SPLIT = 100; // max % to take
File: /contracts/utils/SpigotLib.sol 25: uint8 constant MAX_SPLIT = 100;
indexed
fieldsEach event
should use three indexed
fields if there are three or more fields
There are 1 instances of this issue:
File: /contracts/utils/MutualConsent.sol 21: event MutualConsentRegistered(
#0 - c4-judge
2022-12-06T15:00:26Z
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
x <= y
with x < y + 1
, and x >= y
with x > y - 1
In the EVM, there is no opcode for >= or <=. When using greater than or equal, two operations are performed: > and =. Using strict comparison operators hence saves gas
There are 11 instances of this issue:
File: /contracts/modules/credit/LineOfCredit.sol 112: require(uint(status) >= uint( LineLib.STATUS.ACTIVE)); 132: if (block.timestamp >= deadline && count > 0) { 326: require(amount <= credit.principal + credit.interestAccrued); 520: for (uint256 i; i <= lastSpot; ++i) {
File: /contracts/modules/credit/SpigotedLine.sol 62: require(defaultRevenueSplit_ <= SpigotedLineLib.MAX_SPLIT); 143: require(amount <= unusedTokens[credit.token]);
File: /contracts/utils/CreditLib.sol 117: return price <= 0 ? 0 : (amount * uint(price)) / (1 * 10 ** decimals); 136: if(price <= 0 ) { revert NoTokenPrice(); } 176: if (amount <= credit.interestAccrued) {
File: /contracts/utils/CreditListLib.sol 42: if(len <= 1) return true; // already ordered
File: /contracts/utils/EscrowLib.sol 127: if (price <= 0) {
<x> += <y>
costs more gas than <x> = <x> + <y>
for state variablesThere are 20 instances of this issue:
File: /contracts/modules/credit/LineOfCredit.sol 192: principal += _p; 193: interest += _i; 276: credit.deposit += amount; 351: credit.principal += amount;
File: /contracts/modules/credit/SpigotedLine.sol 122: unusedTokens[credit.token] -= repaid - newTokens; 125: unusedTokens[credit.token] += newTokens - repaid; 144: unusedTokens[credit.token] -= amount; 172: unusedTokens[targetToken] += newTokens;
File: /contracts/utils/CreditLib.sol 177: credit.interestAccrued -= amount; 178: credit.interestRepaid += amount; 186: credit.principal -= principalPayment; 187: credit.interestRepaid += interest; 216: amount -= interest; 218: credit.deposit -= amount; 227: credit.interestRepaid -= amount; 258: credit.interestAccrued += accruedToken;
File: /contracts/utils/EscrowLib.sol 75: collateralValue += CreditLib.calculateValue( 96: self.deposited[token].amount += amount; 164: self.deposited[token].amount -= amount; 202: self.deposited[token].amount -= amount;
There are 2 instances of this issue:
File: /contracts/modules/credit/LineOfCredit.sol 21: uint256 public immutable deadline; 31: uint256 private count; // amount of open credit lines on a Line of Credit facility. ids.length includes null items
require()
/revert()
checks should be refactored to a modifier or functionThere are 5 instances of this issue:
File: /contracts/modules/credit/LineOfCredit.sol 241: require(interestRate.setRate(id, drate, frate)); 259: require(interestRate.setRate(id, drate, frate));
File: /contracts/utils/EscrowLib.sol 91: require(amount > 0); 161: require(amount > 0); 198: require(amount > 0);
payable
Marking a function as payable reduces gas cost since the compiler does not have to check whether a payment was provided or not. This change will save around 21 gas per function call.
There are 2 instances of this issue:
File: /contracts/modules/interest-rate/InterestRateCredit.sol 38: ) external override onlyLineContract returns (uint256) { 78: ) external onlyLineContract returns (bool) {
revert()
/require()
strings to save gasThere are 22 instances of this issue:
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)); 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/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));
File: /contracts/utils/SpigotedLineLib.sol 147: require(ISpigot(spigot).updateOwner(newLine));
#0 - c4-judge
2022-11-17T22:52:49Z
dmvt marked the issue as grade-b