Platform: Code4rena
Start Date: 25/01/2023
Pot Size: $90,500 USDC
Total HM: 3
Participants: 26
Period: 9 days
Judge: GalloDaSballo
Id: 209
League: ETH
Rank: 17/26
Findings: 1
Award: $131.98
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: descharre
Also found by: 0xA5DF, 0xSmartContract, Aymen0909, Deivitto, NoamYakov, ReyAdmirado, Rolezn, chaduke, cryptostellar5, matrix_0wl
131.9758 USDC - $131.98
S No. | Issue | Instances | Gas Savings |
---|---|---|---|
[G-01] | ++I or I++ SHOULD BE UNCHECKED{++I} or UNCHECKED{I++} WHEN IT IS NOT POSSIBLE FOR THEM TO OVERFLOW, AS IS THE CASE WHEN USED IN FOR- AND WHILE-LOOPS | 16 | 640 |
[G-02] | X += Y COSTS MORE GAS THAN X = X + Y FOR STATE VARIABLES | 21 | 2373 |
[G-03] | USING BOTH NAMED RETURNS AND A RETURN STATEMENT ISNT NECESSARY | 48 | 300 |
[G-04] | INTERNAL FUNCTIONS ONLY CALLED ONCE CAN BE INLINED TO SAVE GAS | 15 | 600 |
[G-05] | USE MSG.SENDER INSTEAD OF OPENZEPPELINS _MSGSENDER() WHEN META-TRANSACTIONS CAPABILITIES ARENT USED | 6 | 12 |
Number of Instances Identified: 16
The unchecked
 keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop.
https://github.com/code-423n4/2023-01-drips/blob/main/src/Caller.sol
196: for (uint256 i = 0; i < calls.length; i++) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/Drips.sol
247: for (uint32 cycle = fromCycle; cycle < toCycle; cycle++) { 287: for (uint32 cycle = fromCycle; cycle < toCycle; cycle++) { 358: for (uint256 i = 0; i < squeezedNum; i++) { 422: for (uint256 i = 1; i <= dripsHistory.length && i <= currCycleConfigs; i++) { 450: for (uint256 i = 0; i < dripsHistory.length; i++) { 490: for (; idx < receivers.length; idx++) { 563: for (uint256 i = 0; i < receivers.length; i++) { 664: for (uint256 i = 0; i < newReceivers.length; i++) { 745: for (uint256 i = 0; i < configsLen; i++) { 777: for (uint256 i = 0; i < receivers.length; i++) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/DripsHub.sol
613: for (uint256 i = 0; i < userMetadata.length; i++) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/ImmutableSplitsDriver.sol
61: for (uint256 i = 0; i < receivers.length; i++) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/Splits.sol
127: for (uint256 i = 0; i < currReceivers.length; i++) { 158: for (uint256 i = 0; i < currReceivers.length; i++) { 231: for (uint256 i = 0; i < receivers.length; i++) {
Number of Instances Identified: 21
Using the addition operator instead of plus-equals saves 113 gas
https://github.com/code-423n4/2023-01-drips/blob/main/src/Drips.sol
253: amtDeltas[toCycle].thisCycle += finalAmtPerCycle; 284: toCycle -= receivableCycles; 288: amtPerCycle += state.amtDeltas[cycle].thisCycle; 289: receivedAmt += uint128(amtPerCycle); 290: amtPerCycle += state.amtDeltas[cycle].nextCycle; 429: amt += _squeezedAmt(userId, drips, squeezeStartCap, squeezeEndCap); 495: amt += _drippedAmt(receiver.config.amtPerSec(), start, end); 572: balance -= uint128(_drippedAmt(receiver.config.amtPerSec(), start, end)); 755: spent += _drippedAmt(amtPerSec, start, end); 1053: amtDelta.thisCycle += int128(fullCycle - nextCycle); 1054: amtDelta.nextCycle += int128(nextCycle);
https://github.com/code-423n4/2023-01-drips/blob/main/src/DripsHub.sol
632: totalBalances[erc20] += amt; 636: _dripsHubStorage().totalBalances[erc20] -= amt;
https://github.com/code-423n4/2023-01-drips/blob/main/src/ImmutableSplitsDriver.sol
62: weightSum += receivers[i].weight;
https://github.com/code-423n4/2023-01-drips/blob/main/src/Splits.sol
99: _splitsStorage().splitsStates[userId].balances[assetId].splittable += amt; 128: splitsWeight += currReceivers[i].weight; 159: splitsWeight += currReceivers[i].weight; 162: splitAmt += currSplitAmt; 167: collectableAmt -= splitAmt; 168: balance.collectable += collectableAmt; 235: totalWeight += weight;
Removing unused named returns variables can reduce gas usage (MSTOREs/MLOADs) and improve code clarity. To save gas and improve code quality: consider using only one of those.
Each MLOAD and MSTORE costs 3 additional gas
There are 48 instances of this issue
https://github.com/code-423n4/2023-01-drips/blob/main/src/AddressDriver.sol
40: function calcUserId(address userAddr) public view returns (uint256 userId) { 46: function callerUserId() internal view returns (uint256 userId) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/Caller.sol
124: function isAuthorized(address sender, address user) public view returns (bool authorized) { 132: function allAuthorized(address sender) public view returns (address[] memory authorized) { 144-147: function callAs(address sender, address to, bytes memory data) public payable returns (bytes memory returnData) 164-171: function callSigned( address sender, address to, bytes memory data, uint256 deadline, bytes32 r, bytes32 sv ) public payable returns (bytes memory returnData) { 202-204: function _call(address sender, address to, bytes memory data, uint256 value) internal returns (bytes memory returnData)
https://github.com/code-423n4/2023-01-drips/blob/main/src/Drips.sol
60-63: function create(uint32 dripId_, uint160 amtPerSec_, uint32 start_, uint32 duration_) internal pure returns (DripsConfig) 300-303: function _receivableDripsCycles(uint256 userId, uint256 assetId) internal view returns (uint32 cycles) 470-475: function _squeezedAmt( uint256 userId, DripsHistory memory dripsHistory, uint32 squeezeStartCap, uint32 squeezeEndCap ) private view returns (uint128 squeezedAmt) { 508-511: function _dripsState(uint256 userId, uint256 assetId) internal view returns ( 533-538: function _balanceAt( uint256 userId, uint256 assetId, DripsReceiver[] memory receivers, uint32 timestamp ) internal view returns (uint128 balance) { 737-742: function _isBalanceEnough( uint256 balance, uint256[] memory configs, uint256 configsLen, uint256 maxEnd ) private view returns (bool isEnough) { 792-795: function _addConfig(uint256[] memory configs, uint256 configsLen, DripsReceiver memory receiver) private view returns (uint256 newConfigsLen) 815-818: function _getConfig(uint256[] memory configs, uint256 idx) private pure returns (uint256 amtPerSec, uint256 start, uint256 end) 834-837: function _hashDrips(DripsReceiver[] memory receivers) internal pure returns (bytes32 dripsHash) 852-857: function _hashDripsHistory( bytes32 oldDripsHistoryHash, bytes32 dripsHash, uint32 updateTime, uint32 maxEnd ) internal pure returns (bytes32 dripsHistoryHash) { 970-973: function _dripsRangeInFuture(DripsReceiver memory receiver, uint32 updateTime, uint32 maxEnd) private view returns (uint32 start, uint32 end) 985-991: function _dripsRange( DripsReceiver memory receiver, uint32 updateTime, uint32 maxEnd, uint32 startCap, uint32 endCap ) private pure returns (uint32 start, uint32 end_) { 1120: function _cycleOf(uint32 timestamp) private view returns (uint32 cycle) { 1128: function _currTimestamp() private view returns (uint32 timestamp) { 1134: function _currCycleStart() private view returns (uint32 timestamp) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/DripsHub.sol
145: function driverAddress(uint32 driverId) public view returns (address driverAddr) { 160: function nextDriverId() public view returns (uint32 driverId) { 169: function cycleSecs() public view returns (uint32 cycleSecs_) { 181: function totalBalance(IERC20 erc20) public view returns (uint256 balance) { 196-199: function receivableDripsCycles(uint256 userId, IERC20 erc20) public view returns (uint32 cycles) 317: function splittable(uint256 userId, IERC20 erc20) public view returns (uint128 amt) { 328-331: function splitResult(uint256 userId, SplitsReceiver[] memory currReceivers, uint128 amount) public view returns (uint128 collectableAmt, uint128 splitAmt) 355-358: function split(uint256 userId, IERC20 erc20, SplitsReceiver[] memory currReceivers) public whenNotPaused returns (uint128 collectableAmt, uint128 splitAmt) 372: function collectable(uint256 userId, IERC20 erc20) public view returns (uint128 amt) { 432-435: function dripsState(uint256 userId, IERC20 erc20) public view returns ( 460-465: function balanceAt( uint256 userId, IERC20 erc20, DripsReceiver[] memory receivers, uint32 timestamp ) public view returns (uint128 balance) { 546: function hashDrips(DripsReceiver[] memory receivers) public pure returns (bytes32 dripsHash) { 557-562: function hashDripsHistory( bytes32 oldDripsHistoryHash, bytes32 dripsHash, uint32 updateTime, uint32 maxEnd ) public pure returns (bytes32 dripsHistoryHash) { 587: function splitsHash(uint256 userId) public view returns (bytes32 currSplitsHash) { 595-598: function hashSplits(SplitsReceiver[] memory receivers) public pure returns (bytes32 receiversHash) 642: function _assetId(IERC20 erc20) internal pure returns (uint256 assetId) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/ImmutableSplitsDriver.sol
36: function nextUserId() public view returns (uint256 userId) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/Managed.sol
105: function isPauser(address pauser) public view returns (bool isAddrPauser) { 112: function allPausers() public view returns (address[] memory pausersList) { 117: function paused() public view returns (bool isPaused) { 136: function _erc1967Slot(string memory name) internal pure returns (bytes32 slot) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/NFTDriver.sol
50: function nextTokenId() public view returns (uint256 tokenId) {
https://github.com/code-423n4/2023-01-drips/blob/main/src/Splits.sol
106: function _splittable(uint256 userId, uint256 assetId) internal view returns (uint128 amt) { 176: function _collectable(uint256 userId, uint256 assetId) internal view returns (uint128 amt) { 262: function _splitsHash(uint256 userId) internal view returns (bytes32 currSplitsHash) { 270-273: function _hashSplits(SplitsReceiver[] memory receivers) internal pure returns (bytes32 receiversHash)
Number of Instances Identified: 15
Not inlining costs 20 to 40 gas because of two extra JUMP
instructions and additional stack operations needed for function calls.
https://github.com/code-423n4/2023-01-drips/blob/main/src/Drips.sol
83: function start(DripsConfig config) internal pure returns (uint32) { 88: function duration(DripsConfig config) internal pure returns (uint32) { 94: function lt(DripsConfig config, DripsConfig otherConfig) internal pure returns (bool) { 233: function _receiveDrips(uint256 userId, uint256 assetId, uint32 maxCycles) 300: function _receivableDripsCycles(uint256 userId, uint256 assetId) 342: function _squeezeDrips( 508: function _dripsState(uint256 userId, uint256 assetId) 610: function _setDrips(
https://github.com/code-423n4/2023-01-drips/blob/main/src/Splits.sol
106: function _splittable(uint256 userId, uint256 assetId) internal view returns (uint128 amt) { 117: function _splitResult(uint256 userId, SplitsReceiver[] memory currReceivers, uint128 amount) 143: function _split(uint256 userId, uint256 assetId, SplitsReceiver[] memory currReceivers) 176: function _collectable(uint256 userId, uint256 assetId) internal view returns (uint128 amt) { 185: function _collect(uint256 userId, uint256 assetId) internal returns (uint128 amt) { 199: function _give(uint256 userId, uint256 receiver, uint256 assetId, uint128 amt) internal { 212: function _setSplits(uint256 userId, SplitsReceiver[] memory receivers) internal {
Number of Instances Identified: 6
msg.sender
costs 2 gas (CALLER opcode). _msgSender()
represents the following:
function _msgSender() internal view virtual returns (address payable) { return msg.sender;}
When no meta-transactions capabilities are used: msg.sender
is enough.
See https://docs.openzeppelin.com/contracts/2.x/gsn for more information about GSN capabilities.
Consider replacing _msgSender()
with msg.sender
here
https://github.com/code-423n4/2023-01-drips/blob/main/src/AddressDriver.sol
47: return calcUserId(_msgSender());
https://github.com/code-423n4/2023-01-drips/blob/main/src/Caller.sol
107: address sender = _msgSender(); 115: address sender = _msgSender(); 149: require(isAuthorized(sender, _msgSender()), "Not authorized"); 195: address sender = _msgSender();
https://github.com/code-423n4/2023-01-drips/blob/main/src/NFTDriver.sol
42: _isApprovedOrOwner(_msgSender(), tokenId),
#0 - GalloDaSballo
2023-02-16T16:02:39Z
820 from
Unchecked and +=
#1 - c4-judge
2023-02-24T11:02:06Z
GalloDaSballo marked the issue as grade-b