Shell Protocol - 0xVolcano's results

Shell Protocol is DeFi made simple. Enjoy powerful one-click transactions, unbeatably capital-efficient AMMs, and a modular developer experience.

General Information

Platform: Code4rena

Start Date: 27/11/2023

Pot Size: $36,500 USDC

Total HM: 0

Participants: 22

Period: 8 days

Judge: 0xA5DF

Id: 308

League: ETH

Shell Protocol

Findings Distribution

Researcher Performance

Rank: 12/22

Findings: 1

Award: $72.79

Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: hunter_w3b

Also found by: 0x11singh99, 0xVolcano, IllIllI, Sathish9098

Labels

bug
G (Gas Optimization)
grade-b
insufficient quality report
G-03

Awards

72.7885 USDC - $72.79

External Links

Table of Contents

Pack variables together(Save 1 SLOT: 2100 Gas)

https://github.com/code-423n4/2023-11-shellprotocol/blob/485de7383cdf88284ee6bcf2926fb7c19e9fb257/src/ocean/Ocean.sol#L108-L109

File: /src/ocean/Ocean.sol
108:    uint256 _ERC1155InteractionStatus;
109:    uint256 _ERC721InteractionStatus;

The above two variables are set in the following https://github.com/code-423n4/2023-11-shellprotocol/blob/485de7383cdf88284ee6bcf2926fb7c19e9fb257/src/ocean/Ocean.sol#L169-L174

169:    constructor(string memory uri_) OceanERC1155(uri_) {
170:        unwrapFeeDivisor = type(uint256).max;
171:        _ERC1155InteractionStatus = NOT_INTERACTION;
172:        _ERC721InteractionStatus = NOT_INTERACTION;
173:        WRAPPED_ETHER_ID = _calculateOceanId(address(0x4574686572), 0); // hexadecimal(ascii("Ether"))
174:    }

Note, we are assigning them values of NOT_INTERACTION which is a constant variable with value 1. The other place we assign them is in the function _erc1155Wrap() where we now use the variable INTERACTION which is a constant variable with value 1 We can safely reduce their size from uint256 to uint128 since the only two values we ever set are 1 and 2

diff --git a/src/ocean/Ocean.sol b/src/ocean/Ocean.sol
index 1b687be..d3ac600 100644
--- a/src/ocean/Ocean.sol
+++ b/src/ocean/Ocean.sol
@@ -105,8 +105,8 @@ contract Ocean is IOceanInteractions, IOceanFeeChange, OceanERC1155, IERC721Rece
     /// @dev adapted from OpenZeppelin Reentrancy Guard
     uint256 constant NOT_INTERACTION = 1;
     uint256 constant INTERACTION = 2;
-    uint256 _ERC1155InteractionStatus;
-    uint256 _ERC721InteractionStatus;
+    uint128 _ERC1155InteractionStatus;
+    uint128 _ERC721InteractionStatus;

     event ChangeUnwrapFee(uint256 oldFee, uint256 newFee, address sender);
     event Erc20Wrap(

No need to assign default values to struct(not similar to what the bot reported)

https://github.com/code-423n4/2023-11-shellprotocol/blob/485de7383cdf88284ee6bcf2926fb7c19e9fb257/src/adapters/CurveTricryptoAdapter.sol#L118-L140

File: /src/adapters/CurveTricryptoAdapter.sol
118:    function wrapToken(uint256 tokenId, uint256 amount) internal override {
119:        Interaction memory interaction;

121:        if (tokenId == zToken) {
122:            interaction = Interaction({
123:                interactionTypeAndAddress: 0,
124:                inputToken: 0,
125:                outputToken: 0,
126:                specifiedAmount: 0,
127:                metadata: bytes32(0)
128:            });
129:            IOceanInteractions(ocean).doInteraction{ value: amount }(interaction);
130:        } else {
131:            interaction = Interaction({
132:                interactionTypeAndAddress: _fetchInteractionId(underlying[tokenId], uint256(InteractionType.WrapErc20)),
133:                inputToken: 0,
134:                outputToken: 0,
135:                specifiedAmount: amount,
136:                metadata: bytes32(0)
137:            });
138:            IOceanInteractions(ocean).doInteraction(interaction);
139:        }
140:    }

We are defining a variable of type Interaction which is a struct. At no point is this struct being stored in storage so any values assigned only last inside the blocks they are assigned. This means that , every time the struct is being used, we start off at the default values of all variables in the struct, there is no need therefore to assign the same default value

@@ -119,22 +119,11 @@ contract CurveTricryptoAdapter is OceanAdapter {
         Interaction memory interaction;

         if (tokenId == zToken) {
-            interaction = Interaction({
-                interactionTypeAndAddress: 0,
-                inputToken: 0,
-                outputToken: 0,
-                specifiedAmount: 0,
-                metadata: bytes32(0)
-            });
             IOceanInteractions(ocean).doInteraction{ value: amount }(interaction);
         } else {
-            interaction = Interaction({
-                interactionTypeAndAddress: _fetchInteractionId(underlying[tokenId], uint256(InteractionType.WrapErc20)),
-                inputToken: 0,
-                outputToken: 0,
-                specifiedAmount: amount,
-                metadata: bytes32(0)
-            });
+            interaction.interactionTypeAndAddress = _fetchInteractionId(underlying[tokenId], uint256(InteractionType.WrapErc20));
+            interaction.specifiedAmount = amount;
+
             IOceanInteractions(ocean).doInteraction(interaction);
         }
     }

https://github.com/code-423n4/2023-11-shellprotocol/blob/485de7383cdf88284ee6bcf2926fb7c19e9fb257/src/adapters/CurveTricryptoAdapter.sol#L147-L169

File: /src/adapters/CurveTricryptoAdapter.sol
147:    function unwrapToken(uint256 tokenId, uint256 amount) internal override {
148:        Interaction memory interaction;

150:        if (tokenId == zToken) {
151:            interaction = Interaction({
152:                interactionTypeAndAddress: _fetchInteractionId(address(0), uint256(InteractionType.UnwrapEther)),
153:                inputToken: 0,
154:                outputToken: 0,
155:                specifiedAmount: amount,
156:                metadata: bytes32(0)
157:            });
158:        } else {
159:            interaction = Interaction({
160:                interactionTypeAndAddress: _fetchInteractionId(underlying[tokenId], uint256(InteractionType.UnwrapErc20)),
161:                inputToken: 0,
162:                outputToken: 0,
163:                specifiedAmount: amount,
164:                metadata: bytes32(0)
165:            });
166:        }

168:        IOceanInteractions(ocean).doInteraction(interaction);
169:    }
      * @dev unwraps the underlying token from the Ocean
@@ -148,21 +148,13 @@ contract CurveTricryptoAdapter is OceanAdapter {
         Interaction memory interaction;

         if (tokenId == zToken) {
-            interaction = Interaction({
-                interactionTypeAndAddress: _fetchInteractionId(address(0), uint256(InteractionType.UnwrapEther)),
-                inputToken: 0,
-                outputToken: 0,
-                specifiedAmount: amount,
-                metadata: bytes32(0)
-            });
+                interaction.interactionTypeAndAddress = _fetchInteractionId(address(0), uint256(InteractionType.UnwrapEther));
+                interaction.specifiedAmount = amount;
+
         } else {
-            interaction = Interaction({
-                interactionTypeAndAddress: _fetchInteractionId(underlying[tokenId], uint256(InteractionType.UnwrapErc20)),
-                inputToken: 0,
-                outputToken: 0,
-                specifiedAmount: amount,
-                metadata: bytes32(0)
-            });
+                interaction.interactionTypeAndAddress = _fetchInteractionId(underlying[tokenId], uint256(InteractionType.UnwrapErc20));
+                interaction.specifiedAmount = amount;
+
         }

         IOceanInteractions(ocean).doInteraction(interaction);

Similar scenarios

https://github.com/code-423n4/2023-11-shellprotocol/blob/485de7383cdf88284ee6bcf2926fb7c19e9fb257/src/adapters/Curve2PoolAdapter.sol#L102-L114

File: /src/adapters/Curve2PoolAdapter.sol
102:    function wrapToken(uint256 tokenId, uint256 amount) internal override {
103:        address tokenAddress = underlying[tokenId];

105:        Interaction memory interaction = Interaction({
106:            interactionTypeAndAddress: _fetchInteractionId(tokenAddress, uint256(InteractionType.WrapErc20)),
107:            inputToken: 0,
108:            outputToken: 0,
109:            specifiedAmount: amount,
110:            metadata: bytes32(0)
111:        });

113:        IOceanInteractions(ocean).doInteraction(interaction);
114:    }

https://github.com/code-423n4/2023-11-shellprotocol/blob/485de7383cdf88284ee6bcf2926fb7c19e9fb257/src/adapters/Curve2PoolAdapter.sol#L121-L133

File: /src/adapters/Curve2PoolAdapter.sol
121:    function unwrapToken(uint256 tokenId, uint256 amount) internal override {
122:        address tokenAddress = underlying[tokenId];

124:        Interaction memory interaction = Interaction({
125:            interactionTypeAndAddress: _fetchInteractionId(tokenAddress, uint256(InteractionType.UnwrapErc20)),
126:            inputToken: 0,
127:            outputToken: 0,
128:            specifiedAmount: amount,
129:            metadata: bytes32(0)
130:        });

132:        IOceanInteractions(ocean).doInteraction(interaction);
133:    }

#0 - c4-pre-sort

2023-12-10T17:14:55Z

raymondfam marked the issue as insufficient quality report

#1 - 0xA5DF

2023-12-14T16:17:04Z

The first finding seems significant, can save 2000 gas in some txs (when a user wraps both types in the same tx)

#2 - c4-judge

2023-12-17T09:35:49Z

0xA5DF 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