Issue | Contexts | |
---|---|---|
NC‑1 | Array lengths not checked | 1 |
NC‑2 | Avoid Floating Pragmas: The Version Should Be Locked | 9 |
NC‑3 | Condition will not revert when block.timestamp is == to the compared variable |
1 |
NC‑4 | Consider adding a deny-list | 1 |
NC‑5 | Consider disabling renounceOwnership() |
7 |
NC‑6 | Consider using named mappings | 4 |
NC‑7 | Constants Should Be Defined Rather Than Using Magic Numbers | 2 |
NC‑8 | Constants in comparisons should appear on the left side | 2 |
NC‑9 | Contract does not follow the Solidity style guide's suggested layout ordering | 1 |
NC‑10 | Critical Changes Should Use Two-step Procedure | 4 |
NC‑11 | Custom error has no error details | 15 |
NC‑12 | Declare interfaces on separate files | 1 |
NC‑13 | Empty bytes check is missing |
8 |
NC‑14 | File is missing NatSpec | 5 |
NC‑15 | Function names should differ to make the code more readable | 2 |
NC‑16 | Function must not be longer than 50 lines | 4 |
NC‑17 | Functions that alter state should emit events | 3 |
NC‑18 | Use delete to Clear Variables |
1 |
NC‑19 | No need to initialize uints to zero | 2 |
NC‑20 | Initial value check is missing in Set Functions | 3 |
NC‑21 | Interfaces should be indicated with an I prefix in the contract name |
1 |
NC‑22 | internal functions not called by the contract should be removed |
2 |
NC‑23 | Long functions should be refactored into multiple, smaller, functions | 2 |
NC‑24 | NatSpec comments should be increased in contracts | 2 |
NC‑25 | NatSpec @return argument is missing |
1 |
NC‑26 | Non-usage of specific imports | 4 |
NC‑27 | Use the latest solidity (prior to 0.8.20 if on L2s) for deployment | 9 |
NC‑28 | Operations such as the changing of the owner should be behind a timelock | 1 |
NC‑29 | Overly complicated arithmetic | 1 |
NC‑30 | It is standard for all external and public functions to be overridden from an interface | 27 |
NC‑31 | uint variables should have the bit size defined explicitly |
2 |
NC‑32 | Unused struct definition |
1 |
NC‑33 | Large multiples of ten should use scientific notation | 6 |
NC‑34 | Use SMTChecker | 1 |
NC‑35 | Use Underscores for Number Literals | 6 |
NC‑36 | Zero as a function argument should have a descriptive meaning | 1 |
Total: 143 contexts over 36 issues
If the length of the arrays are not required to be of the same length, user operations may not be fully executed
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L355
Avoid floating pragmas for non-library contracts.
While floating pragmas make sense for libraries to allow them to be included with multiple different versions of applications, it may be a security risk for application implementations.
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.
It is recommended to pin to a concrete compiler version.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/interfaces/IERC20.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/interfaces/ISwapRouter.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Errors.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Structs.sol#L2
block.timestamp
is ==
to the compared variableThe condition does not revert when block.timestamp is equal to the compared >
or <
variable. For example, if there is a check for block.timestamp > loan.auctionStartTimestamp + loan.auctionLength
then there should be a check for cases where block.timestamp
is ==
to loan.auctionStartTimestamp + loan.auctionLength
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L471
Doing so will significantly increase centralization, but will help to prevent hackers from using stolen tokens
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L9
renounceOwnership()
Typically, the contract's owner is the account that deploys the contract. As a result, the owner is able to perform certain privileged activities. The OpenZeppelin's Ownable
is used in this project contract implements renounceOwnership
. 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, thereby removing any functionality that is only available to the owner.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L9
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L11
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L10
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L73
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L11
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L31
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L4
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
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L70
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L19
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L22
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L24
Even assembly can benefit from using readable constants instead of hex/numeric literals
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L85
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L93
Doing so will prevent typo bugs
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L212
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L244
The style guide says that, within a contract, the ordering should be 1) Type declarations, 2) State variables, 3) Events, 4) Errors 5) Modifiers, and 6) Functions, but the contract(s) below do not follow this ordering
The critical procedures should be two step process.
See similar findings in previous Code4rena contests for reference:
https://code4rena.com/reports/2022-06-illuminate/#2-critical-changes-should-use-two-step-procedure
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L84
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L92
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L100
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L130
Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.
Consider adding parameters to the error to indicate which user or values caused the failure
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Errors.sol#L4-L18
Interfaces should be declared on a separate file and not on the same file where the contract resides in.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L7
bytes
check is missingTo avoid mistakenly accepting empty bytes
as a valid value, consider to check for empty bytes
. This helps ensure that empty bytes
are not treated as valid inputs, preventing potential issues.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L182
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L198
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L210
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L221
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L355
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L356
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L465
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L732
In Solidity, while function overriding allows for functions with the same name to coexist, it is advisable to avoid this practice to enhance code readability and maintainability. Having multiple functions with the same name, even with different parameters or in inherited contracts, can cause confusion and increase the likelihood of errors during development, testing, and debugging. Using distinct and descriptive function names not only clarifies the purpose and behavior of each function, but also helps prevent unintended function calls or incorrect overriding. By adopting a clear and consistent naming convention, developers can create more comprehensible and maintainable smart contracts.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L8
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L53
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L232
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L355
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L465
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L591
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L84
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L92
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L100
delete
to Clear Variablesdelete a
assigns the initial value for the type to a
. i.e. for integers it is equivalent to a = 0
, but it can also be used on arrays, where it assigns a dynamic array of length zero or a static array of the same length with all elements reset. For structs, it assigns a struct with all members reset. Similarly, it can also be used to set an address to zero address. It has no effect on whole mappings though (as the keys of mappings may be arbitrary and are generally unknown). However, individual keys and what they map to can be deleted: If a
is a mapping, then delete a[x]
will delete the value stored at x
.
The delete
key better conveys the intention and is also more idiomatic. Consider replacing assignments of zero with delete
statements.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L56
There is no need to initialize uint
variables to zero as their default value is 0
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L14
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L16
A check regarding whether the current value and the new value are the same should be added
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L84
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L92
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L100
I
prefix in the contract namehttps://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L7
internal
functions not called by the contract should be removedhttps://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L15
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L29
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L355
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L591
It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI). It is clearly stated in the Solidity official documentation. In complex projects such as Defi, the interpretation of all functions and their arguments and returns is important for code readability and auditability. https://docs.soliditylang.org/en/v0.8.15/natspec-format.html
NatSpec comments should be increased in contracts
@return
argument is missinghttps://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L127
The current form of relative path import is not recommended for use because it can unpredictably pollute the namespace.
Instead, the Solidity docs recommend specifying imported symbols explicitly.
https://docs.soliditylang.org/en/v0.8.15/layout-of-source-files.html#importing-other-source-files
A good example:
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L4-L5
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L4-L5
Use specific imports syntax per solidity docs recommendation.
When deploying contracts, you should use the latest released version of Solidity. Apart from exceptional cases, only the latest version receives security fixes.
Assembler: Use push0 for placing 0 on the stack for EVM versions starting from “Shanghai”. This decreases the deployment and runtime costs.
EVM: Set default EVM version to “Shanghai”.
EVM: Support for the EVM Version “Shanghai”.
Optimizer: Re-implement simplified version of UnusedAssignEliminator and UnusedStoreEliminator. It can correctly remove some unused assignments in deeply nested loops that were ignored by the old version.
Parser: Unary plus is no longer recognized as a unary operator in the AST and triggers an error at the parsing stage (rather than later during the analysis).
SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option --model-checker-show-unsupported and the JSON option settings.modelChecker.showUnsupported can be enabled to show the full list.
SMTChecker: Properties that are proved safe are now reported explicitly at the end of analysis. By default, only the number of safe properties is shown. The CLI option --model-checker-show-proved-safe and the JSON option settings.modelChecker.showProvedSafe can be enabled to show the full list of safe properties.
Standard JSON Interface: Add experimental support for importing ASTs via Standard JSON.
Yul EVM Code Transform: If available, use push0 instead of codesize to produce an arbitrary value on stack in order to create equal stack heights between branches.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/interfaces/IERC20.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/interfaces/ISwapRouter.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Errors.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L2
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Structs.sol#L2
Consider updating to a more recent solidity version.
From the point of view of a user, the changing of the owner of a contract is a high risk operation that may have outcomes ranging from an attacker gaining control over the protocol, to the function no longer functioning due to a typo in the destination address. To give users plenty of warning so that they can validate any ownership changes, changes of ownership should be behind a timelock.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L19
To maintain readability in code, particularly in Solidity which can involve complex mathematical operations, it is often recommended to limit the number of arithmetic operations to a maximum of 2-3 per line. Too many operations in a single line can make the code difficult to read and understand, increase the likelihood of mistakes, and complicate the process of debugging and reviewing the code. Consider splitting such operations over more than one line, take special care when dealing with division however. Try to limit the number of arithmetic operations to a maximum of 3 per line.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L724
Check that all public or external functions are override. This is iseful to make sure that the whole API is extracted in an interface.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Beedle.sol#L36
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L26
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L84
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L92
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L100
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L108
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L116
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L130
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L182
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L198
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L210
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L221
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L232
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L292
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L355
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L437
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L465
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L540
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L548
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L591
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L8
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L38
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L46
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L53
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L61
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L80
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Ownable.sol#L19
uint
variables should have the bit size defined explicitlyInstead of using uint
to declare uint256
, explicitly define uint256
to ensure there is no confusion
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L38
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Staking.sol#L46
struct
definitionNote that there may be cases where a struct superficially appears to be used, but this is only because there are multiple definitions of the struct in different files. In such cases, the struct definition should be moved into a separate file. The instances below are the unused definitions.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/utils/Structs.sol#L68
Use (e.g. 1e6) rather than decimal literals (e.g. 100000), for better code readability.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L59
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L265
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L561
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L650
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L724
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L725
The highest tier of smart contract behavior assurance is formal mathematical verification. All assertions that are made are guaranteed to be true across all inputs → The quality of your asserts is the quality of your verification
https://twitter.com/0xOwenThurm/status/1614359896350425088?t=dbG9gHFigBX85Rv29lOjIQ&s=19
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L59
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L265
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L561
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L650
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L724
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Lender.sol#L725
Consider using descriptive constants or an enum instead of passing zero directly on function calls, as that might be error-prone, to fully describe the caller's intention.
https://github.com/Cyfrin/2023-07-beedle/tree/main/src/Fees.sol#L38
The 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.