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: 70/120
Findings: 2
Award: $69.43
🌟 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
8.0811 USDC - $8.08
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/utils/LineLib.sol#L71
excess eth
sent to LineOfCredit
is stuck in the contract. SecuredLine
and SpigotedLine
both have a sweep that can eventually release the eth
. But this kind of applies to them too as it requires the debit to be repaid or only the arbiter can retrieve them.
PoC test in LineOfCredit.t.sol
function test_credit_position_ETH_to_much_sent() public { assertEq(address(line).balance, 0, "Line balance should be 0"); assertEq(lender.balance, mintAmount, "lender should have initial mint balance"); console.log(lender.balance); hoax(borrower); line.addCredit(dRate, fRate, 1 ether, Denominations.ETH, lender); vm.startPrank(lender); line.addCredit{value: 2 ether}(dRate, fRate, 1 ether, Denominations.ETH, lender); vm.stopPrank(); console.log(lender.balance); bytes32 id = line.ids(0); assert(id != bytes32(0)); assertEq(address(line).balance, 2 ether, "Line balance should be 1e18"); assertEq(lender.balance, mintAmount - 2 ether, "Lender should have initial mint balance minus 1e18"); vm.startPrank(lender); // line.withdraw(id,2 ether); fails line.withdraw(id,1 ether); assertEq(address(line).balance, 1 ether, "Line balance should be 1e18"); // line.withdraw(id,1 ether); fails vm.stopPrank(); }
vscode, forge
change:
diff --git a/contracts/utils/LineLib.sol b/contracts/utils/LineLib.sol index fb112cb..62fc7f8 100644 --- a/contracts/utils/LineLib.sol +++ b/contracts/utils/LineLib.sol @@ -68,7 +68,7 @@ library LineLib { if(token != Denominations.ETH) { // ERC20 IERC20(token).safeTransferFrom(sender, address(this), amount); } else { // ETH - if(msg.value < amount) { revert TransferFailed(); } + if(msg.value != amount) { revert TransferFailed(); } } return true; }
There's never any reason to send more eth
than stated in amount
to the contract.
#0 - c4-judge
2022-11-17T14:37:30Z
dmvt marked the issue as duplicate of #25
#1 - c4-judge
2022-12-06T15:38:38Z
dmvt marked the issue as satisfactory
#2 - 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
61.3462 USDC - $61.35
to not accidentally transfer ownership/operator to the wrong address. Since these can potentially control a lot of other contracts.
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/modules/spigot/Spigot.sol#L159-L161
File: modules/spigot/Spigot.sol 159: function updateOwner(address newOwner) external returns (bool) { 160: return state.updateOwner(newOwner); 161: }
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/modules/spigot/Spigot.sol#L170-L172
File: modules/spigot/Spigot.sol 170: function updateOperator(address newOperator) external returns (bool) { 171: return state.updateOperator(newOperator); 172: }
Doesn't follow checks effect interactions. If you really go out of your way as a borrower you could use this reentrancy to mess up the state of ids
however that requires a lot of intentional effort to shoot yourself in the foot so I don't see it as any real issue.
https://fravoll.github.io/solidity-patterns/checks_effects_interactions.html
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/modules/credit/LineOfCredit.sol#L364
File: modules/credit/LineOfCredit.sol 360: LineLib.sendOutTokenOrETH(credit.token, borrower, amount); // interaction 361: 362: emit Borrow(id, amount); 363: 364: _sortIntoQ(id); // state change
Tokens like STA
, PAXG
. Also, USDT
and USDC
have the possiblilty to charge a fee in the future.
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/utils/LineLib.sol#L69
File: utils/LineLib.sol 68: if(token != Denominations.ETH) { // ERC20 69: IERC20(token).safeTransferFrom(sender, address(this), amount); 70: } else { // ETH
The accounting assumes that amount
has been transferred while it might be less. Hence tokens that have a fee would cause accounting errors. Since token used are decided by the lender, borrower and arbiter it might be good with a warning saying tokens with transfer fees are not supported.
Alternatively calculate the balance diff after transfer and use that for amount.
File: modules/credit/SpigotedLine.sol 84: * @notice requires Spigot contract itselgf to be transfered to Arbiter and sold off to a 3rd party before declaring insolvent
File: modules/escrow/Escrow.sol 94: * @notice - allows the lines arbiter to enable thdeposits of an asset 95: * - gives better risk segmentation forlenders
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/modules/credit/EscrowedLine.sol#L43
File: modules/credit/EscrowedLine.sol 43: * see SecuredlLine.liquidate
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/modules/credit/EscrowedLine.sol#L45
File: modules/credit/EscrowedLine.sol 45: * @dev priviliegad function. Do checks before calling.
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/modules/credit/EscrowedLine.sol#L74
File: modules/credit/EscrowedLine.sol 74: *(@dev priviliegad internal function.
File: modules/credit/EscrowedLine.sol 83: * see SecuredlLine.rollover 84: * @notice helper function to allow borrower to easily swithc collateral to a new Line after repyment 85: *(@dev priviliegad internal function.
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/utils/SpigotedLineLib.sol#L207
File: utils/SpigotedLineLib.sol 205: revert CallerAccessDenied(); 206: 207: return false;
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/utils/SpigotedLineLib.sol#L234
File: utils/SpigotedLineLib.sol 234: revert CallerAccessDenied(); 235: 236: return false;
type(uint256).max
instead of 111....35
easier to read
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/utils/EscrowLib.sol#L25-L26
File: utils/EscrowLib.sol 25: uint256 constant MAX_INT = 26: 115792089237316195423570985008687907853269984665640564039457584007913129639935;
and in tests
GitHub starts using a scroll bar when the length is over 164 characters, the lines below should be split when they reach that length.
https://github.com/debtdao/Line-of-Credit/blob/master/contracts/interfaces/ISpigotedLine.sol#L33
File: interfaces/ISpigotedLine.sol 33: * @notice - Claims revenue tokens from the Spigot, trades them for credit tokens via a Dex aggregator (Ox protocol) and uses the bought credit tokens to repay debt.
claimFunction
Consider adding a function to update the claimFunction
for the spigot so you don't have to remove and re-add the whole spigot just to change the claimFunction
. Either if the claimFunction
was wrong or if you want to switch from pull to push.
#0 - c4-judge
2022-12-07T17:31:00Z
dmvt marked the issue as grade-b