Omniscia 0xPhase Audit
DBV1 Code Style Findings
DBV1 Code Style Findings
DBV-01C: Inefficient Assignments of State
Type | Severity | Location |
---|---|---|
Gas Optimization | DBV1.sol:L45, L207 |
Description:
The referenced assignments of state are performed within a for
loop instead of being performed outside of it.
Example:
199function add(bytes32[] memory keys, bytes32 value) public override onlyOwner {200 Set storage valueSet = _values[value];201
202 for (uint256 i = 0; i < keys.length; i++) {203 bytes32 key = keys[i];204 Set storage keySet = _keys[key];205
206 keySet.exists = true;207 valueSet.exists = true;208
209 keySet.list.add(value);210 valueSet.list.add(key);211 }212
213 _valueList.add(value);214}
Recommendation:
We advise them to be relocated outside the for
loop and executed solely when each loop will iterate at least once (i.e. the loop's length
limit is non-zero), optimizing the codebase.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The exists
value of the valueSet
is now optimally set to true
by using the condition we advised and relocating its assignment outside the for
loop.
DBV-02C: Inefficient Iteration of Expected Results
Type | Severity | Location |
---|---|---|
Gas Optimization | DBV1.sol:L118-L132 |
Description:
The DBV1::digest
function will first identify the total items it is expected to yield and then iterate them and store their value in the result
array.
Example:
110/// @inheritdoc IDB111function digest(112 Opcode memory opcode113) external view override returns (bytes32[] memory result) {114 uint256 length = _valueList.length();115 uint256[] memory digested = _digest(opcode);116 uint256 totalTruthy = 0;117
118 for (uint256 i = 0; i < length; i++) {119 if (digested[i] > 0) {120 totalTruthy++;121 }122 }123
124 uint256 counter = 0;125 result = new bytes32[](totalTruthy);126
127 for (uint256 i = 0; i < length; i++) {128 if (digested[i] > 0) {129 result[counter] = _valueList.at(i);130 counter++;131 }132 }133}
Recommendation:
We advise the code to directly store the values to the result
array, instantiating it at the maximum possible values desired (i.e. length
). Once the for
loop concludes, the code can use an assembly
block to mutate the result
array's size safely to the actual amount of values identified as digested.
To note, this is solely possible because downsizing an in-memory array is safe when performed in an assembly
block in Solidity.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The optimization has been applied as advised, greatly reducing the gas cost of the DBV1::digest
function and requiring only a single array iteration and instantiation.
DBV-03C: Loop Iterator Optimizations
Type | Severity | Location |
---|---|---|
Gas Optimization | DBV1.sol:L41, L60, L118, L127, L161, L178, L202, L297, L301, L308, L312, L324, L335, L338, L361, L385, L388 |
Description:
The linked for
loops increment / decrement their iterator "safely" due to Solidity's built - in safe arithmetics (post-0.8.X
).
Example:
41for (uint256 i = 0; i < values.length; i++) {
Recommendation:
We advise the increment / decrement operations to be performed in an unchecked
code block as the last statement within each for
loop to optimize their execution cost.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
All referenced loop iterators have been optimized as advised, removing their for
declaration increment statement and instead performing it in an unchecked
code block wherever needed (i.e. before a continue
statement or at the end of the for
loop's body).
DBV-04C: Redundant Instantiations of Arrays
Type | Severity | Location |
---|---|---|
Gas Optimization | DBV1.sol:L154, L171 |
Description:
The referenced instantiations of empty arrays are redundant given that each function these instances are in contains an explicitly named return argument of the same type.
Example:
149/// @inheritdoc IDB150function getValues(151 bytes32 key152) external view override returns (bytes32[] memory arr) {153 Set storage keySet = _keys[key];154 if (!keySet.exists) return new bytes32[](0);
Recommendation:
We advise the named return argument to be yielded directly (i.e. return arr
) as uninitialized variables are by default set to their "empty" state.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The redundant instantiations of in-memory arrays have been safely replaced by the named return variables as advised, optimizing each function's gas cost.