Platform: Code4rena
Start Date: 28/06/2022
Pot Size: $25,000 USDC
Total HM: 14
Participants: 50
Period: 4 days
Judge: GalloDaSballo
Total Solo HM: 7
Id: 141
League: ETH
Rank: 15/50
Findings: 2
Award: $170.23
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: zzzitron
Also found by: 0v3rf10w, 0x1f8b, 0x29A, AlleyCat, Bnke0x0, Chom, Funen, JC, Lambda, Limbooo, Meera, Picodes, Sm4rty, TerrierLover, TomJ, __141345__, asutorufos, aysha, c3phas, cccz, defsec, fatherOfBlocks, grGred, hake, ignacio, ladboy233, mrpathfindr, oyc_109, rfa, sach1r0, samruna, slywaters, ynnad
43.8433 USDC - $43.84
QA
SenderNotCNote()
https://github.com/Plex-Engineer/lending-market-v2/blob/ea5840de72eab58bec837bb51986ac73712fcfde/contracts/Accountant/AccountantDelegate.sol#L51 https://github.com/Plex-Engineer/lending-market-v2/blob/ea5840de72eab58bec837bb51986ac73712fcfde/contracts/Accountant/AccountantDelegate.sol#L65
Sender address was expected to be inputed as the argument. But in the current implementation, the note address is inputed as the argument
RECOMMENDED MITIGATION STEP Change address(note) to msg.sender
_accountant
address is allowed to do reentrancyRemoving the check that msg.sender != _accountant
can save gas (by reducing action in code), beside it also can prevent any security issue by including _accountant
to the validation step
#0 - GalloDaSballo
2022-08-13T23:34:23Z
Valid NC
Valid Low. Agree that no caller should be allow to reEnter
Neat unique report, 1L 1NC
🌟 Selected for report: 0x1f8b
Also found by: 0x29A, 0xArshia, 0xKitsune, Bnke0x0, Chom, Fitraldys, Funen, JC, Lambda, Meera, Noah3o6, Picodes, RedOneN, Rohan16, Sm4rty, TerrierLover, TomJ, Tomio, Waze, ajtra, c3phas, cRat1st0s, defsec, durianSausage, fatherOfBlocks, grGred, hake, ladboy233, m_Rassska, mrpathfindr, oyc_109, rfa, ynnad
126.3909 USDC - $126.39
GAS
err
Declaring de var in returns() without using statement value can save 13 execution gas fee
RECOMMENDED MITIGATION
function supplyMarket(uint amount) external override returns(uint err) { if (msg.sender != address(cnote)) { revert SenderNotCNote(address(cnote)); } err = cnote.mint(amount); emit AcctSupplied(amount, uint(err)); // @audit-info: remove return statement here }
https://github.com/Plex-Engineer/lending-market-v2/blob/ea5840de72eab58bec837bb51986ac73712fcfde/contracts/CNote.sol#L148 https://github.com/Plex-Engineer/lending-market-v2/blob/ea5840de72eab58bec837bb51986ac73712fcfde/contracts/Governance/Comp.sol#L190 https://github.com/Plex-Engineer/lending-market-v2/blob/ea5840de72eab58bec837bb51986ac73712fcfde/contracts/Governance/Comp.sol#L234-L235 https://github.com/Plex-Engineer/lending-market-v2/blob/ea5840de72eab58bec837bb51986ac73712fcfde/contracts/Governance/GovernorAlpha.sol#L145-L146
Strings are broken into 32 byte chunks for operations. Revert error strings over 32 bytes therefore consume extra gas than shorter strings
nonreentrant
modifierUsing uint8 instead of bool as variable type can save 386 execution gas fee per nonReentrant modifier call
RECOMMENDED MITIGATION STEP
uint8 _notEntered = 1; modifier nonReentrant() { require(_notEntered == 1); _notEntered = 2; _; _notEntered = 1; }
balanceCur
MSTOREbalanceCur
is just called once in the function. We can do SLOAD directly. Remove L103
Using function to validate that the result of math operation won't underflow/overflow in solidity >=0.8.0 its gas consuming. I recommend to add/sub the value without check (without add96/sub96 function), or use unchecked for operation
MITIGATION STEP
function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96 c) { unchecked{ c = a + b;} //@audit: Declare c in returns() require(c >= a, errorMessage); //@audit: remove return statement } function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { require(b <= a, errorMessage); unchecked{return a - b;} }
Proposal
struct variable packingBy placing bool (which) has 1 bytes size next to address (20 bytes size) can save 1 slot at the storage
RECOMMENDED MITIGATION STEP
struct Proposal { /// @notice Unique id for looking up a proposal uint id; /// @notice Creator of the proposal address proposer; /// @notice Flag marking whether the proposal has been canceled bool canceled; /// @notice Flag marking whether the proposal has been executed bool executed; /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds uint eta; /// @notice the ordered list of target addresses for calls to be made address[] targets; /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made uint[] values; /// @notice The ordered list of function signatures to be called string[] signatures; /// @notice The ordered list of calldata to be passed to each call bytes[] calldatas; /// @notice The block at which voting begins: holders must delegate their votes prior to this block uint startBlock; /// @notice The block at which voting ends: votes must be cast prior to this block uint endBlock; /// @notice Current number of votes in favor of this proposal uint forVotes; /// @notice Current number of votes in opposition to this proposal uint againstVotes; /// @notice Receipts of ballots for the entire set of voters mapping (address => Receipt) receipts; }
We can move canceled
and executed
below proposer
var
proposalCount
SLOADBy using prefix increment and do the operation while assigning proposalId
can save 111 execution gas
RECOMMENDED MITIGATION STEP
uint proposalId = ++proposalCount;
#0 - GalloDaSballo
2022-08-14T22:30:42Z
I'm very confused by this as the real savings are in not triggering the gas refunds, hence keeping the Slot non-zero, causing each use of the modifier to cost 5k * 2 vs 20k + 5k
-> 15k
-> Will save in writing and reading, let's say 2.1k * 2 for two saved SLOADs
19200 gas saved, rest is minor