Omniscia Boson Protocol Audit

GroupHandlerFacet Code Style Findings

GroupHandlerFacet Code Style Findings

GHF-01C: Inefficient mapping Lookups

TypeSeverityLocation
Gas OptimizationGroupHandlerFacet.sol:L113, L122, L127

Description:

The linked statements perform key-based lookup operations on mapping declarations from storage multiple times for the same key redundantly.

Example:

contracts/protocol/facets/GroupHandlerFacet.sol
111uint256 len = group.offerIds.length;
112//Get the index in the offerIds array, which is 1 less than the offerIdIndexByGroup index
113uint256 index = protocolLookups().offerIdIndexByGroup[groupId][offerId] - 1;
114
115if (index != len - 1) {
116 // if index == len - 1 then only pop and delete are needed
117 // Need to fill gap caused by delete if more than one element in storage array
118 uint256 offerIdToMove = group.offerIds[len - 1];
119 // Copy the last token in the array to this index to fill the gap
120 group.offerIds[index] = offerIdToMove;
121 //Reset index mapping. Should be index in offerIds array + 1
122 protocolLookups().offerIdIndexByGroup[groupId][offerIdToMove] = index + 1;
123}
124// Delete last offer id in the array, which was just moved to fill the gap
125group.offerIds.pop();
126// Delete from index mapping
127delete protocolLookups().offerIdIndexByGroup[groupId][offerId];

Recommendation:

As the lookups internally perform an expensive keccak256 operation, we advise the lookups to be cached wherever possible to a single local declaration that either holds the value of the mapping in case of primitive types or holds a storage pointer to the struct contained.

Alleviation (44009967e4f68092941d841e9e0f5dd2bb31bf0b):

The referenced mapping lookups have been optimized to the greatest extent possible thus greatly reducing the gas cost of the codebase.

GHF-02C: Repetitive Invocations of Getter Function

TypeSeverityLocation
Gas OptimizationGroupHandlerFacet.sol:L109, L113, L122, L127

Description:

The linked statements repetitively invoke the same getter function whilst its return value remains unchanged.

Example:

contracts/protocol/facets/GroupHandlerFacet.sol
101for (uint256 i = 0; i < _offerIds.length; i++) {
102 uint256 offerId = _offerIds[i];
103
104 // Offer should belong to the group
105 (, uint256 groupId) = getGroupIdByOffer(offerId);
106 require(_groupId == groupId, OFFER_NOT_IN_GROUP);
107
108 // remove groupIdByOffer mapping
109 delete protocolLookups().groupIdByOffer[offerId];
110
111 uint256 len = group.offerIds.length;
112 //Get the index in the offerIds array, which is 1 less than the offerIdIndexByGroup index
113 uint256 index = protocolLookups().offerIdIndexByGroup[groupId][offerId] - 1;
114
115 if (index != len - 1) {
116 // if index == len - 1 then only pop and delete are needed
117 // Need to fill gap caused by delete if more than one element in storage array
118 uint256 offerIdToMove = group.offerIds[len - 1];
119 // Copy the last token in the array to this index to fill the gap
120 group.offerIds[index] = offerIdToMove;
121 //Reset index mapping. Should be index in offerIds array + 1
122 protocolLookups().offerIdIndexByGroup[groupId][offerIdToMove] = index + 1;
123 }
124 // Delete last offer id in the array, which was just moved to fill the gap
125 group.offerIds.pop();
126 // Delete from index mapping
127 delete protocolLookups().offerIdIndexByGroup[groupId][offerId];
128}

Recommendation:

We advise the getter function to be invoked once and its result to be stored to a local variable that is consequently utilized optimizing the gas cost of the statements significantly.

Alleviation (44009967e4f68092941d841e9e0f5dd2bb31bf0b):

The protocol lookups are now correctly cached to local variable declarations thus optimizing the codebase's gas cost.