Omniscia Gravita Protocol Audit

StabilityPool Code Style Findings

StabilityPool Code Style Findings

SPL-01C: Inefficient Renunciation of Ownership

TypeSeverityLocation
Gas OptimizationStabilityPool.sol:L267

Description:

The StabilityPool::setAddresses function will invoke the OwnableUpgradeable::renounceOwnership function which in turn will apply the onlyOwner modifier redundantly.

Example:

contracts/StabilityPool.sol
242function setAddresses(
243 address _borrowerOperationsAddress,
244 address _vesselManagerAddress,
245 address _activePoolAddress,
246 address _debtTokenAddress,
247 address _sortedVesselsAddress,
248 address _communityIssuanceAddress,
249 address _adminContractAddress
250) external initializer override {
251 require(!isInitialized, "StabilityPool: Already initialized");
252
253 isInitialized = true;
254 __Ownable_init();
255 __ReentrancyGuard_init();
256
257 borrowerOperations = IBorrowerOperations(_borrowerOperationsAddress);
258 vesselManager = IVesselManager(_vesselManagerAddress);
259 activePool = IActivePool(_activePoolAddress);
260 debtToken = IDebtToken(_debtTokenAddress);
261 sortedVessels = ISortedVessels(_sortedVesselsAddress);
262 communityIssuance = ICommunityIssuance(_communityIssuanceAddress);
263 adminContract = IAdminContract(_adminContractAddress);
264
265 P = DECIMAL_PRECISION;
266
267 renounceOwnership();
268}

Recommendation:

We advise the OwnableUpgradeable::_transferOwnership function to be utilized directly, transferring ownership to the zero address.

Alleviation:

Ownership of the contract is no longer renounced in the latest iteration of the codebase rendering this exhibit inapplicable.

SPL-02C: Inefficient mapping Lookups

TypeSeverityLocation
Gas OptimizationStabilityPool.sol:L404, L405, L661, L662, L836, L838-L841, L852, L856-L859

Description:

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

Example:

contracts/StabilityPool.sol
392function _updateG(uint256 _GRVTIssuance) internal {
393 uint256 cachedTotalDebtTokenDeposits = totalDebtTokenDeposits; // cached to save an SLOAD
394 /*
395 * When total deposits is 0, G is not updated. In this case, the GRVT issued can not be obtained by later
396 * depositors - it is missed out on, and remains in the balanceof the CommunityIssuance contract.
397 *
398 */
399 if (cachedTotalDebtTokenDeposits == 0 || _GRVTIssuance == 0) {
400 return;
401 }
402 uint256 GRVTPerUnitStaked = _computeGRVTPerUnitStaked(_GRVTIssuance, cachedTotalDebtTokenDeposits);
403 uint256 marginalGRVTGain = GRVTPerUnitStaked.mul(P);
404 epochToScaleToG[currentEpoch][currentScale] = epochToScaleToG[currentEpoch][currentScale].add(marginalGRVTGain);
405 emit G_Updated(epochToScaleToG[currentEpoch][currentScale], currentEpoch, currentScale);
406}

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:

All but the first instance pair have been optimized per our recommendation, rendering this exhibit partially alleviated.

SPL-03C: Inexplicable Contract Member

TypeSeverityLocation
Gas OptimizationStabilityPool.sol:L174, L615-L616, L806-L807

Description:

The pendingCollGains member of the StabilityPool is utilized in multiple statements within the code, however, it results in a no-op as it remains filled with zero-values throughout its lifetime.

Example:

contracts/StabilityPool.sol
805// Reset pendingCollGains since those were all sent to the borrower
806Colls memory tempPendingCollGains;
807pendingCollGains[_to] = tempPendingCollGains;

Recommendation:

We advise it to be re-evaluated and potentially omitted, significantly improving the gas costs of the functions it was utilized in.

Alleviation:

The pendingCollGains contract member has been safely removed as advised.

SPL-04C: Inexplicable Ownable Pattern

TypeSeverityLocation
Gas OptimizationStabilityPool.sol:L254, L267

Description:

The StabilityPool inherits the OwnableUpgradeable implementation redundantly as it initializes it within the StabilityPool::setAddresses function and consequently renounces ownership in the same call.

Example:

contracts/StabilityPool.sol
242function setAddresses(
243 address _borrowerOperationsAddress,
244 address _vesselManagerAddress,
245 address _activePoolAddress,
246 address _debtTokenAddress,
247 address _sortedVesselsAddress,
248 address _communityIssuanceAddress,
249 address _adminContractAddress
250) external initializer override {
251 require(!isInitialized, "StabilityPool: Already initialized");
252
253 isInitialized = true;
254 __Ownable_init();
255 __ReentrancyGuard_init();
256
257 borrowerOperations = IBorrowerOperations(_borrowerOperationsAddress);
258 vesselManager = IVesselManager(_vesselManagerAddress);
259 activePool = IActivePool(_activePoolAddress);
260 debtToken = IDebtToken(_debtTokenAddress);
261 sortedVessels = ISortedVessels(_sortedVesselsAddress);
262 communityIssuance = ICommunityIssuance(_communityIssuanceAddress);
263 adminContract = IAdminContract(_adminContractAddress);
264
265 P = DECIMAL_PRECISION;
266
267 renounceOwnership();
268}

Recommendation:

We advise it to be removed, inheriting the Initializable implementation of OpenZeppelin instead which is properly put in use within the contract.

Alleviation:

The contract no longer utilizes or inherits the OwnableUpgradeable implementation, addressing this exhibit in full.

SPL-05C: Loop Iterator Optimizations

TypeSeverityLocation
Gas OptimizationStabilityPool.sol:L635, L794, L835, L849, L896, L924, L934

Description:

The linked for loops increment / decrement their iterator "safely" due to Solidity's built - in safe arithmetics (post-0.8.X).

Example:

contracts/StabilityPool.sol
635for (uint256 i = 0; i < assetsLen; ++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:

The loop iterator increments have been optimized as advised where applicable, however, their i++ counterpart is utilized instead of ++i. We advise the latter to be set in use as it is more optimal than the present code.

SPL-06C: Redundant Initialization Paradigm

TypeSeverityLocation
Gas OptimizationStabilityPool.sol:L250-L251, L253

Description:

The StabilityPool contract inherits the OpenZeppelin OwnableUpgradeable implementation which contains the Initializable implementation, put in use within the StabilityPool::setAddresses function. As such, the manual isInitialized flag is redundant.

Example:

contracts/StabilityPool.sol
242function setAddresses(
243 address _borrowerOperationsAddress,
244 address _vesselManagerAddress,
245 address _activePoolAddress,
246 address _debtTokenAddress,
247 address _sortedVesselsAddress,
248 address _communityIssuanceAddress,
249 address _adminContractAddress
250) external initializer override {
251 require(!isInitialized, "StabilityPool: Already initialized");
252
253 isInitialized = true;
254 __Ownable_init();
255 __ReentrancyGuard_init();
256
257 borrowerOperations = IBorrowerOperations(_borrowerOperationsAddress);
258 vesselManager = IVesselManager(_vesselManagerAddress);
259 activePool = IActivePool(_activePoolAddress);
260 debtToken = IDebtToken(_debtTokenAddress);
261 sortedVessels = ISortedVessels(_sortedVesselsAddress);
262 communityIssuance = ICommunityIssuance(_communityIssuanceAddress);
263 adminContract = IAdminContract(_adminContractAddress);
264
265 P = DECIMAL_PRECISION;
266
267 renounceOwnership();
268}

Recommendation:

We advise it and its validations to be omitted from the codebase as it is ineffectual and duplicates the purpose of the Initializable::initializer modifier.

Alleviation:

The manual initialization methodology has been removed from the contract as advised.

SPL-07C: Suboptimal Struct Declaration Style

TypeSeverityLocation
Code StyleStabilityPool.sol:L614

Description:

The linked declaration style of a struct is using index-based argument initialization.

Example:

contracts/StabilityPool.sol
614Colls(collateralsFromNewGains, amountsFromNewGains),

Recommendation:

We advise the key-value declaration format to be utilized instead, greatly increasing the legibility of the codebase.

Alleviation:

The referenced declaration of a struct is no longer present in the codebase, rendering this exhibit no longer applicable.