ID | Title | Category | Severity | Instances |
---|---|---|---|---|
[1] | The owner is a single point of failure and a centralization risk |
Centralization / Privilege | Low | 2 |
[2] | Void constructor | Coding Style | Low | 1 |
[3] | Unbounded loop | Control Flow | Low | 2 |
[4] | Use Ownable2Step's transfer function rather than Ownable's for transfers of ownership | Centralization / Privilege | Low | 1 |
[5] | onlyOwner functions not accessible if owner renounces ownership |
Centralization / Privilege | Low | 2 |
[6] | Minting tokens to the zero address should be avoided | Control Flow | Low | 1 |
[7] | Functions return bool true but cannot return false | Logical Issue | Low | 1 |
[8] | Solidity version 0.8.20 may not work on other chains due to PUSH0 |
Volatile Code | Low | 2 |
[1] | Functions guaranteed to revert when called by normal users can be marked payable |
Gas Optimization | Informational | 2 |
[2] | Floating pragma | Coding Style | Informational | 2 |
[3] | Unspecific compiler version pragma | Coding Style | Informational | 2 |
[4] | Use a more recent version of solidity | Coding Style | Informational | 2 |
[5] | Variables need not be initialized to zero | Coding Style | Informational | 2 |
[6] | Use a single file for all system-wide constants | Coding Style | Informational | 6 |
[7] | Not using the named return variables anywhere in the function is confusing | Coding Style | Informational | 2 |
[8] | Uppercase immutable variables | Coding Style | Informational | 1 |
[9] | Consider using named mappings | Coding Style | Informational | 3 |
[10] | Consider disabling renounceOwnership() |
Control Flow | Informational | 1 |
[11] | Consider bounding input array length | Control Flow | Informational | 2 |
[12] | Control structures do not follow the Solidity Style Guide | Coding Style | Informational | 8 |
[13] | Reduce gas usage by moving to Solidity 0.8.19 or later | Gas Optimization | Informational | 2 |
[14] | Event is not properly indexed | Coding Style | Informational | 1 |
[15] | Events may be emitted out of order due to reentranc | Logical Issue | Informational | 1 |
[16] | Cache array length outside of loop | Gas Optimization | Informational | 2 |
[17] | Functions guaranteed to revert when called by normal users can be marked payable | Gas Optimization | Informational | 2 |
[18] | >= costs less gas than > |
Gas Optimization | Informational | 4 |
[19] | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) |
Gas Optimization | Informational | 2 |
[20] | x += y/x -= y costs more gas than x = x + y/x = x - y for state variables |
Gas Optimization | Informational | 3 |
[21] | Don't initialize variables with default value | Gas Optimization | Informational | 2 |
[22] | Inverting the condition of an if-else-statement wastes gas | Gas Optimization | Informational | 1 |
[23] | ++i /i++ should be unchecked{++i} /unchecked{i++} when it is not possible for them to overflow, as is the case when used in for - and while -loops |
Gas Optimization | Informational | 2 |
[24] | Use constants instead of type(uintx).max |
Gas Optimization | Informational | 1 |
[25] | Use shift Right/Left instead of division/multiplication if possible | Gas Optimization | Informational | 5 |
[26] | Constructors can be marked payable |
Gas Optimization | Informational | 4 |
[27] | Reduce gas usage by moving to Solidity 0.8.19 or later | Gas Optimization | Informational | 2 |
[28] | Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate |
Gas Optimization | Informational | 3 |
[29] | Unnecessary cast | Gas Optimization | Informational | 2 |
[30] | Calling .length in a for loop wastes gas |
Gas Optimization | Informational | 2 |
[31] | unchecked {} can be used on the division of two uints in order to save gas |
Gas Optimization | Informational | 2 |
owner
is a single point of failure and a centralization riskHaving a single EOA as the only owner of contracts is a large centralization risk and a single point of failure. A single private key may be taken in a hack, or the sole holder of the key may become unable to retrieve the key when necessary. Consider changing to a multi-signature setup, or having a role-based authorization model.
DecentralizedStableCoin.sol#L46
DecentralizedStableCoin.sol#L57
Detect the call to a constructor that is not implemented.
DecentralizedStableCoin.sol#L44
While looping large collections, it's possible to run out of gas - causing a DOS condition
Ownable2Step
and Ownable2StepUpgradeable
prevent the contract ownership from mistakenly being transferred to an address that cannot handle it (e.g. due to a typo in the address), by requiring that the recipient of the owner permissions actively accept via a contract call of its own.
DecentralizedStableCoin.sol#L39
onlyOwner
functions not accessible if owner renounces ownershipThe owner is able to perform certain privileged activities, but it's possible to set the owner to address(0). This can represent a certain risk if the ownership is renounced for any other reason than by design. Renouncing ownership will leave the contract without an owner, therefore limiting any functionality that needs authority.
DecentralizedStableCoin.sol#L46
DecentralizedStableCoin.sol#L57
The core function mint is used by users to mint an option position by providing token1 as collateral and borrowing the max amount of liquidity. Address(0) check is missing in both this function and the internal function _mint, which is triggered to mint the tokens to the to address. Consider applying a check in the function to ensure tokens aren't minted to the zero address.
DecentralizedStableCoin.sol#L64
DecentralizedStableCoin.sol#L65
PUSH0
The compiler for Solidity 0.8.20 switches the default target EVM version to Shanghai, which includes the new PUSH0 op code. This op code may not yet be implemented on all L2s, so deployment on these chains will fail. To work around this issue, use an earlier EVM version
DecentralizedStableCoin.sol#L24
payable
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
DecentralizedStableCoin.sol#L46
DecentralizedStableCoin.sol#L57
use fixed solidity version
DecentralizedStableCoin.sol#L24
DecentralizedStableCoin.sol#L24
DecentralizedStableCoin.sol#L24
The default value for variables is zero, so initializing them to zero is superfluous.
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant in a library. If the variable is a local cache of another contract’s value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don’t get out of sync.
Consider changing the variable to be an unnamed one, since the variable is never assigned, nor is it returned by name. If the optimizer is not turned on, leaving the code as it is will also waste gas for the stack variable.
Variable does not follow Solidity naming best pratices
Consider moving to solidity version 0.8.18 or later, and using named mappings to make it easier to understand the purpose of each mapping.
renounceOwnership()
If the plan for your project does not include eventually giving up all ownership control, consider overwriting OpenZeppelin's Ownable's renounceOwnership() function in order to disable it.
DecentralizedStableCoin.sol#L39
The functions below take in an unbounded array, and make function calls for entries in the array. While the function will revert if it eventually runs out of gas, it may be a nicer user experience to require() that the length of the array is below some reasonable maximum, so that the user doesn't have to use up a full transaction's gas only to see that the transaction reverts.
See the control structures section of the Solidity Style Guide
DecentralizedStableCoin.sol#L48
DecentralizedStableCoin.sol#L61
See this link for the full details
DecentralizedStableCoin.sol#L24
The emitted events are not indexed, making off-chain scripts such as front-ends of dApps difficult to filter the events efficiently.
Ensure that events follow the best practice of check-effects-interaction, and are emitted before external calls
If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).
If a function modifier such as onlyOwner
is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.
DecentralizedStableCoin.sol#L46
DecentralizedStableCoin.sol#L57
>=
costs less gas than >
The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas
DecentralizedStableCoin.sol#L51
++i
costs less gas than i++
, especially when it's used in for
-loops (--i
/i--
too)Saves 5 gas per loop
x += y/x -= y
costs more gas than x = x + y/x = x - y
for state variablesUsing the addition operator instead of plus-equals saves 113 gas
If a variable is not initialized, it is assumed to have the default value. Explicitly initializing a variable with its default value costs unnecessary gas. For more info, see Mudit Gupta's Blog at point No need to initialize variables with default values
.
Flipping the true
and false
blocks instead saves 3 gas
++i
/i++
should be unchecked{++i}
/unchecked{i++}
when it is not possible for them to overflow, as is the case when used in for
- and while
-loopsThe unchecked
keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop
type(uintx).max
it uses more gas in the distribution process and also for each transaction than constant usage.
A division/multiplication by any number x being a power of 2 can be calculated by shifting log2(x) to the right/left. While the DIV opcode uses 5 gas, the SHR opcode only uses 3 gas. Furthermore, Solidity's division operation also includes a division-by-0 prevention which is bypassed using shifting.
payable
Payable functions cost less gas to execute, since the compiler does not have to add extra checks to ensure that a payment wasn't provided. A constructor can safely be marked as payable, since only the deployer would be able to pass funds, and the project itself would not pass any funds.
DecentralizedStableCoin.sol#L15
DecentralizedStableCoin.sol#L44
See this link for the full details
DecentralizedStableCoin.sol#L24
address/ID
mappings can be combined into a single mapping of an address/ID to a struct, where appropriateSaves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot.
.length
in a for loop wastes gasRather than calling .length for an array in a for loop declaration, it is far more gas efficient to cache this length before and use that instead. This will prevent the array length from being called every loop iteration
unchecked {}
can be used on the division of two uints
in order to save gasThe contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.