Omniscia Avant Protocol Audit

StakedAvUSDV2 Code Style Findings

StakedAvUSDV2 Code Style Findings

SAS-01C: Inefficient Event Emittance

Description:

The StakedAvUSDV2::setCooldownDuration function will inefficiently emit the CooldownDurationUpdated event as it will store a local variable redundantly and emit a value from storage.

Example:

contracts/StakedAvUSDV2.sol
121/// @notice Set cooldown duration. If cooldown duration is set to zero, the StakedAvUSDV2 behavior changes to follow ERC4626 standard and disables cooldownShares and cooldownAssets methods. If cooldown duration is greater than zero, the ERC4626 withdrawal and redeem functions are disabled, breaking the ERC4626 standard, and enabling the cooldownShares and the cooldownAssets functions.
122/// @param duration Duration of the cooldown
123function setCooldownDuration(uint24 duration) external onlyRole(DEFAULT_ADMIN_ROLE) {
124 if (duration > MAX_COOLDOWN_DURATION) {
125 revert InvalidCooldown();
126 }
127
128 uint24 previousDuration = cooldownDuration;
129 cooldownDuration = duration;
130 emit CooldownDurationUpdated(previousDuration, cooldownDuration);
131}

Recommendation:

We advise the event to be emitted prior to the cooldownDuration assignment, permitting the first argument to be the cooldownDuration data entry directly and the second argument to be the input duration, optimizing the function's gas cost.

Alleviation:

The event's emission was updated to utilize the in-memory duration variable, optimizing its gas cost.

SAS-02C: Inefficient mapping Lookups

Description:

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

Example:

contracts/StakedAvUSDV2.sol
95/// @notice redeem assets and starts a cooldown to claim the converted underlying asset
96/// @param assets assets to redeem
97function cooldownAssets(uint256 assets) external ensureCooldownOn returns (uint256 shares) {
98 if (assets > maxWithdraw(msg.sender)) revert ExcessiveWithdrawAmount();
99
100 shares = previewWithdraw(assets);
101
102 cooldowns[msg.sender].cooldownEnd = uint104(block.timestamp) + cooldownDuration;
103 cooldowns[msg.sender].underlyingAmount += uint152(assets);
104
105 _withdraw(msg.sender, address(silo), msg.sender, assets, shares);
106}
107
108/// @notice redeem shares into assets and starts a cooldown to claim the converted underlying asset
109/// @param shares shares to redeem
110function cooldownShares(uint256 shares) external ensureCooldownOn returns (uint256 assets) {
111 if (shares > maxRedeem(msg.sender)) revert ExcessiveRedeemAmount();
112
113 assets = previewRedeem(shares);
114
115 cooldowns[msg.sender].cooldownEnd = uint104(block.timestamp) + cooldownDuration;
116 cooldowns[msg.sender].underlyingAmount += uint152(assets);
117
118 _withdraw(msg.sender, address(silo), msg.sender, assets, shares);
119}

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.

As the compiler's optimizations may take care of these caching operations automatically at-times, we advise the optimization to be selectively applied, tested, and then fully adopted to ensure that the proposed caching model indeed leads to a reduction in gas costs.

Alleviation:

All referenced inefficient mapping lookups have been optimized to the greatest extent possible, significantly reducing the gas cost of the functions the statements were located in.