Omniscia Alliance Block Audit

LibDiamond Code Style Findings

LibDiamond Code Style Findings

LDD-01C: Duplication of Code

TypeSeverityLocation
Gas OptimizationInformationalLibDiamond.sol:L130-L220

Description:

Certain notions and statements are replicated across these functions that can be better refactored into independent functions, like removeFunction.

Example:

contracts/libraries/LibDiamond.sol
130function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
131 require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
132 DiamondStorage storage ds = diamondStorage();
133 // uint16 selectorCount = uint16(diamondStorage().selectors.length);
134 require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
135 uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
136 // add new facet address if it does not exist
137 if (selectorPosition == 0) {
138 enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
139 ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
140 ds.facetAddresses.push(_facetAddress);
141 }
142 for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
143 bytes4 selector = _functionSelectors[selectorIndex];
144 address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
145 require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
146 ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
147 ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
148 ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
149 selectorPosition++;
150 }
151}
152
153function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
154 require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
155 DiamondStorage storage ds = diamondStorage();
156 require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
157 uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
158 // add new facet address if it does not exist
159 if (selectorPosition == 0) {
160 enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
161 ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
162 ds.facetAddresses.push(_facetAddress);
163 }
164 for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
165 bytes4 selector = _functionSelectors[selectorIndex];
166 address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
167 require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
168 removeFunction(oldFacetAddress, selector);
169 // add function
170 ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
171 ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
172 ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
173 selectorPosition++;
174 }
175}

Recommendation:

We advise them to be done so to ensure code maintainability and legibility.

Alleviation:

The addition of a new function was refactored into its dedicated function thus reducing the bytecode of the contract significantly, using the Diamond storage pointer in each instance to further reduce the gas required by the function.

LDD-02C: Inefficient Data Types

TypeSeverityLocation
Gas OptimizationInformationalLibDiamond.sol:L17, L22

Description:

The EVM is made to operate on 256-bit data types and as such, operations on less than that length will cost more gas due to the unpadding and padding operations performed.

Example:

contracts/libraries/LibDiamond.sol
15struct FacetAddressAndPosition {
16 address facetAddress;
17 uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
18}
19
20struct FacetFunctionSelectors {
21 bytes4[] functionSelectors;
22 uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
23}

Recommendation:

We advise the linked variables to be expanded to fill the remaining space of their already reserved slots to ensure less operations are needed at the EVM level. For the first link, this means (256 - address) -> (256 - 160) -> 96 and for the latter it means a full uint256 slot as it is "packed" with a dynamic array.

Alleviation:

The development team has acknowledged this exhibit but decided to not apply its remediation in the current version of the codebase citing time constraints.

LDD-03C: Inefficient Implementation

TypeSeverityLocation
Gas OptimizationInformationalLibDiamond.sol:L85-L104

Description:

The validateSignatures function ensures that no duplicate signatures exist by iterating through the previously computed signatures, computing them again and checking whether the signers equal the current signer.

Example:

contracts/libraries/LibDiamond.sol
95function validateSignatures(bytes32 ethHash, bytes[] memory signatures) internal view {
96 for (uint256 i = 0; i < signatures.length; i++) {
97 address signer = ECDSA.recover(ethHash, signatures[i]);
98 require(isMember(signer), "Router: invalid signer");
99 for (uint256 j = 0; j < i; j++) {
100 address signer2 = ECDSA.recover(ethHash, signatures[j]);
101 require(signer != signer2, "Router: duplicate signatures");
102 }
103 }
104}

Recommendation:

We advise an in-memory array to be declared at the start of the function with the same length as the signatures array that stores address and is assigned to on each iteration of the for loop, ensuring that the nested for loop will not re-compute ECDSA.recover and will instead access the in-memory array directly reducing the gas cost of the function.

Alleviation:

The membership-controlled contract implementation was replaced by a singular LibGovernance implementation thus no longer rendering this exhibit applicable.