Drips Protocol contest - NoamYakov's results

An Ethereum protocol for streaming and splitting funds.

General Information

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

Drips Protocol

Findings Distribution

Researcher Performance

Rank: 13/26

Findings: 1

Award: $131.98

Gas:
grade-b

🌟 Selected for report: 0

šŸš€ Solo Findings: 0

Findings Information

Labels

bug
G (Gas Optimization)
grade-b
G-01

Awards

131.9758 USDC - $131.98

External Links

Summary

Gas Optimizations

IssueInstancesTotal Gas Saved
[G‑01]++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops221170
[G‑02]Use custom errors rather than revert()/require() strings to save gas3150
[G‑03]<x> += <y> costs more gas than <x> = <x> + <y> for state variables (-= too)6678

Total: 31 instances over 3 issues with 1998 gas saved.

Gas totals use lower bounds of ranges and count two iterations of each for-loop. All values above are runtime, not deployment, values; deployment values are listed in the individual issue descriptions.

Gas Optimizations

[G‑01] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops

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.

There are 22 instances of this issue:

File: src\Caller.sol

174         uint256 currNonce = nonce[sender]++;

196         for (uint256 i = 0; i < calls.length; i++) {
File: src\DripsHub.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++) {

/// @audit inside `for`-loop
428                     squeezedRevIdxs[squeezedNum++] = 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++) {

655             state.currCycleConfigs++;

664             for (uint256 i = 0; i < newReceivers.length; i++) {

/// @audit inside `while`-loop
959                 currIdx++;

/// @audit inside `while`-loop
962                 newIdx++;
File: src\DripsHub.sol

136         driverId = dripsHubStorage.nextDriverId++;

613         for (uint256 i = 0; i < userMetadata.length; i++) {
File: src\ImmutableSplitsDriver.sol

59          StorageSlot.getUint256Slot(_counterSlot).value++;

61          for (uint256 i = 0; i < receivers.length; i++) {
File: src\NFTDriver.sol

93          StorageSlot.getUint256Slot(_mintedTokensSlot).value++;
File: 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++) {

[G‑02] Use custom errors rather than revert()/require() strings to save gas

Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hit by avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas.

There are 3 instances of this issue:

File: src\Managed.sol

53          require(
54              admin() == msg.sender || isPauser(msg.sender), "Caller is not the admin or a pauser"
55          );
File: src\NFTDriver.sol

41          require(
42              _isApprovedOrOwner(_msgSender(), tokenId),
43              "ERC721: caller is not token owner or approved"
44        );
File: src\Splits.sol

254         require(
255             _hashSplits(currReceivers) == _splitsHash(userId), "Invalid current splits receivers"
256         );

[G‑03] <x> += <y> costs more gas than <x> = <x> + <y> for state variables (-= too)

Using the addition operator instead of plus-equals saves 113 gas. Subtructions act the same way.

There are 6 instances of this issue:

File: src\Drips.sol

253                     amtDeltas[toCycle].thisCycle += finalAmtPerCycle;

1053                amtDelta.thisCycle += int128(fullCycle - nextCycle);

1054                amtDelta.nextCycle += int128(nextCycle);
File: src\DripsHub.sol

632         totalBalances[erc20] += amt;
File: src\Splits.sol

99          _splitsStorage().splitsStates[userId].balances[assetId].splittable += amt;

168         balance.collectable += collectableAmt;

#0 - GalloDaSballo

2023-02-16T15:39:06Z

Unchecked 20 * 22 440

+= - 100 600

1040

#1 - c4-judge

2023-02-24T11:02:01Z

GalloDaSballo marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Ā© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter