Platform: Code4rena
Start Date: 24/10/2023
Pot Size: $149,725 USDC
Total HM: 7
Participants: 52
Period: 21 days
Judge: ronnyx2017
Total Solo HM: 2
Id: 300
League: ETH
Rank: 39/52
Findings: 1
Award: $21.02
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: DavidGiladi
Also found by: 0xhex, 0xta, Collinsoden, JCK, Madalad, SAQ, SY_S, Sathish9098, cheatc0d3, codeslide, hihen, hunter_w3b, jamshed, lsaudit, mgf15, nonseodion, oualidpro, petrichor, sivanesh_808, tala7985, unique, ybansal2403, zabihullahazadzoi
21.0214 USDC - $21.02
By using assembly, we can directly interact with the storage slot of the stored variable, allowing us to efficiently write and read address values in storage.
diff --git a/ActivePool.sol b/aActivePool.sol index 40b6a1f..345d3dd 100644 --- a/ActivePool.sol +++ b/aActivePool.sol @@ -193,10 +197,13 @@ contract ActivePool is IActivePool, ERC3156FlashLender, ReentrancyGuard, BaseMat function increaseSystemDebt(uint256 _amount) external override { _requireCallerIsBOorCdpM(); - + uint256 cachedSystemDebt = systemDebt + _amount; - - systemDebt = cachedSystemDebt; + //@audit use assembly to update storge + assembly{ + sstore(systemDebt.slot,cachedSystemDebt) + } + //systemDebt = cachedSystemDebt; emit ActivePoolEBTCDebtUpdated(cachedSystemDebt); } @@ -206,10 +213,13 @@ contract ActivePool is IActivePool, ERC3156FlashLender, ReentrancyGuard, BaseMat function decreaseSystemDebt(uint256 _amount) external override { _requireCallerIsBOorCdpM(); - - uint256 cachedSystemDebt = systemDebt - _amount; - - systemDebt = cachedSystemDebt; + uint256 cachedSystemDebt; + unchecked{ + cachedSystemDebt = systemDebt - _amount; + } + assembly{ + sstore(systemDebt.slot,cachedSystemDebt) + } emit ActivePoolEBTCDebtUpdated(cachedSystemDebt); }
Gas diff
|----------------------------------------------|-----------------|-------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | | Function Name | min | avg | median | max | # calls | -| increaseSystemDebt | 1777 | 2746 | 1777 | 21677 | 3078 | +| increaseSystemDebt | 1785 | 2640 | 1785 | 21685 | 3489 |
Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings.
to
struct MoveTokensParams { address user; bool isDebtIncrease; uint256 collSharesChange; uint256 collAddUnderlying; // ONLY for isCollIncrease=true bool isCollIncrease; uint256 netDebtChange; }
diff --git a/ActivePool.sol b/aActivePool.sol index 40b6a1f..345d3dd 100644 --- a/ActivePool.sol +++ b/aActivePool.sol @@ -50,11 +50,15 @@ contract ActivePool is IActivePool, ERC3156FlashLender, ReentrancyGuard, BaseMat address _collSurplusAddress, address _feeRecipientAddress ) { + //@audit use assembly to write address + assembly{ + sstore(feeRecipientAddress.slot,_feeRecipientAddress) + } borrowerOperationsAddress = _borrowerOperationsAddress; cdpManagerAddress = _cdpManagerAddress; collateral = ICollateralToken(_collTokenAddress); collSurplusPoolAddress = _collSurplusAddress; - feeRecipientAddress = _feeRecipientAddress; + //feeRecipientAddress = _feeRecipientAddress; // TEMP: read authority to avoid signature change address _authorityAddress = address(AuthNoOwner(cdpManagerAddress).authority());
A do while loop will cost less gas since the condition is not being checked for the first iteration.
diff --git a/Governor.sol b/aGovernor.sol index 0195952..4263f50 100644 --- a/Governor.sol +++ b/aGovernor.sol @@ -43,25 +43,40 @@ contract Governor is RolesAuthority { function getUsersByRole(uint8 role) external view returns (address[] memory usersWithRole) { // Search over all users: O(n) * 2 uint256 count; - for (uint256 i = 0; i < users.length(); i++) { + //@audit use do while + uint256 i; + uint256 len = users.length(); + do{ + //for (uint256 i = 0; i < users.length(); i++) { address user = users.at(i); bool _canCall = doesUserHaveRole(user, role); if (_canCall) { count += 1; } - } + unchecked{ + ++i; + } + }while(i<len); if (count > 0) { - uint256 j = 0; + //uint256 j = 0; usersWithRole = new address[](count); address[] memory _usrs = users.values(); - for (uint256 i = 0; i < _usrs.length; i++) { + uint256 j; + uint256 i = 0; + do{ + //for (uint256 i = 0; i < _usrs.length; i++) { address user = _usrs[i]; bool _canCall = doesUserHaveRole(user, role); if (_canCall) { usersWithRole[j] = user; - j++; + unchecked{ + ++j; + } } - } + unchecked{ + ++i; + } + }while(i<_usrs.length); } }
Gas Diff
|------------------------------------------|-----------------|--------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | | Function Name | min | avg | median | max | # calls | -| getUsersByRole | 145426 | 145426 | 145426 | 145426 | 1 | +| getUsersByRole | 123563 | 123563 | 123563 | 123563 | 1 |
diff --git a/ActivePool.sol b/aActivePool.sol index 40b6a1f..345d3dd 100644 --- a/ActivePool.sol +++ b/aActivePool.sol @@ -408,7 +418,11 @@ contract ActivePool is IActivePool, ERC3156FlashLender, ReentrancyGuard, BaseMat // set new flash fee uint256 _oldFee = feeBps; - feeBps = uint16(_newFee); + uint16 _fee = uint16(_newFee); + assembly{ + sstore(feeBps.slot,_fee) + } + //feeBps = uint16(_newFee); emit FlashFeeSet(msg.sender, _oldFee, _newFee); }
Gas diff
| contracts/ActivePool.sol:ActivePool contract | | | | | | |----------------------------------------------|-----------------|-------|--------|--------|---------| | Deployment Cost | Deployment Size | | | | | | Function Name | min | avg | median | max | # calls | -| setFeeBps | 50078 | 50078 | 50078 | 50078 | 1 | +| setFeeBps | 47244 | 47244 | 47244 | 47244 | 1 |
#0 - c4-pre-sort
2023-11-17T14:42:02Z
bytes032 marked the issue as sufficient quality report
#1 - c4-judge
2023-11-28T03:04:01Z
jhsagd76 marked the issue as grade-a
#2 - c4-judge
2023-11-28T06:38:04Z
jhsagd76 marked the issue as selected for report
#3 - GalloDaSballo
2023-11-28T18:04:03Z
G-2 is memory not storage
#4 - jhsagd76
2023-12-06T17:29:21Z
3*4 + 1 - 4
9
#5 - c4-judge
2023-12-06T20:57:13Z
jhsagd76 marked the issue as not selected for report
#6 - c4-judge
2023-12-06T20:57:18Z
jhsagd76 marked the issue as grade-b