Notional x Index Coop - ellahi's results

A collaboration between Notional and Index Coop to create fixed rate yield index tokens.

General Information

Platform: Code4rena

Start Date: 07/06/2022

Pot Size: $75,000 USDC

Total HM: 11

Participants: 77

Period: 7 days

Judge: gzeon

Total Solo HM: 7

Id: 124

League: ETH

Notional

Findings Distribution

Researcher Performance

Rank: 36/77

Findings: 2

Award: $136.79

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Low

[L-01] Unspecific Compiler Version Pragma

Impact

A known vulnerable compiler version may accidentally be selected or security tools might fall-back to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain.

Proof of Concept
  wfCashERC4626.sol::2 => pragma solidity ^0.8.0;
Recommendation

Avoid floating pragmas for non-library contracts. It is recommended to pin to a concrete compiler version.

[L-02] Do not use Deprecated Library Functions

Impact

The usage of deprecated library functions should be discouraged.

Proof of Concept
  wfCashBase.sol::68 => assetToken.safeApprove(address(NotionalV2), type(uint256).max);
  wfCashBase.sol::73 => underlyingToken.safeApprove(address(NotionalV2), type(uint256).max);
Recommendation

Use safeIncreaseAllowance / safeDecreaseAllowance instead of safeApprove.

Non-Critical

[N-01] Missing Natspec

Missing @return natspec throughout the codebase

Tools used

manual

Gas

[G-01] Unnecessary variable assignment.

Impact

If a variable is not set/initialized, it is assumed to have the default value (0, false, 0x0 etc depending on the data type). Explicitly initializing it with its default value is an anti-pattern and wastes gas.

Proof of Concept
  NotionalTradeModule.sol::238 => for(uint256 i = 0; i < modules.length; i++) {
  NotionalTradeModule.sol::254 => for(uint256 i = 0; i < modules.length; i++) {
  NotionalTradeModule.sol::393 => for(uint256 i = 0; i < positionsLength; i++) {
  NotionalTradeModule.sol::519 => uint32 minImpliedRate = 0;
  NotionalTradeModule.sol::605 => for(uint256 i = 0; i < positionsLength; i++) {
  NotionalTradeModule.sol::618 => for(uint256 i = 0; i < positionsLength; i++) {
Recommendation

Remove explicit zero initialization.

[G-02] Contracts using unlocked pragma.

Impact

Contracts in scope use pragma solidity ^0.8.0, allowing wide enough range of versions.

Proof of Concept
  wfCashERC4626.sol::2 => pragma solidity ^0.8.0;
Recommendation

Consider locking compiler version, for example pragma solidity 0.8.6. This can have additional benefits, for example using custom errors to save gas and so forth.

[G-03] Reduce the size of error messages (Long revert Strings).

Impact

Shortening revert strings to fit in 32 bytes will decrease deployment time gas and will decrease runtime gas when the revert condition is met. Revert strings that are longer than 32 bytes require at least one additional mstore, along with additional overhead for computing memory offset, etc.

Proof of Concept
  NotionalTradeModule.sol::169 => require(_setToken.isComponent(address(_sendToken)), "Send token must be an index component");
  NotionalTradeModule.sol::199 => require(_setToken.isComponent(address(wrappedfCash)), "FCash to redeem must be an index component");
  NotionalTradeModule.sol::378 => require(wrappedfCashAddress.isContract(), "WrappedfCash not deployed for given parameters");
  NotionalTradeModule.sol::573 => require(_paymentToken == assetToken, "Token is neither asset nor underlying token");
Recommendation

Shorten the revert strings to fit in 32 bytes, or use custom errors if >0.8.4.

[G-04] Cache Array Length Outside of Loop.

Impact

Reading array length at each iteration of the loop takes 6 gas (3 for mload and 3 to place memory_offset) in the stack. Caching the array length in the stack saves around 3 gas per iteration.

Proof of Concept
  NotionalTradeModule.sol::238 => for(uint256 i = 0; i < modules.length; i++) {
  NotionalTradeModule.sol::254 => for(uint256 i = 0; i < modules.length; i++) {
Recommendation

Store the array’s length in a variable before the for-loop.

[G-05] ++i costs less gas compared to i++ or i += 1

Impact

++i costs less gas compared to i++ or i += 1 for unsigned integer, as pre-increment is cheaper (about 5 gas per iteration). This statement is true even with the optimizer enabled.

Proof of Concept
  NotionalTradeModule.sol::238 => for(uint256 i = 0; i < modules.length; i++) {
  NotionalTradeModule.sol::254 => for(uint256 i = 0; i < modules.length; i++) {
  NotionalTradeModule.sol::393 => for(uint256 i = 0; i < positionsLength; i++) {
  NotionalTradeModule.sol::605 => for(uint256 i = 0; i < positionsLength; i++) {
  NotionalTradeModule.sol::618 => for(uint256 i = 0; i < positionsLength; i++) {
Recommendation

Use ++i instead of i++ to increment the value of an uint variable. Same thing for --i and i--.

Tools used

c4udit, manual

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter