Omniscia Euler Finance Audit

ESynth Code Style Findings

ESynth Code Style Findings

ESH-01C: Ineffectual Usage of Safe Arithmetics

Description:

The linked mathematical operation is guaranteed to be performed safely by surrounding conditionals evaluated in either require checks or if-else constructs.

Example:

src/Synths/ESynth.sol
73minterCache.minted = minterCache.minted > amount ? minterCache.minted - uint128(amount) : 0; // down-casting is safe because amount < minted <= max uint128

Recommendation:

Given that safe arithmetics are toggled on by default in pragma versions of 0.8.X, we advise the linked statement to be wrapped in an unchecked code block thereby optimizing its execution cost.

Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):

The referenced subtraction has been wrapped in an unchecked code block safely, optimizing its gas cost.

ESH-02C: Inefficient Loop Limit Evaluation

Description:

The linked for loop evaluates its limit inefficiently on each iteration.

Example:

src/Synths/ESynth.sol
138for (uint256 i = 0; i < ignoredForTotalSupply.length(); i++) {

Recommendation:

We advise the statements within the for loop limit to be relocated outside to a local variable declaration that is consequently utilized for the evaluation to significantly reduce the codebase's gas cost. We should note the same optimization is applicable for storage reads present in such limits as they are newly read on each iteration (i.e. length members of arrays in storage).

Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):

The referenced loop limit evaluation (ignoredForTotalSupply.length()) has been properly cached outside the for loop to a dedicated local variable ignoredLength that is consequently utilized, optimizing the loop's gas cost significantly.

ESH-03C: Inefficient Structure Mutability Specifiers

TypeSeverityLocation
Gas OptimizationESynth.sol:L45, L55, L65, L74

Description:

The MinterData structures that are loaded in the ESynth::mint and ESynth::burn functions are declared as storage yet they are re-written to their respective mapping slot after being mutated.

Example:

src/Synths/ESynth.sol
40/// @notice Mints a certain amount of tokens to the account.
41/// @param account The account to mint the tokens to.
42/// @param amount The amount of tokens to mint.
43function mint(address account, uint256 amount) external nonReentrant {
44 address sender = _msgSender();
45 MinterData storage minterCache = minters[sender];
46
47 if (
48 amount > type(uint128).max - minterCache.minted
49 || minterCache.capacity < uint256(minterCache.minted) + amount
50 ) {
51 revert E_CapacityReached();
52 }
53
54 minterCache.minted += uint128(amount); // safe to down-cast because amount <= capacity <= max uint128
55 minters[sender] = minterCache;
56
57 _mint(account, amount);
58}
59
60/// @notice Burns a certain amount of tokens from the accounts balance. Requires the account, except the owner to have an allowance for the sender.
61/// @param account The account to burn the tokens from.
62/// @param amount The amount of tokens to burn.
63function burn(address account, uint256 amount) external nonReentrant {
64 address sender = _msgSender();
65 MinterData storage minterCache = minters[sender];
66
67 // The allowance check should be performed if the spender is not the account with the exception of the owner burning from this contract.
68 if (account != sender && !(account == address(this) && sender == owner())) {
69 _spendAllowance(account, sender, amount);
70 }
71
72 // If burning more than minted, reset minted to 0
73 minterCache.minted = minterCache.minted > amount ? minterCache.minted - uint128(amount) : 0; // down-casting is safe because amount < minted <= max uint128
74 minters[sender] = minterCache;
75
76 _burn(account, amount);
77}

Recommendation:

We advise both variables to be set as memory, optimizing the gas cost of each function to one SLOAD and one SSTORE operation.

Alleviation (fb2dd77a6ff9b7f710edb48e7eb5437e0db4fc1a):

The data locations of the two referenced local MinterData declarations have been properly updated to memory, optimizing each function's gas cost.

ESH-04C: Loop Iterator Optimization

Description:

The linked for loop increments / decrements the iterator "safely" due to Solidity's built-in safe arithmetics (post-0.8.X).

Example:

src/Synths/ESynth.sol
138for (uint256 i = 0; i < ignoredForTotalSupply.length(); i++) {

Recommendation:

We advise the increment / decrement operation to be performed in an unchecked code block as the last statement within the for loop to optimize its execution cost.

Alleviation (fb2dd77a6f):

The recommendation has been indirectly addressed due to the alleviation of exhibit ESH-02C and thus the optimizer's application.

To note, the original loop iterator was not optimized as the ignoredForTotalSupply.length() statement was considered dynamic and thus the optimizer did not assume the increment would be securely performed.

Alleviation (0f2192ac81):

After further testing of the proposed optimization, we concluded that the built-in optimizations of the Solidity compiler the project uses (0.8.23) would have covered the iterator case described in the exhibit per the official requirements of the optimization.

As such, we consider the optimization nullified as it would not have resulted in a gas reduction in its original form.