Platform: Code4rena
Start Date: 21/06/2022
Pot Size: $55,000 USDC
Total HM: 29
Participants: 88
Period: 5 days
Judge: gzeon
Total Solo HM: 7
Id: 134
League: ETH
Rank: 56/88
Findings: 2
Award: $126.40
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: defsec
Also found by: 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkowloon, 0xmint, Bnke0x0, BowTiedWardens, Chom, ElKu, Funen, GalloDaSballo, GimelSec, IllIllI, JC, Kenshin, Kulk0, Lambda, Limbooo, MadWookie, Metatron, Picodes, Soosh, StErMi, TomJ, WatchPug, Waze, Yiko, _Adam, ak1, asutorufos, aysha, bardamu, catchup, datapunk, delfin454000, dipp, fatherOfBlocks, grGred, hake, hansfriese, hyh, joestakey, kebabsec, kenzo, kirk-baird, oyc_109, pashov, poirots, rfa, robee, saian, sashik_eth, shenwilly, simon135, slywaters, z3s, zeesaw, zer0dot
63.9425 USDC - $63.94
admin
should be set in two stephttps://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L129-L132
When we try to set the new admin of smart contract, we better to set the pending admin, then we let the pending admin claim the admin role to minimize the risk of falsely inputting the new admin address. The admin role is quite critical for the smart contract.
Create new function which set the pendingAdmin and let pending admin claim the ownership in a new other function:
function setPendingAdmin(address a) external authorized(admin) returns (bool) { pendingAdmin = a; //@audit-info: new var at storage return true; } function claimAdmin() external { require(msg.sender == pendingAdmin); admin = msg.sender; }
feeNominator
should be named feeDenominator
https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L681
nominator is not an appropriate term for bottom part of fraction. Using Denominator is more accurate
https://math.stackexchange.com/questions/159081/numerator-vs-denominator-vs-nominator
https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L129-L140
Changing admin
and feenominator
is critical change in the smart contract. By emitting event on this, it easier for the off chain system to track any changes.
🌟 Selected for report: BowTiedWardens
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xkowloon, Bnke0x0, ElKu, Fitraldys, Funen, GalloDaSballo, IllIllI, JC, Kaiziron, Lambda, MadWookie, Noah3o6, Nyamcil, RoiEvenHaim, TomJ, Tomio, UnusualTurtle, Waze, _Adam, ajtra, asutorufos, bardamu, c3phas, catchup, datapunk, defsec, delfin454000, fatherOfBlocks, grGred, hake, hansfriese, hyh, ignacio, joestakey, kebabsec, ladboy233, oyc_109, pashov, poirots, rfa, robee, sach1r0, samruna, sashik_eth, simon135, slywaters, z3s, zer0dot
62.4602 USDC - $62.46
i
Occurrences: https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L96
Using prefix increment can save 5 gas per loop
unchecked { ++i; }
https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L227
The function already return the value in if()
statement above it, so if the condition p == uint8(MarketPlace.Principals.Yield)
== true. The code inside else statement won't be executed
Remove else statement:
if (p == uint8(MarketPlace.Principals.Yield)) { // Purchase yield PTs to lender.sol (address(this)) uint256 returned = yield(u, y, a - calculateFee(a), address(this)); // Mint and distribute equivalent illuminate PTs IERC5095(principalToken(u, m)).mint(msg.sender, returned); emit Lend(p, u, m, returned); return returned; } // Purchase illuminate PTs directly to msg.sender uint256 returned = yield(u, y, a - calculateFee(a), msg.sender); emit Lend(p, u, m, returned); return returned;
It can save 24 deployment gas fee
https://github.com/code-423n4/2022-06-illuminate/blob/main/lender/Lender.sol#L251
Using calldata pointer to store read only array args can save gas