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: 27/120
Findings: 3
Award: $673.39
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xdeadbeef0x
Also found by: 8olidity, Ch_301, HE1M, Koolex, Lambda, Nyx, RedOneN, Ruhum, Tomo, Trust, adriro, aphak5010, ayeslick, berndartmueller, brgltd, carlitox477, cccz, codexploder, d3e4, eierina, eighty, immeas, joestakey, lotux, minhquanym, perseverancesuccess, rbserver, rvierdiiev
4.0405 USDC - $4.04
Judge has assessed an item in Issue #508 as M risk. The relevant finding follows:
https://github.com/code-423n4/2022-11-debtdao-findings/issues/508
#0 - dmvt
2022-12-07T20:17:34Z
[03] Locked msg.value Impact For functions able to transfer ether and erc20, if ether is sent accidentaly with token denomiation different than ETH, the msg.value will be locked.
Proof of Concept Functions handling both ether and erc20 transfers.
Recommended Mitigation Steps When the token denomination is not ETH, add a check if msg.value is zero, e.g. require(msg.value == 0), to prevent accidentaly locking ether on these transactions.
#1 - c4-judge
2022-12-07T20:17:49Z
dmvt marked the issue as duplicate of #25
#2 - c4-judge
2022-12-07T20:17:55Z
dmvt marked the issue as partial-50
#3 - C4-Staff
2022-12-20T06:44:54Z
liveactionllama marked the issue as duplicate of #39
🌟 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
620.1198 USDC - $620.12
.transfer will forward 2300 gas and if the recipient has a fallback/receive function with custom logic, the transation may run of of gas, breaking the contract desired functionality and causing unexpected behavior.
Usage of .transfer to send ether in the library LineLib
, called by LineOfCredit
contract.
Replace .transfer with .call to prevent potential issues with .transfer. Note that the return of .call needs to be checked.
LineOfCredit._updateOutstandingDebt()
_updateOustandingDebt()
will interate over all ids
. The ids
state variable is unbounded.
Updating the debt related functionalities can run out of gas causing a DOS condition.
Limit the maximum number of items in ids
. Alternatively, enable a functionality to update the debt on a chunk of the ids
, instead of the entire array.
For functions able to transfer ether and erc20, if ether is sent accidentaly with token denomiation different than ETH, the msg.value will be locked.
Functions handling both ether and erc20 transfers.
When the token denomination is not ETH, add a check if msg.value is zero, e.g. require(msg.value == 0)
, to prevent accidentaly locking ether on these transactions.
LineOfCredit.borrow()
reentrancy vulnerabilityUpdating the state after external calls that handle control to external contracts allow for attackers to reenter into the original function and break the function state that is updated only after external calls.
LineOfCredit.borrow()
will update the state variables ids
and credits
after the external call to send out ETH or ERC20 tokens. An attacker can callback into LineOfCreditBorrow()
from a fallback/receive function, or from a malicious token contract.
Call _sortIntoQ()
after LineLib.sendOutTokenOrETH()
. Alternatively, add a nonReentrant
modifier into LineOfCredit.borrow()
.
LineLib.receiveTokenOrETH()
won't transfer etherLineLib.receiveTokenOrETH
won't implement any transfer and will return true if msg.value is bigger than amount
and the denomination is ETH
.
Impacted is any functionality calling LineLib
to transfer ether into the contract. It will result in a silent failure.
Add the missing functionality to transfer ether into the contract.
LineLib.receiveTokenOrETH()
for erc20 transfersFunctions calling into LineLib.receiveTokenOrETH()
(LineOfCredit.addCredit()
and LineOfCredit.increaseCredit()
) can pass arbitrary addresses into the erc20 transfer function.
Wherever possible, consider using msg.sender
as the sender argument to avoid having issues related to undesired addresses receiving credit.
The following contracts are using 0.8.9.
contracts/modules/credit/EscrowedLine.sol, contracts/modules/spigot/Spigot.sol, contracts/modules/escrow/Escrow.sol, contracts/modules/factories/LineFactory.sol, contracts/utils/CreditLib.sol, contracts/utils/LineLib.sol, contracts/utils/CreditListLib.sol, contracts/utils/EscrowLib.sol, contracts/utils/SpigotLib.sol, contracts/utils/SpigotedLineLib.sol, contracts/utils/MutualConsent.sol, contracts/utils/LineFactoryLib.sol
Consider using the latest version of solidity to ensure the compiler contains the latest security fixes and improved features. e.g. use version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value
The following contracts are floating the pragma version.
contracts/modules/credit/LineOfCredit.sol, contracts/modules/credit/SecuredLine.sol, contracts/modules/credit/SpigotedLine.sol, contracts/modules/interest-rate/InterestRateCredit.sol,
Locking the pragma helps to ensure that contracts do not accidentally get deployed using an outdated compiler version.
Note that pragma statements can be allowed to float when a contract is intended for consumption by other developers, as in the case with contracts in a library or a package.
If a variable gets configured with address zero, failure to immediately reset the value can result in unexpected behavior for the project.
Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.
Some one-liner conditionals included curly braces and others do not. Consider normalizing only one approach.
Consider adding natspec on all functions to improve documentation.
Consider using only one approach, e.g. either returning a manual value, or not returning a manual value and returning the named variable from the function header.
The solidity documentation recommends the following order for functions:
constructor receive function (if exists) fallback function (if exists) external public internal private
The instance bellow shows internal above external.
The solidity documentation recommends a maximum of 120 characters.
Consider adding a limit of 120 characters or less to prevent large lines.
Consider using only one approach to declare 256 bits integers.
Todos should be resolved before deployment.
Consider refactoring defaultRevenueSplit into DEFAULT_REVENUE_SPLIT
#0 - c4-judge
2022-12-07T20:19:52Z
dmvt marked the issue as grade-a
🌟 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
It can save 30-40 gas per loop
Using the addition operator instead of plus-equals saves 113 gas.
Caching of a state variable replace each Gwarmaccess (100 gas) with a cheaper stack read.
#0 - c4-judge
2022-11-17T23:07:31Z
dmvt marked the issue as grade-b