Omniscia Nori Audit
ScheduleUtils Code Style Findings
ScheduleUtils Code Style Findings
SUS-01C: Inefficient Cliff Total Evaluation
Type | Severity | Location |
---|---|---|
Gas Optimization | ![]() | ScheduleUtils.sol:L80-L93 |
Description:
The total cliff amount evaluation occurs on each cliff addition and contains an expensive iteration of all cliff periods and their amounts.
Example:
51/**52 * @dev Adds a cliff defined by *time* and *amount* to *schedule*53 *54 * *time* must be >= any existing cliff, >= schedule.startTime and <= schedule.endTime55 * *amount* must be <= (schedule.totalAmount - total of existing cliffs)56 */57function addCliff(58 Schedule storage schedule,59 uint256 time,60 uint256 amount61) internal {62 if (schedule.cliffCount == 0) {63 require(time >= schedule.startTime, "Cliff before schedule start");64 } else {65 require(66 time >= schedule.cliffs[schedule.cliffCount - 1].time,67 "Cliffs not chronological"68 );69 }70 require(time <= schedule.endTime, "Cliffs cannot end after schedule");71 require(72 allCliffAmounts(schedule) + amount <= schedule.totalAmount,73 "cliff amounts exceed total"74 );75 schedule.cliffs[schedule.cliffCount].time = time;76 schedule.cliffs[schedule.cliffCount].amount = amount;77 schedule.cliffCount += 1;78}79
80/**81 * @dev The sum of all cliff amounts in *schedule*82 */83function allCliffAmounts(Schedule storage schedule)84 internal85 view86 returns (uint256)87{88 uint256 cliffAmounts;89 for (uint256 i = 0; i < schedule.cliffCount; i++) {90 cliffAmounts += schedule.cliffs[i].amount;91 }92 return cliffAmounts;93}
Recommendation:
We advise the total to be tracked whenever a cliff is introduced instead, greatly optimizing the efficiency of the system.
Alleviation:
The total cliff amount is now correctly tracked in every addCliff
operation rendering the calculation of it redundant.
SUS-02C: Inefficient Loop Limit Evaluations
Type | Severity | Location |
---|---|---|
Gas Optimization | ![]() | ScheduleUtils.sol:L89, L104 |
Description:
The linked loop limit evaluations read a value from storage
on each iteration.
Example:
98function cliffAmountsAvailable(Schedule storage schedule, uint256 atTime)99 internal100 view101 returns (uint256)102{103 uint256 available = 0;104 for (uint256 i = 0; i < schedule.cliffCount; i++) {
Recommendation:
We advise their limit to instead be cached to a local variable that is consequently utilized greatly optimizing their gas cost.
Alleviation:
The first loop was omitted as part of another exhibit and the second loop was optimized as advised thereby alleviating this exhibit.
SUS-03C: Inefficient Usage of Signed Integers
Type | Severity | Location |
---|---|---|
Gas Optimization | ![]() | ScheduleUtils.sol:L135-L139 |
Description:
The linked statements make use of the int256
type to allow the subtraction to occur even when it goes to negative values in which case the value of 0
is yielded for linear amount available.
Example:
135int256 rampTimeElapsed = int256(atTime) - int256(rampStartTime);136return137 rampTimeElapsed <= 0138 ? 0139 : (rampTotalAmount * uint256(rampTimeElapsed)) / rampTotalTime;
Recommendation:
We advise an if
check to be utilized instead that checks whether atTime
is greater-than (>
) the value of rampStartTime
in which case the value of zero is returned, reducing the complexity and gas cost of the statements.
Alleviation:
The code was updated to utilize the existing ternary operator instead with a different conditional optimizing the codebase.
SUS-04C: Inefficient mapping
Lookups
Type | Severity | Location |
---|---|---|
Gas Optimization | ![]() | ScheduleUtils.sol:L75, L76, L105, L106 |
Description:
The linked statements contain duplicate mapping
entry lookups which could instead be cached to a local variable (i.e. for mapping(uint256 => Struct) foo
the statements foo[0].a = 0; foo[0].b = 1;
can be optimized to Struct storage bar = foo[0]; bar.a = 0; bar.b = 1;
).
Example:
75schedule.cliffs[schedule.cliffCount].time = time;76schedule.cliffs[schedule.cliffCount].amount = amount;
Recommendation:
We advise optimizations to be applied as outlined in the description.
Alleviation:
The mapping lookups were only optimized for the first instance thereby partially alleviating this exhibit.
SUS-05C: Redundant Duplicate Value Reads
Type | Severity | Location |
---|---|---|
Gas Optimization | ![]() | ScheduleUtils.sol:L62, L66, L75, L76, L77 |
Description:
The linked statements read schedule.cliffCount
from storage
multiple times redundantly.
Example:
57function addCliff(58 Schedule storage schedule,59 uint256 time,60 uint256 amount61) internal {62 if (schedule.cliffCount == 0) {63 require(time >= schedule.startTime, "Cliff before schedule start");64 } else {65 require(66 time >= schedule.cliffs[schedule.cliffCount - 1].time,67 "Cliffs not chronological"68 );69 }70 require(time <= schedule.endTime, "Cliffs cannot end after schedule");71 require(72 allCliffAmounts(schedule) + amount <= schedule.totalAmount,73 "cliff amounts exceed total"74 );75 schedule.cliffs[schedule.cliffCount].time = time;76 schedule.cliffs[schedule.cliffCount].amount = amount;77 schedule.cliffCount += 1;78}
Recommendation:
We advise its value to be cached to a local variable optimizing the code's execution cost.
Alleviation:
The code was optimized in all instances except the first if
conditional thereby partially alleviating this exhibit.